using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Media; using Avalonia.Platform.Storage; using CommunityToolkit.Mvvm.Input; using Eremex.AvaloniaUI.Controls; using MarketData; using MarketData.DataAccess; using MarketData.Generator.CMTrend; using MarketData.Generator.Interface; using MarketData.Generator.Model; using MarketData.Generator.ModelGenerators; using MarketData.MarketDataModel; using MarketData.Utils; using PortfolioManager.DataSeriesViewModels; using PortfolioManager.Dialogs; using PortfolioManager.Models; using PortfolioManager.UIUtils; using Position=MarketData.Generator.CMTrend.Position; using StopLimit = MarketData.MarketDataModel.StopLimit; namespace PortfolioManager.ViewModels { public partial class CMTrendViewModel : WorkspaceViewModel { private bool isBusy = false; private bool showMarkers = false; private ModelPerformanceSeries modelPerformanceSeries = null; private ModelStatistics modelStatistics = null; private bool showAsGainLoss = true; private CMTPositionModelCollection positions = null; private CMTPositionModel selectedPosition = null; private CMTParams configuration = null; private String pathFileName = null; private CMTSessionParams sessionParams; private NVPDictionary nvpDictionary = null; private ObservableCollection nvpDictionaryKeys = null; private String selectedParameter = null; public CMTrendViewModel() { DisplayName = "CMTrend Model"; PropertyChanged += OnViewModelPropertyChanged; } protected override void OnDispose() { base.OnDispose(); } private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs) { } public bool IsBusy { get { return isBusy; } set { isBusy = value; base.OnPropertyChanged("IsBusy"); } } public bool ShowMarkers { get { return showMarkers; } set { showMarkers = value; base.OnPropertyChanged("ShowMarkers"); } } public CompositeDataSource Data { get { if (null == modelPerformanceSeries) return GainLossModel.Empty(); CompositeDataSource compositeDataSource = null; compositeDataSource = GainLossModel.GainLoss(modelPerformanceSeries, showAsGainLoss); return compositeDataSource; } } public String PercentButtonText { get { if (!showAsGainLoss) return "Show $"; else return "Show %"; } } public ObservableCollection Parameters { get { return nvpDictionaryKeys; } } public String SelectedParameter { get { return selectedParameter; } set { selectedParameter = value; base.OnPropertyChanged("SelectedParameter"); base.OnPropertyChanged("ParameterValue"); } } public String ParameterValue { get { if (null == nvpDictionary || null == nvpDictionaryKeys || null == selectedParameter) return null; return nvpDictionary[selectedParameter].Value; } } public String TradeDate { get { if (null == sessionParams) return Constants.CONST_DASHES; DateGenerator dateGenerator = new DateGenerator(); return Utility.DateTimeToStringMMSDDSYYYY(sessionParams.TradeDate); } } public String CashBalance { get { if (null == sessionParams) return Constants.CONST_DASHES; return Utility.FormatCurrency(sessionParams.CashBalance); } } public String NonTradeableCash { get { if (null == sessionParams) return Constants.CONST_DASHES; return Utility.FormatCurrency(sessionParams.NonTradeableCash); } } public String ModelExpectation { get { if (null == modelStatistics) return ""; return Utility.FormatNumber(modelStatistics.Expectancy, 2); } } public IBrush ExpectationColor { get { if (null == modelStatistics) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black); if (modelStatistics.Expectancy > 0.00) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Black); return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red); } } public String GraphTitle { get { if (null == sessionParams || null == modelPerformanceSeries) return ""; StringBuilder sb = new StringBuilder(); Positions allPositions = sessionParams.GetCombinedPositions(); DateTime minDate = allPositions.Min(x => x.PurchaseDate); DateTime maxDate = PricingDA.GetLatestDate(); if (modelPerformanceSeries.Count < 2) { sb.Append(showAsGainLoss ? "$ GainLoss" : "% Return"); sb.Append(" "); sb.Append("(").Append(minDate.ToShortDateString()).Append("-").Append(maxDate.ToShortDateString()).Append(")"); sb.Append(showAsGainLoss ? Utility.FormatCurrency(modelPerformanceSeries[modelPerformanceSeries.Count - 1].CumulativeGainLoss) : Utility.FormatPercent(modelPerformanceSeries[modelPerformanceSeries.Count - 1].CumProdMinusOne)); return sb.ToString(); } if (showAsGainLoss) { double latestGainLoss = modelPerformanceSeries[modelPerformanceSeries.Count - 1].CumulativeGainLoss; double change = modelPerformanceSeries[modelPerformanceSeries.Count - 1].GainLossDOD; sb.Append("$ GainLoss"); sb.Append(" "); sb.Append("(").Append(minDate.ToShortDateString()).Append("-").Append(maxDate.ToShortDateString()).Append(")"); sb.Append(" "); sb.Append(Utility.FormatCurrency(latestGainLoss)); sb.Append(","); sb.Append(" "); sb.Append(change > 0.00 ? "+" : "").Append(Utility.FormatCurrency(change)); } else { double latestCumGainLoss = modelPerformanceSeries[modelPerformanceSeries.Count - 1].CumProdMinusOne; double prevCumGainLoss = modelPerformanceSeries[modelPerformanceSeries.Count - 2].CumProdMinusOne; double change = latestCumGainLoss - prevCumGainLoss; sb.Append("% Return"); sb.Append(" "); sb.Append("(").Append(minDate.ToShortDateString()).Append("-").Append(maxDate.ToShortDateString()).Append(")"); sb.Append(" "); sb.Append(Utility.FormatPercent(latestCumGainLoss)); sb.Append(","); sb.Append(" "); sb.Append(change > 0.00 ? "+" : "").Append(Utility.FormatPercent(change)); } return sb.ToString(); } } // ***************************************************************************************************************************************************** public ObservableCollection PositionsMenuItems { get { ObservableCollection collection = new ObservableCollection(); collection.Add(new MenuItem() { Header = "Close Position...", Command = CloseCommand, StaysOpenOnClick = false }); collection.Add(new MenuItem() { Header = "Edit Position...", Command = EditCommand, StaysOpenOnClick = false }); collection.Add(new MenuItem() { Header = "Add To WatchList", Command = AddToWatchListCommand, StaysOpenOnClick = false }); collection.Add(new MenuItem() { Header = "Remove From WatchList", Command = RemoveFromWatchListCommand, StaysOpenOnClick = false }); return collection; } } // ********************************************************************* R E L A Y S ***************************************************************** [RelayCommand(CanExecute = nameof(CanClosePosition))] public async Task Close() { await OpenCloseDialog(); } public bool CanClosePosition() { if (null == selectedPosition || null == selectedPosition.Symbol) return false; return true; } [RelayCommand(CanExecute = nameof(CanEdit))] public async Task Edit() { await OpenEditDialog(); } public bool CanEdit() { if (null == selectedPosition || null == selectedPosition.Symbol || !Utility.IsEpoch(selectedPosition.SellDate)) return false; return true; } [RelayCommand] public void ToggleReturnOrPercent() { HandleToggleReturnOrPercent(); } // This is not currently being displayed // [RelayCommand] // public void Run() // { // RunCandidateGenerator(); // } [RelayCommand] public async Task LoadFile() { await LoadTradeFile(); } [RelayCommand] public async Task Reload() { await ReloadTradeFile(); } public async Task ReloadTradeFile() { LoadSessionFile(); await Task.FromResult(true); } [RelayCommand(CanExecute = nameof(CanAddToWatchList))] public async Task AddToWatchList() { WatchListDA.AddToWatchList(selectedPosition.Symbol); MxMessageBox.Show(GetTopLevelWindow(), $"Added {selectedPosition.Symbol} to WatchList", "Add To WatchList"); await Task.FromResult(true); } public bool CanAddToWatchList() { if (null == selectedPosition) return false; return WatchListDA.IsInWatchList(selectedPosition.Symbol) ? false : true; } [RelayCommand(CanExecute = nameof(CanRemoveFromWatchList))] public async Task RemoveFromWatchList() { WatchListDA.RemoveFromWatchList(selectedPosition.Symbol); MxMessageBox.Show(GetTopLevelWindow(), $"Removed {selectedPosition.Symbol} from WatchList", "Remove From WatchList"); await Task.FromResult(true); } public bool CanRemoveFromWatchList() { if (null == selectedPosition) return false; if (!WatchListDA.IsInWatchList(selectedPosition.Symbol)) return false; PortfolioTrades portfolioTrades = PortfolioDA.GetOpenTrades(); if (portfolioTrades.Any(x => x.Symbol.Equals(selectedPosition.Symbol))) return false; return true; } private void HandleToggleReturnOrPercent() { showAsGainLoss = !showAsGainLoss; base.OnPropertyChanged("Data"); base.OnPropertyChanged("PercentButtonText"); base.OnPropertyChanged("GraphTitle"); } public bool ReloadEnabled { get { return !String.IsNullOrEmpty(pathFileName); } } public CMTPositionModelCollection AllPositions { get { return positions; } } public override String DisplayName { get { if (null == pathFileName) return "CMTrend Model"; String pureFileName = Utility.GetFileNameNoExtension(pathFileName); return "CMTrend Model (" + pureFileName + ")"; } } public override String Title { get { return DisplayName; } } // *********************************************************************************************************************************** #region Operations public async Task OpenCloseDialog() { bool deleteStop = false; IPosition clonedPosition = Position.Clone(selectedPosition.Position); // bool hasStopLimit = PortfolioDA.HasStopLimit(clonedPosition.Symbol); ClosePositionDialog dialog = new ClosePositionDialog(); ClosePositionDialogViewModel closePositionViewModel = new ClosePositionDialogViewModel(dialog, clonedPosition); dialog.DataContext = closePositionViewModel; await dialog.ShowDialog(GetTopLevelWindow()); if (!closePositionViewModel.IsSuccess) return; CMTTrendModel mmTrendModel = new CMTTrendModel(); if (!mmTrendModel.ClosePosition(clonedPosition.Symbol, clonedPosition.PurchaseDate, clonedPosition.SellDate, clonedPosition.CurrentPrice, pathFileName)) { MxMessageBox.Show(GetTopLevelWindow(), "Failed to close the position, check log for details.", "Close Position"); return; } // if (deleteStop) PortfolioDA.DeleteStopLimit(clonedPosition.Symbol); String strMessage = String.Format("Closed position for {0}, Purchase Date:{1}, Sell Date{2}, Current Price:{3}, Delete Stop:{4} to {5}. A backup was created.", clonedPosition.Symbol, clonedPosition.PurchaseDate.ToShortDateString(), clonedPosition.SellDate.ToShortDateString(), Utility.FormatCurrency(clonedPosition.CurrentPrice), deleteStop, pathFileName); MxMessageBox.Show(GetTopLevelWindow(), strMessage, "Close Position"); LoadSessionFile(); } public async Task OpenEditDialog() { EditPositionDialog dialog = new EditPositionDialog(); IPosition clonedPosition = Position.Clone(selectedPosition.Position); EditPositionDialogViewModel editPositionViewModel = new EditPositionDialogViewModel(dialog, clonedPosition); dialog.DataContext = editPositionViewModel; await dialog.ShowDialog(GetTopLevelWindow()); GetTopLevelWindow().BringIntoView(); if (!editPositionViewModel.IsSuccess) return; CMTTrendModel mmTrendModel = new CMTTrendModel(); if (!mmTrendModel.EditPosition(clonedPosition.Symbol, clonedPosition.PurchaseDate, clonedPosition.PurchasePrice, clonedPosition.InitialStopLimit, clonedPosition.TrailingStopLimit, pathFileName)) { MxMessageBox.Show(GetTopLevelWindow(), "Failed to edit the position, check log for details.", "Edit Position"); return; } if (!selectedPosition.TrailingStopLimit.Equals(clonedPosition.TrailingStopLimit)) { selectedPosition.TrailingStopLimit = clonedPosition.TrailingStopLimit; selectedPosition.LastStopAdjustment = DateTime.Now.Date; } selectedPosition.PurchaseDate = clonedPosition.PurchaseDate; selectedPosition.PurchasePrice = clonedPosition.PurchasePrice; selectedPosition.TrailingStopLimit = clonedPosition.TrailingStopLimit; selectedPosition.InitialStopLimit = clonedPosition.InitialStopLimit; String strMessage = String.Format("Edited Position for {0} Purchase Date:{1} Purchase Price:{2}, Trailing Stop:{3}. A backup was created.", selectedPosition.Symbol, selectedPosition.PurchaseDate.ToShortDateString(), Utility.FormatCurrency(selectedPosition.PurchasePrice), Utility.FormatCurrency(selectedPosition.TrailingStopLimit)); MxMessageBox.Show(GetTopLevelWindow(), strMessage, "Edit Position"); LoadSessionFile(); } public async Task LoadTradeFile() { TopLevel topLevel = TopLevel.GetTopLevel(GetTopLevelWindow()); IReadOnlyList files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = "Open Trade File", AllowMultiple = false, }); IStorageFile storageFile = files.FirstOrDefault(); if (null == storageFile) return; Uri uri = storageFile.Path; pathFileName = uri.LocalPath; if (null == pathFileName) return; if (!CMTSessionManager.IsValidSessionFile(pathFileName)) { pathFileName = null; } else LoadSessionFile(); } public bool LoadSessionFile() { IsBusy = true; Task workerTask = Task.Factory.StartNew(() => { try { if (!CMTSessionManager.IsValidSessionFile(pathFileName)) return false; sessionParams = CMTSessionManager.RestoreSession(pathFileName); if (null == sessionParams) { pathFileName = null; return false; } modelStatistics = CMTTrendModel.GetModelStatistics(sessionParams); modelPerformanceSeries = CMTTrendModel.GetModelPerformance(sessionParams); configuration = sessionParams.CMTParams; NVPCollection nvpCollection = sessionParams.CMTParams.ToNVPCollection(); nvpDictionary = nvpCollection.ToDictionary(); List dictionaryKeys = new List(nvpDictionary.Keys); dictionaryKeys.Sort(); nvpDictionaryKeys = new ObservableCollection(dictionaryKeys); selectedParameter = nvpDictionaryKeys[0]; positions = new CMTPositionModelCollection(); positions.Add(sessionParams.ActivePositions); positions.Add(sessionParams.AllPositions); UpdatePositionPrices(false); RunPerformance(); return true; } catch (Exception exception) { IsBusy = false; MDTrace.WriteLine(LogLevel.DEBUG, exception.ToString()); pathFileName = null; return false; } }); workerTask.ContinueWith(continuation => { IsBusy = false; base.OnPropertyChanged("Parameters"); base.OnPropertyChanged("SelectedParameter"); base.OnPropertyChanged("ParameterValue"); base.OnPropertyChanged("Title"); base.OnPropertyChanged("DisplayName"); base.OnPropertyChanged("AllPositions"); base.OnPropertyChanged("CashBalance"); base.OnPropertyChanged("NonTradeableCash"); base.OnPropertyChanged("ModelExpectation"); base.OnPropertyChanged("ExpectationColor"); base.OnPropertyChanged("ReloadEnabled"); base.OnPropertyChanged("TradeDate"); UpdateTooltipProperties(); }); return true; } private void UpdateTooltipProperties() { base.OnPropertyChanged("ExpectationDescription"); base.OnPropertyChanged("CompanyDescriptionSelectedPosition"); base.OnPropertyChanged("ToolTipPurchasePrice"); base.OnPropertyChanged("ToolTipCurrentPrice"); base.OnPropertyChanged("ToolTipCurrentPriceLow"); base.OnPropertyChanged("ToolTipInitialStop"); base.OnPropertyChanged("ToolTipTrailingStop"); base.OnPropertyChanged("ToolTipR"); base.OnPropertyChanged("ToolTipTotalRiskExposure"); base.OnPropertyChanged("ToolTipRMultiple"); base.OnPropertyChanged("ToolTipEdgeRatio"); } private void RunPerformance() { if (null == sessionParams) return; modelPerformanceSeries = CMTTrendModel.GetModelPerformance(sessionParams); base.OnPropertyChanged("Data"); base.OnPropertyChanged("GraphTitle"); } private void UpdatePositionPrices(bool signalChangeEvent = true) { try { DateTime today = DateTime.Now; if (null == positions || 0 == positions.Count) return; List symbols = (from CMTPositionModel position in positions where position.IsActivePosition select position.Symbol).Distinct().ToList(); foreach (String symbol in symbols) { var selectedPositions = (from CMTPositionModel position in positions where position.IsActivePosition && position.Symbol.Equals(symbol) select position); foreach (CMTPositionModel selectedPosition in selectedPositions) { Price price = PricingDA.GetPrice(symbol); if (null == price) continue; selectedPosition.CurrentPrice = price.Close; selectedPosition.CurrentPriceLow = price.Low; selectedPosition.LastUpdated = price.Date.Date < today.Date ? price.Date : today; selectedPosition.EdgeRatio = EdgeRatioGenerator.CalculateEdgeRatio(symbol, selectedPosition.PurchaseDate, selectedPosition.PurchasePrice, price.Date).EdgeRatio; } } if (signalChangeEvent) positions.OnCollectionChanged(); } catch (Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG, exception.ToString()); } } #endregion public CMTPositionModel SelectedPosition { get { return selectedPosition; } set { selectedPosition = value; base.OnPropertyChanged("SelectedPosition"); } } // ****************************************************** P E R S I S T E N C E ******************************************************** public override bool CanPersist() { return true; } public override SaveParameters GetSaveParameters() { SaveParameters saveParams = new SaveParameters(); if (null == pathFileName) return null; saveParams.Add(new KeyValuePair("Type", GetType().Namespace + "." + GetType().Name)); saveParams.Add(new KeyValuePair("PathFileName", pathFileName)); return saveParams; } public override void SetSaveParameters(SaveParameters saveParameters) { try { pathFileName = (from KeyValuePair item in saveParameters where item.Key.Equals("PathFileName") select item).FirstOrDefault().Value; if (!LoadSessionFile()) pathFileName = null; } catch (Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Exception:{0}", exception.ToString())); } } // ************************************************** T O O L T I P S ************************************************* public String ExpectationDescription { get { if (null == modelStatistics) return ""; StringBuilder sb = new StringBuilder(); sb.Append("Expectancy is (percentage of winning trades * average gain) / (percentage of losing trades * average loss).").Append("\n"); sb.Append("Total Trades : ").Append(modelStatistics.TotalTrades).Append("\n"); sb.Append("Winning Trades : ").Append(modelStatistics.WinningTrades).Append("\n"); sb.Append("Losing Trades : ").Append(modelStatistics.LosingTrades).Append("\n"); sb.Append("Winning Trades : ").Append(Utility.FormatNumber(modelStatistics.WinningTradesPercent, 2)).Append("%").Append("\n"); sb.Append("Losing Trades : ").Append(Utility.FormatNumber(modelStatistics.LosingTradesPercent, 2)).Append("%").Append("\n"); sb.Append("Average Winning Trade Gain : ").Append(Utility.FormatNumber(modelStatistics.AverageWinningTradePercentGain, 2)).Append("%").Append("\n"); sb.Append("Average Losing Trade Loss : ").Append(Utility.FormatNumber(modelStatistics.AverageLosingTradePercentLoss, 2)).Append("%").Append("\n"); sb.Append("Expectancy : ").Append(Utility.FormatNumber(modelStatistics.Expectancy, 2)).Append("\n"); sb.Append("\n"); sb.Append("Maintain a positive Expectancy and you're a winner."); sb.Append("\n"); sb.Append("The calculations are based on closed positions."); return sb.ToString(); } } public String CompanyDescriptionSelectedPosition { get { if (null == selectedPosition || null == selectedPosition.Symbol) return "No row selected."; CompanyProfile companyProfile = CompanyProfileDA.GetCompanyProfile(selectedPosition.Symbol); if (null == companyProfile || null == companyProfile.Description || "".Equals(companyProfile.Description)) return "No description found."; StringBuilder sb = new StringBuilder(); sb.Append(companyProfile.Symbol).Append(" - ").Append(companyProfile.CompanyName).Append("\n"); sb.Append(companyProfile.Sector).Append("/").Append(companyProfile.Industry).Append("\n").Append(companyProfile.Description); return sb.ToString(); } } public String ToolTipPurchasePrice { get { if (null == selectedPosition) return "No row selected."; StringBuilder sb = new StringBuilder(); sb.Append("[PurchasePrice]=([PurchasePrice])").Append("\n"); sb.Append(Utility.FormatCurrency(selectedPosition.PurchasePrice)).Append("=").Append(Utility.FormatCurrency(selectedPosition.PurchasePrice)); return sb.ToString(); } } public String ToolTipCurrentPrice { get { if (null == selectedPosition) return "No row selected."; StringBuilder sb = new StringBuilder(); sb.Append("[Price]=([CurrentPrice])").Append("\n"); sb.Append(Utility.FormatCurrency(selectedPosition.CurrentPrice)).Append("=").Append(Utility.FormatCurrency(selectedPosition.CurrentPrice)); return sb.ToString(); } } public String ToolTipCurrentPriceLow { get { if (null == selectedPosition) return "No row selected."; StringBuilder sb = new StringBuilder(); sb.Append("[Low]=([CurrentLowPrice])").Append("\n"); sb.Append(Utility.FormatCurrency(selectedPosition.CurrentPriceLow)).Append("=").Append(Utility.FormatCurrency(selectedPosition.CurrentPriceLow)); return sb.ToString(); } } public String ToolTipInitialStop { get { if (null == selectedPosition) return "No row selected."; StringBuilder sb = new StringBuilder(); sb.Append("[InitialStop]=([InitialStopLimit])").Append("\n"); sb.Append(Utility.FormatCurrency(selectedPosition.InitialStopLimit)).Append("=").Append(Utility.FormatCurrency(selectedPosition.InitialStopLimit)); return sb.ToString(); } } public String ToolTipTrailingStop { get { if (null == selectedPosition)return "No row selected."; StringBuilder sb = new StringBuilder(); sb.Append("[TrailingStop]=([TrailingStopLimit])").Append("\n"); sb.Append(Utility.FormatCurrency(selectedPosition.TrailingStopLimit)).Append("=").Append(Utility.FormatCurrency(selectedPosition.TrailingStopLimit)).Append("\n"); List stopLimits = GetHistoricalStopLimits(); if (selectedPosition.TrailingStopLimit > selectedPosition.PurchasePrice) { sb.Append("Riskless Gain").Append(" = "); sb.Append(String.Format("(Trailing Stop - Purchase Price) * Shares")); sb.Append("\n"); sb.Append(String.Format("{0}", Utility.FormatCurrency((selectedPosition.TrailingStopLimit - selectedPosition.PurchasePrice) * selectedPosition.Shares))); sb.Append(String.Format("=({0}-{1})*{2}", Utility.FormatCurrency(selectedPosition.TrailingStopLimit), Utility.FormatCurrency(selectedPosition.PurchasePrice), Utility.FormatNumber(selectedPosition.Shares, 3))); sb.Append("\n"); } if (null != stopLimits && 0 != stopLimits.Count) { sb.Append("Stop History").Append("\n"); foreach (MarketData.Generator.Model.StopLimit stopLimit in stopLimits) { sb.Append(String.Format("Analysis Date:{0} New Stop:{1} Previous Stop:{2}", Utility.DateTimeToStringMMSDDSYYYY(stopLimit.AnalysisDate), Utility.FormatCurrency(stopLimit.NewStop), Utility.FormatCurrency(stopLimit.PreviousStop))); sb.Append("\n"); } } return sb.ToString(); } } public String ToolTipR { get { if(null==selectedPosition)return "No row selected."; StringBuilder sb=new StringBuilder(); sb.Append("Current R/Share. See RMultiple for initial risk assumptions.").Append("\n"); sb.Append("R/Share=TrailingStop>PurchasePrice?0.00:PurchasePrice-TrailingStop").Append("\n"); if(selectedPosition.TrailingStopLimit>selectedPosition.PurchasePrice) { sb.Append(Utility.FormatCurrency(0)).Append("=").Append(Utility.FormatCurrency(0)); } else { sb.Append(Utility.FormatCurrency(selectedPosition.TrailingStopLimit>selectedPosition.PurchasePrice?0.00:selectedPosition.PurchasePrice-selectedPosition.TrailingStopLimit)); sb.Append("=").Append(Utility.FormatCurrency(selectedPosition.PurchasePrice)).Append("-").Append(Utility.FormatCurrency(selectedPosition.TrailingStopLimit)); } return sb.ToString(); } } public String ToolTipTotalRiskExposure { get { if(null==selectedPosition)return "No row selected."; StringBuilder sb=new StringBuilder(); sb.Append("Current Risk. See RMultiple for initial risk assumptions.").Append("\n"); sb.Append("[TotalRiskExposure]=([R/Share]*[Shares])").Append("\n"); if(null==selectedPosition) return sb.ToString(); sb.Append(Utility.FormatCurrency(selectedPosition.TotalRiskExposure)).Append("=(").Append(Utility.FormatCurrency(selectedPosition.R)).Append("*").Append(Utility.FormatNumber(selectedPosition.Shares,0)).Append(")"); return sb.ToString(); } } public String ToolTipRMultiple { get { if(null==selectedPosition)return "No row selected."; StringBuilder sb=new StringBuilder(); sb.Append("RMultiple is based on original position setup.").Append("\n"); sb.Append("Original Exposure=").Append(Utility.FormatCurrency(selectedPosition.PurchasePrice*selectedPosition.Shares)).Append("\n"); sb.Append("Original R/Share=PurchasePrice-InitialStop").Append("\n"); sb.Append(Utility.FormatCurrency(selectedPosition.PurchasePrice-selectedPosition.InitialStopLimit)).Append("=").Append(Utility.FormatCurrency(selectedPosition.PurchasePrice)).Append("-").Append(Utility.FormatCurrency(selectedPosition.InitialStopLimit)).Append("\n"); sb.Append("Original Risk=Original R/Share*Shares").Append("\n"); sb.Append(Utility.FormatCurrency((selectedPosition.PurchasePrice-selectedPosition.InitialStopLimit)*selectedPosition.Shares)).Append("=").Append(Utility.FormatCurrency(selectedPosition.PurchasePrice-selectedPosition.InitialStopLimit)).Append("*").Append(selectedPosition.Shares).Append("\n"); sb.Append("RMultiple=(CurrentPrice-PurchasePrice)/(PurchasePrice-InitialStop)").Append("\n"); sb.Append(selectedPosition.RMultipleAsString).Append("=").Append("(").Append(Utility.FormatCurrency(selectedPosition.CurrentPrice)).Append("-").Append(Utility.FormatCurrency(selectedPosition.PurchasePrice)).Append(")"); sb.Append("/").Append("(").Append(Utility.FormatCurrency(selectedPosition.PurchasePrice)).Append("-").Append(Utility.FormatCurrency(selectedPosition.InitialStopLimit)).Append(")"); return sb.ToString(); } } public String ToolTipEdgeRatio { get { if(null==selectedPosition)return "No row selected."; StringBuilder sb=new StringBuilder(); sb.Append("[EdgeRatio]=AVG(SUM(MFE/ATR(14)))/AVG(SUM(MAE/ATR(14)))").Append("\n"); sb.Append("MFE=Maximum Favorable Excursion").Append("\n"); sb.Append("MAE=Maximum Adverse Excursion").Append("\n"); sb.Append("ATR=Average True Range. 14 days").Append("\n"); if(selectedPosition.EdgeRatio<1.00) { sb.Append(String.Format("You can expect a further {0} units more of adverse volatility.",Utility.FormatNumber(1.00-selectedPosition.EdgeRatio,2))); } else { sb.Append(String.Format("You can expect a further {0} units more of favorable volatility.",Utility.FormatNumber(selectedPosition.EdgeRatio-1.00,2))); } return sb.ToString(); } } // This getter returns MMTrend specific stop limits to show in the tooltips public MarketData.Generator.Model.StopLimits GetHistoricalStopLimits() { if (null == sessionParams || null == selectedPosition) return null; MarketData.Generator.Model.StopLimits stopLimits = new MarketData.Generator.Model.StopLimits((from MarketData.Generator.Model.StopLimit stopLimit in sessionParams.StopLimits where stopLimit.Symbol.Equals(selectedPosition.Symbol) select stopLimit).OrderByDescending(x => x.AnalysisDate).ToList()); return stopLimits; } } }