Files
TradeBlotter/ViewModels/GainLossViewModel.cs
2026-02-24 12:20:56 -05:00

1043 lines
46 KiB
C#

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Windows.Input;
using System.Windows.Threading;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.Threading;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay.DataSources;
using MarketData;
using MarketData.MarketDataModel;
using MarketData.Generator;
using MarketData.DataAccess;
using MarketData.Utils;
using TradeBlotter.UIUtils;
using TradeBlotter.Model;
using TradeBlotter.Command;
using TradeBlotter.Cache;
using MarketData.Numerical;
using MarketData.Generator.GainLoss;
using MarketData.MarketDataModel.GainLoss;
using MarketData.Cache;
using MarketData.Helper;
using MarketData.Generator.MovingAverage;
namespace TradeBlotter.ViewModels
{
public class GainLossViewModel : WorkspaceViewModel
{
private enum Tasks{Accounts,SelectedSymbol,SelectedAccounts,LeastSquaresFit,UseDividends};
private Dictionary<Tasks,Semaphore> semaphorePool=new Dictionary<Tasks,Semaphore>();
private ObservableCollection<GainLossSummaryItem> gainLossSummaryItemCollection=new ObservableCollection<GainLossSummaryItem>();
private ITotalGainLossGenerator gainLossGenerator=null;
private IActiveGainLossGenerator activeGainLossGenerator=null;
private ObservableCollection<GainLossCompoundModel> gainLossCompoundModelCollection=new ObservableCollection<GainLossCompoundModel>();
private GainLossCompoundModelCollection gainLossModelCollection=null;
private GainLossCompoundModel selectedGainLossCompoundItem=null;
private GainLossSummaryItem selectedGainLossSummaryItem=null;
private String selectedSymbol =Constants.CONST_ALL;
private TotalGainLossCollection totalGainLoss=null; // total gain/loss
private PortfolioTrades portfolioTrades = null;
private String selectedCompanyName;
private bool suspendUpdate=false;
private String selectedAccounts;
private List<String> accounts=null;
private DateTime latestMarketDate=Utility.Epoch;
// RelayCommands
private RelayCommand refreshCommand=null;
private RelayCommand toggleReturnOrPercentCommand=null;
private RelayCommand toggleActiveOrTotalCommand=null;
// RelayCommand for menu
private RelayCommand saveCommand=null;
private RelayCommand stochasticsCommand=null;
private RelayCommand relativeStrengthCommand=null;
private RelayCommand macdCommand=null;
private RelayCommand movingAverageCommand;
private RelayCommand bollingerBandCommand=null;
private RelayCommand priceHistoryCommand=null;
private RelayCommand stickerValuationCommand=null;
private RelayCommand dcfValuationCommand=null;
private RelayCommand displayAnalystRatingsCommand=null;
private RelayCommand displayHeadlinesCommand=null;
private RelayCommand rollPriceForwardCommand=null;
private RelayCommand dividendHistoryCommand=null;
private RelayCommand displayHistoricalCommand=null;
private RelayCommand proformaDividendRiskCommand = null;
//
private ObservableCollection<String> symbols = new ObservableCollection<String>();
private bool busyIndicator = false;
private bool isLegendVisible = true;
private bool useLeastSquaresFit=true;
private bool useCumulativeGainLoss=true;
private Boolean showAsGainLoss = true;
private Boolean showActiveGainLoss=false; // show the total gain/loss graph in the view by default
private Boolean includeDividends=false; // include dividends in the calculation of TOTAL gain/loss, ACTIVE gain/loss never includes dividends
private String busyContent = "Generating Gain/Loss...";
public GainLossViewModel()
{
latestMarketDate=PremarketDA.GetLatestMarketDate();
semaphorePool.Add(Tasks.SelectedSymbol,new Semaphore(1,1));
semaphorePool.Add(Tasks.SelectedAccounts,new Semaphore(1,1));
semaphorePool.Add(Tasks.LeastSquaresFit,new Semaphore(1,1));
semaphorePool.Add(Tasks.Accounts,new Semaphore(1,1));
semaphorePool.Add(Tasks.UseDividends,new Semaphore(1,1));
base.DisplayName = "GainLossView";
PropertyChanged += OnGainLossViewModelPropertyChanged;
BusyIndicator = true;
suspendUpdate=true;
Task workerTask = Task.Factory.StartNew(() =>
{
semaphorePool[Tasks.Accounts].WaitOne();
portfolioTrades = PortfolioDA.GetTrades();
if(null!=portfolioTrades&&0!=portfolioTrades.Count)
{
accounts = portfolioTrades.Accounts;
}
});
workerTask.ContinueWith((continuation) =>
{
BusyIndicator = false;
SelectedAccounts=AccountsToString(accounts);
suspendUpdate=false;
SetSymbols();
semaphorePool[Tasks.Accounts].Release();
});
}
public override SaveParameters GetSaveParameters()
{
return null;
}
public override void SetSaveParameters(SaveParameters saveParameters)
{
}
public override bool CanPersist()
{
return false;
}
public bool BusyIndicator
{
get { return busyIndicator; }
set
{
busyIndicator = value;
base.OnPropertyChanged("BusyIndicator");
}
}
public String BusyContent
{
get { return busyContent; }
set
{
busyContent = value;
base.OnPropertyChanged("BusyContent");
}
}
private void OnGainLossViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
{
if (eventArgs.PropertyName.Equals("SelectedSymbol"))HandleSelectedSymbol();
else if (eventArgs.PropertyName.Equals("SelectedAccounts"))HandleSelectedAccounts();
else if (eventArgs.PropertyName.Equals("LeastSquaresFit"))HandleLeastSquaresFit();
else if (eventArgs.PropertyName.Equals("SelectedGainLossCompoundItem"))HandleSelectedGainLossCompoundItem();
else if(eventArgs.PropertyName.Equals("CheckBoxUseCumulativeReturns")) HandleCheckBoxUseCumulativeReturns();
}
public void HandleCheckBoxUseCumulativeReturns()
{
gainLossGenerator=null;
activeGainLossGenerator=null;
base.OnPropertyChanged("SelectedSymbol");
}
public void HandleSelectedGainLossCompoundItem()
{
if(null==selectedGainLossCompoundItem)return;
BusyIndicator = true;
Task workerTask = Task.Factory.StartNew(() =>
{
DateTime selectedDate=selectedGainLossCompoundItem.Date;
PortfolioTrades tradesOnOrBefore=portfolioTrades.GetTradesOnOrBefore(selectedDate);
GainLossSummaryItemCollection gainLossSummaryItems=new GainLossSummaryItemCollection(tradesOnOrBefore,gainLossGenerator,activeGainLossGenerator,selectedDate);
gainLossSummaryItemCollection=new ObservableCollection<GainLossSummaryItem>(gainLossSummaryItems);
});
workerTask.ContinueWith((continuation) =>
{
BusyIndicator = false;
base.OnPropertyChanged("GainLossSummaryItemCollection");
});
}
public void InstantiateGenerators()
{
if(null==gainLossGenerator)
{
if(useCumulativeGainLoss)gainLossGenerator=new GainLossGeneratorCum();
else gainLossGenerator=new GainLossGenerator();
}
if(null==activeGainLossGenerator) activeGainLossGenerator=new ActiveGainLossGenerator();
}
public void HandleLeastSquaresFit()
{
try
{
semaphorePool[Tasks.LeastSquaresFit].WaitOne();
base.OnPropertyChanged("LeastSquares");
}
finally
{
semaphorePool[Tasks.LeastSquaresFit].Release();
}
}
public void HandleSelectedAccounts()
{
try
{
semaphorePool[Tasks.SelectedAccounts].WaitOne();
if(suspendUpdate)return;
MDTrace.WriteLine(String.Format("[GainLossViewModel::OnGainLossViewModelPropertyChanged]SelectedAccounts '{0}'",selectedAccounts));
portfolioTrades = PortfolioDA.GetTradesForAccounts(ParseAccounts(selectedAccounts));
SetSymbols();
}
finally
{
semaphorePool[Tasks.SelectedAccounts].Release();
}
}
public void HandleSelectedSymbol()
{
try
{
semaphorePool[Tasks.SelectedSymbol].WaitOne();
gainLossCompoundModelCollection=null;
gainLossSummaryItemCollection=null;
if(suspendUpdate)return;
if (null == selectedSymbol||"".Equals(selectedAccounts))
{
UpdateProperties();
return;
}
MDTrace.WriteLine(String.Format("[GainLossViewModel::OnGainLossViewModelPropertyChanged]SelectedSymbol '{0}'",selectedSymbol));
BusyIndicator = true;
Task workerTask = Task.Factory.StartNew(() =>
{
DividendPayments dividendPayments=null;
if(Constants.CONST_ALL.Equals(selectedSymbol))
{
portfolioTrades = PortfolioDA.GetTrades();
if(includeDividends)dividendPayments=DividendPaymentDA.GetDividendPayments();
selectedCompanyName="";
}
else
{
portfolioTrades = PortfolioDA.GetTrades(selectedSymbol);
if(includeDividends)dividendPayments=DividendPaymentDA.GetDividendPaymentsForSymbol(selectedSymbol);
selectedCompanyName=PricingDA.GetNameForSymbol(selectedSymbol);
}
if(null!=portfolioTrades&&0!=portfolioTrades.Count)
{
accounts = portfolioTrades.Accounts;
}
portfolioTrades=portfolioTrades.FilterAccount(ParseAccounts(selectedAccounts));
if(null!=dividendPayments)dividendPayments=dividendPayments.FilterAccounts(selectedAccounts);
// check the TotalGainLoss generator and build appropriately
InstantiateGenerators();
LocalPriceCache.GetInstance().Refresh();
GainLossCollection gainLoss = null;
gainLoss=activeGainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions
// Call the appropriate TotalGainLoss method depending on whether we should include dividends or not.
if(includeDividends)totalGainLoss=gainLossGenerator.GenerateTotalGainLossWithDividends(portfolioTrades,dividendPayments);
else totalGainLoss=gainLossGenerator.GenerateTotalGainLoss(portfolioTrades);
gainLossModelCollection=null;
gainLossModelCollection=new GainLossCompoundModelCollection(gainLoss,totalGainLoss);
if(null!=gainLossModelCollection)
{
gainLossModelCollection.Sort(new SortGainLossCompoundModelYearDescendingOrder());
gainLossCompoundModelCollection=new ObservableCollection<GainLossCompoundModel>(gainLossModelCollection);
}
GainLossSummaryItemCollection gainLossSummaryItems=new GainLossSummaryItemCollection(portfolioTrades,gainLossGenerator,activeGainLossGenerator);
gainLossSummaryItemCollection=new ObservableCollection<GainLossSummaryItem>(gainLossSummaryItems);
});
workerTask.ContinueWith((continuation) =>
{
BusyIndicator = false;
UpdateProperties();
});
}
finally
{
semaphorePool[Tasks.SelectedSymbol].Release();
}
}
public void UpdateProperties()
{
base.OnPropertyChanged("Accounts");
base.OnPropertyChanged("Data");
base.OnPropertyChanged("MA21");
base.OnPropertyChanged("MA55");
base.OnPropertyChanged("MA90");
base.OnPropertyChanged("Title");
base.OnPropertyChanged("GainLossCompoundModelCollection");
base.OnPropertyChanged("GainLossSummaryItemCollection");
base.OnPropertyChanged("LeastSquares");
base.OnPropertyChanged("LeastSquaresTitle");
}
public void SetSymbols()
{
symbols = new ObservableCollection<String>();
symbols.Add(Constants.CONST_ALL);
List<String> tradedSymbols = portfolioTrades.Symbols;
foreach (String symbol in tradedSymbols) symbols.Add(symbol);
base.OnPropertyChanged("Symbols");
SelectedSymbol=symbols[0];
}
public ObservableCollection<String> Symbols
{
get
{
return symbols;
}
set
{
symbols = value;
base.OnPropertyChanged("Symbols");
}
}
public String SelectedSymbol
{
get
{
MDTrace.WriteLine(String.Format("[GainLossViewModel::SelectedSymbol] Get {0}",selectedSymbol));
return selectedSymbol;
}
set
{
MDTrace.WriteLine(String.Format("[GainLossViewModel::SelectedSymbol] Set {0}",selectedSymbol));
selectedSymbol = value;
base.OnPropertyChanged("SelectedSymbol");
}
}
public List<String> Accounts
{
get
{
semaphorePool[Tasks.Accounts].WaitOne();
MDTrace.WriteLine(String.Format("[GainLossViewModel::Accounts] {0}",accounts==null?"null":"non-null"));
semaphorePool[Tasks.Accounts].Release();
return accounts;
}
}
public String SelectedAccounts
{
get
{
MDTrace.WriteLine(String.Format("[GainLossViewModel:SelectedAccounts]Get '{0}'",selectedAccounts));
return selectedAccounts;
}
set
{
MDTrace.WriteLine(String.Format("[GainLossViewModel:SelectedAccounts]Set '{0}'",value));
selectedAccounts = value;
base.OnPropertyChanged("SelectedAccounts");
portfolioTrades = PortfolioDA.GetTradesForAccounts(ParseAccounts(selectedAccounts));
if(null==portfolioTrades)return;
accounts = portfolioTrades.Accounts;
SetSymbols();
}
}
private static String AccountsToString(List<String> accounts)
{
StringBuilder sb=new StringBuilder();
for(int index=0;index<accounts.Count;index++)
{
sb.Append(accounts[index]);
if(index<accounts.Count-1)sb.Append(",");
}
return sb.ToString();
}
private List<String> ParseAccounts(String strAccounts)
{
String[] accounts=strAccounts.Split(',');
return accounts.ToList();
}
// *************************************************************************************************************************************************************************
// *************************************************************************** L I N E G R A P H D A T A ***************************************************************
// *************************************************************************************************************************************************************************
public CompositeDataSource Data
{
get
{
if (null == gainLossModelCollection) return null;
CompositeDataSource compositeDataSource=null;
if(showActiveGainLoss)compositeDataSource = GainLossModel.GainLoss(gainLossModelCollection,showAsGainLoss);
else compositeDataSource = GainLossModel.TotalGainLoss(gainLossModelCollection,showAsGainLoss);
return compositeDataSource;
}
}
public CompositeDataSource LeastSquares
{
get
{
if(!useLeastSquaresFit||null==gainLossModelCollection)return null;
if(showActiveGainLoss)return GainLossModel.LeastSquares(gainLossModelCollection,showAsGainLoss);
else return GainLossModel.TotalLeastSquares(gainLossModelCollection,showAsGainLoss);
}
}
public CompositeDataSource MA21
{
get
{
if (null == gainLossModelCollection) return null;
CompositeDataSource compositeDataSource = null;
DMAValues dmaValues=null;
if(showActiveGainLoss)
{
if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLoss,21);
else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLossPercent,21);
compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
}
else
{
if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLoss,21);
else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLossPercent,21);
compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
}
return compositeDataSource;
}
}
public CompositeDataSource MA55
{
get
{
if (null == gainLossModelCollection) return null;
CompositeDataSource compositeDataSource = null;
DMAValues dmaValues=null;
if(showActiveGainLoss)
{
if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLoss,55);
else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLossPercent,55);
compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
}
else
{
if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLoss,55);
else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLossPercent,55);
compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
}
return compositeDataSource;
}
}
public CompositeDataSource MA90
{
get
{
if (null == gainLossModelCollection) return null;
CompositeDataSource compositeDataSource = null;
DMAValues dmaValues=null;
if(showActiveGainLoss)
{
if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLoss,90);
else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLossPercent,90);
compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
}
else
{
if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLoss,90);
else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLossPercent,90);
compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
}
return compositeDataSource;
}
}
// ***********************************************************************************************************************************************************************************
// ****************************************************************************** C H E C K B O X E S ******************************************************************************
// ***********************************************************************************************************************************************************************************
public Boolean CheckBoxLegendVisible
{
get
{
return isLegendVisible;
}
set
{
isLegendVisible = value;
base.OnPropertyChanged("CheckBoxLegendVisible");
base.OnPropertyChanged("LegendVisible");
}
}
public Boolean CheckBoxIncludeDividends
{
get
{
return includeDividends;
}
set
{
includeDividends = value;
base.OnPropertyChanged("CheckBoxIncludeDividends");
base.OnPropertyChanged("SelectedSymbol");
}
}
public Boolean CheckBoxUseCumulativeReturns
{
get
{
return useCumulativeGainLoss;
}
set
{
useCumulativeGainLoss=value;
base.OnPropertyChanged("CheckBoxUseCumulativeReturns");
}
}
public Boolean CheckBoxSuspendUpdate
{
get
{
return suspendUpdate;
}
set
{
suspendUpdate = value;
base.OnPropertyChanged("CheckBoxSuspendUpdate");
if(!suspendUpdate)base.OnPropertyChanged("SelectedSymbol");
}
}
public String LeastSquaresTitle
{
get
{
if(null==gainLossModelCollection)return "LeastSquares";
LeastSquaresResult leastSquaresResult=GainLossModel.LeastSquaresFit(gainLossModelCollection,showAsGainLoss);
return "LeastSquares="+Utility.FormatNumber(leastSquaresResult.Slope,2);
}
}
public Boolean LeastSquaresFit
{
get
{
return useLeastSquaresFit;
}
set
{
useLeastSquaresFit = value;
base.OnPropertyChanged("LeastSquaresFit");
}
}
public String LegendVisible
{
get
{
if (isLegendVisible) return "true";
return "false";
}
set
{
isLegendVisible = Boolean.Parse(value);
base.OnPropertyChanged("LegendVisible");
}
}
public override String Title
{
get
{
if(null==gainLossModelCollection||0==gainLossModelCollection.Count)return "";
StringBuilder sb = new StringBuilder();
sb.Append(showActiveGainLoss?"Active":"Total").Append(" ");
sb.Append("Gain/Loss ");
if (showAsGainLoss) sb.Append("($)");
else sb.Append("(%)");
if (!Constants.CONST_ALL.Equals(selectedSymbol))sb.Append(" (").Append(selectedAccounts).Append(") ").Append(" - ").Append(selectedCompanyName).Append(" (").Append(selectedSymbol).Append(") ");
else sb.Append(" (").Append(selectedAccounts).Append(") ").Append(" - ").Append(selectedCompanyName);
DateTime fromDate=gainLossModelCollection.Select(x => x.Date).Min();
DateTime toDate = gainLossModelCollection.Select(x => x.Date).Max();
sb.Append(" from ").Append(Utility.DateTimeToStringMMHDDHYYYY(fromDate));
sb.Append(" Thru ").Append(Utility.DateTimeToStringMMHDDHYYYY(toDate));
return sb.ToString();
}
}
private void Refresh()
{
latestMarketDate = PremarketDA.GetLatestMarketDate();
base.OnPropertyChanged("SelectedSymbol");
}
public ICommand RefreshCommand
{
get
{
if (refreshCommand == null)
{
refreshCommand = new RelayCommand(param => this.Refresh(), param => { return true;});
}
return refreshCommand;
}
}
// This is the button that controls the display in terms of percentages or dollar values
public String PercentButtonText
{
get
{
if (!showAsGainLoss) return "Show $";
else return "Show %";
}
}
public ICommand ToggleReturnOrPercentCommand
{
get
{
if (toggleReturnOrPercentCommand == null)
{
toggleReturnOrPercentCommand = new RelayCommand(action =>
{
showAsGainLoss = !showAsGainLoss;
base.OnPropertyChanged("SelectedSymbol");
base.OnPropertyChanged("PercentButtonText");
}, action => { return true; });
}
return toggleReturnOrPercentCommand;
}
}
// This is the button that controls the display in terms of active vs total return display on the graph
public String ActiveTotalButtonText
{
get
{
if (!showActiveGainLoss) return "Show Active G/L";
else return "Show Total G/L";
}
}
public ICommand ToggleActiveOrTotalCommand
{
get
{
if (toggleActiveOrTotalCommand == null)
{
toggleActiveOrTotalCommand = new RelayCommand(action =>
{
showActiveGainLoss=!showActiveGainLoss;
base.OnPropertyChanged("SelectedSymbol");
base.OnPropertyChanged("ActiveTotalButtonText");
}, action => { return true; });
}
return toggleActiveOrTotalCommand;
}
}
// *************************************************************************************************************************************************************************
// ***************************************************************************** T A B L E D A T A ***********************************************************************
// *************************************************************************************************************************************************************************
// The compound model collection is the data behind the views left-hand grid. This view shows the compound gain/loss since inception
public ObservableCollection<GainLossCompoundModel> GainLossCompoundModelCollection
{
get
{
return gainLossCompoundModelCollection;
}
}
// The summary item collection is the data behind the views right-hand grid. This view shows the gain/loss for the date that is selected in the compound model
public ObservableCollection<GainLossSummaryItem> GainLossSummaryItemCollection
{
get
{
return gainLossSummaryItemCollection;
}
}
// ****************************************************************************** G R I D S E L E C T I O N S ***********************************************
// The selected item in the compoint model
public GainLossCompoundModel SelectedGainLossCompoundItem
{
get
{
return selectedGainLossCompoundItem;
}
set
{
selectedGainLossCompoundItem = value;
base.OnPropertyChanged("SelectedGainLossCompoundItem");
}
}
// The selected item in the summary model
public GainLossSummaryItem SelectedGainLossSummaryItem
{
get
{
return selectedGainLossSummaryItem;
}
set
{
selectedGainLossSummaryItem = value;
base.OnPropertyChanged("SelectedGainLossSummaryItem");
}
}
// ************************************************************************************************************************************************************************************
// ************************************************************************************************************************************************************************************
// ************************************************************************************************************************************************************************************
public ObservableCollection<MenuItem> MenuItems
{
get
{
ObservableCollection<MenuItem> collection = new ObservableCollection<MenuItem>();
collection.Add(new MenuItem() { Text = "Display Bollinger Band", MenuItemClickedCommand = DisplayBollingerBand, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Dividend History", MenuItemClickedCommand = DisplayDividendHistory, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Proforma Dividend Risk", MenuItemClickedCommand = DisplayProformaDividendRisk, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Sticker Valuation", MenuItemClickedCommand = DisplayStickerValuation, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Historical", MenuItemClickedCommand = DisplayHistorical, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Stochastics", MenuItemClickedCommand = DisplayStochastic, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Relative Strength", MenuItemClickedCommand = DisplayRelativeStrength, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display MACD", MenuItemClickedCommand = DisplayMACD, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Moving Average", MenuItemClickedCommand = DisplayMovingAverage, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Price History", MenuItemClickedCommand = DisplayPriceHistory, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display DCF Valuation", MenuItemClickedCommand = DisplayDCFValuation, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Analyst Ratings", MenuItemClickedCommand = DisplayAnalystRatings, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Display Headlines", MenuItemClickedCommand = DisplayHeadlines, StaysOpenOnClick = false });
collection.Add(new MenuItem() { Text = "Roll Price Forward", MenuItemClickedCommand = RollPriceForward, StaysOpenOnClick = false });
return collection;
}
}
public ICommand DisplayBollingerBand
{
get
{
if (bollingerBandCommand == null)
{
bollingerBandCommand = new RelayCommand(param => this.DisplayBollingerBandCommand(),
param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return bollingerBandCommand;
}
}
public ICommand DisplayDividendHistory
{
get
{
if (dividendHistoryCommand == null)
{
dividendHistoryCommand = new RelayCommand(param =>
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.DividendHistoryViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}, param => { return null != selectedGainLossSummaryItem && null != selectedGainLossSummaryItem.Symbol; });
}
return dividendHistoryCommand;
}
}
public ICommand DisplayProformaDividendRisk
{
get
{
if (proformaDividendRiskCommand == null)
{
proformaDividendRiskCommand = new RelayCommand(param =>
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.DividendRiskParityViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + "");
saveParams.Referer = this;
WorkspaceInstantiator.Invoke(saveParams);
}, param => { return null != selectedGainLossSummaryItem && null != selectedGainLossSummaryItem.Symbol; });
}
return proformaDividendRiskCommand;
}
}
public ICommand DisplayStickerValuation
{
get
{
if (null == stickerValuationCommand)
{
stickerValuationCommand = new RelayCommand(param =>
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.StickerPriceViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}, param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return stickerValuationCommand;
}
}
public ICommand DisplayHistorical
{
get
{
if (displayHistoricalCommand == null)
{
displayHistoricalCommand = new RelayCommand(param =>
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.HistoricalViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}, param => { return null != selectedGainLossSummaryItem && null != selectedGainLossSummaryItem.Symbol; });
}
return displayHistoricalCommand;
}
}
public ICommand DisplayStochastic
{
get
{
if (stochasticsCommand == null)
{
stochasticsCommand = new RelayCommand(param => this.DisplayStochasticCommand(),
param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return stochasticsCommand;
}
}
public ICommand DisplayRelativeStrength
{
get
{
if (relativeStrengthCommand == null)
{
relativeStrengthCommand = new RelayCommand(param => this.DisplayRelativeStrengthCommand(),
param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return relativeStrengthCommand;
}
}
public ICommand DisplayMACD
{
get
{
if (macdCommand == null)
{
macdCommand = new RelayCommand(param => this.DisplayMACDCommand(),
param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return macdCommand;
}
}
public ICommand DisplayMovingAverage
{
get
{
if (movingAverageCommand == null)
{
movingAverageCommand = new RelayCommand(param => this.DisplayMovingAverageCommand(), param => { return null != selectedGainLossSummaryItem && null != selectedGainLossSummaryItem.Symbol; });
}
return movingAverageCommand;
}
}
public ICommand DisplayPriceHistory
{
get
{
if (priceHistoryCommand == null)
{
priceHistoryCommand = new RelayCommand(param => this.DisplayPriceHistoryCommand(),
param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return priceHistoryCommand;
}
}
public ICommand DisplayDCFValuation
{
get
{
if (null == dcfValuationCommand)
{
dcfValuationCommand = new RelayCommand(param =>
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.DCFValuationViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}, param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return dcfValuationCommand;
}
}
public ICommand DisplayAnalystRatings
{
get
{
if (null == displayAnalystRatingsCommand)
{
displayAnalystRatingsCommand = new RelayCommand(param =>
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.AnalystRatingsViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}, param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return displayAnalystRatingsCommand;
}
}
public ICommand DisplayHeadlines
{
get
{
if (null == displayHeadlinesCommand)
{
displayHeadlinesCommand = new RelayCommand(param =>
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.HeadlinesViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,Valuations");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}, param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
}
return displayHeadlinesCommand;
}
}
public ICommand RollPriceForward
{
get
{
if (null == rollPriceForwardCommand)
{
rollPriceForwardCommand = new RelayCommand(param =>
{
Price previousPrice=PricingDA.GetPrice(selectedGainLossSummaryItem.Symbol);
Price latestPrice=PricingMarketDataHelper.RollPriceForward(selectedGainLossSummaryItem.Symbol);
System.Windows.MessageBox.Show(String.Format("{0} price rolled forward from {1} to {2}",selectedGainLossSummaryItem.Symbol,previousPrice.Date.ToShortDateString(),latestPrice.Date.ToShortDateString()),"Info",MessageBoxButton.OK,MessageBoxImage.Information);
ClearCache();
HandleSelectedSymbol();
}, param =>
{
if(null == selectedGainLossSummaryItem || null==selectedGainLossSummaryItem.Symbol)return false;
Price symbolPrice=GBPriceCache.GetInstance().GetPriceOrLatestAvailable(selectedGainLossSummaryItem.Symbol,latestMarketDate);
if(null==symbolPrice)return false;
if(symbolPrice.Date.Equals(latestMarketDate))return false;
DateGenerator dateGenerator=new DateGenerator();
DateTime prevBusinessDay=dateGenerator.FindPrevBusinessDay(latestMarketDate);
if(!symbolPrice.Date.Equals(prevBusinessDay))return false;
// This method was slowing things down quite considerably as it was constantly hitting the pricingDA.GetLatestDate()
// Refactored to the above code and seeing how that works out.
//DateTime latestDate=PremarketDA.GetLatestMarketDate();
//DateTime latestDateSymbol=PricingDA.GetLatestDate(selectedGainLossSummaryItem.Symbol);
//if(latestDate.Equals(latestDateSymbol))return false;
//DateGenerator dateGenerator=new DateGenerator();
//DateTime prevBusinessDay=dateGenerator.FindPrevBusinessDay(latestDate);
//if(!latestDateSymbol.Equals(prevBusinessDay))return false;
return true;
});
}
return rollPriceForwardCommand;
}
}
private void ClearCache()
{
try{LocalPriceCache.GetInstance().Clear();}catch(Exception){;}
try{GBPriceCache.GetInstance().Clear();}catch(Exception){;}
}
// **************************************************************************************************************************************************************************************
// ******************************************************************************** C O M M A N D S *************************************************************************************
// **************************************************************************************************************************************************************************************
public void DisplayBollingerBandCommand()
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.BollingerBandViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,180,SyncTradeToBand,FALSE");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}
public void DisplayRelativeStrengthCommand()
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.RSIViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,60,SelectedRSIDayCount,3");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}
public void DisplayStochasticCommand()
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.StochasticsViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,90");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}
public void DisplayMACDCommand()
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.MACDViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,90");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}
public void DisplayMovingAverageCommand()
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.MovingAverageViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,360");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}
public void DisplayPriceHistoryCommand()
{
SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.PricingViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,90");
saveParams.Referer=this;
WorkspaceInstantiator.Invoke(saveParams);
}
// **************************************************************************************************************************************************
// ************************************************************* T O O L T I P C A L L O U T*******************************************************
// **************************************************************************************************************************************************
public String DollarChangePercent
{
get
{
return "'$ Change(%)' is calculated as a percentage of dollar change in market value from the previous period to the current period.\nThis number may appear skewed if share count has changed day over day.";
}
}
public String Parity
{
get
{
if(null== selectedGainLossSummaryItem || null==selectedGainLossSummaryItem.Symbol)return "No row selected.";
StringBuilder sb=new StringBuilder();
PortfolioTrades portfolioTrades=PortfolioDA.GetOpenTradesSymbol(selectedGainLossSummaryItem.Symbol);
double weightAdjustedDividendYield=portfolioTrades.GetWeightAdjustedDividendYield();
DateTime currentDate=PricingDA.GetLatestDate(selectedGainLossSummaryItem.Symbol);
String companyName=PricingDA.GetNameForSymbol(selectedGainLossSummaryItem.Symbol);
if(null!=companyName)sb.Append(companyName).Append("\n");
CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(selectedGainLossSummaryItem.Symbol);
if(null!=companyProfile)
{
sb.Append(companyProfile.Sector??Constants.CONST_QUESTION).Append("/").Append(companyProfile.Industry??Constants.CONST_QUESTION).Append("\n");
}
if(null!=portfolioTrades&&0!=portfolioTrades.Count)
{
double shares=(from PortfolioTrade portfolioTrade in portfolioTrades select portfolioTrade.Shares).Sum();
double exposure=portfolioTrades.Sum(x=>x.Exposure());
// Calculate the gain loss so that we can show the difference between our all time high percentage and where we are right now
InstantiateGenerators();
GainLossCollection gainLoss=activeGainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions
GainLossItem maxGainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault();
GainLossItem minGainLossItem=gainLoss.OrderBy(x => x.GainLossPercent).FirstOrDefault();
String accounts=Utility.ListToString(portfolioTrades.Accounts);
sb.Append("You own '").Append(selectedGainLossSummaryItem.Symbol).Append("' in ").Append(portfolioTrades.Count).Append(" lot(s) (").Append(Utility.FormatNumber(shares,0,true)).Append(" shares) ").Append("Exposure: ").Append(Utility.FormatCurrency(exposure));
sb.Append("\n").Append("Accounts: ").Append(accounts);
if(!double.IsNaN(weightAdjustedDividendYield))
{
sb.Append("\n").Append("Dividend Yield: ").Append(Utility.FormatPercent(weightAdjustedDividendYield)).Append(" ");
sb.Append("(").Append(Utility.FormatCurrency(exposure*weightAdjustedDividendYield)).Append("/Yr.)");
}
ParityElement parityElement=ParityGenerator.GenerateBreakEven(selectedGainLossSummaryItem.Symbol);
if(null!=parityElement)
{
sb.Append("\n").Append(parityElement.ToString());
sb.Append("\n").Append("All Time Gain/Loss: ").Append(maxGainLossItem.GainLossPercent<0?"":"+").Append(Utility.FormatPercent(maxGainLossItem.GainLossPercent/100));
sb.Append(" (").Append(minGainLossItem.GainLossPercent<0?"":"+").Append(Utility.FormatPercent(minGainLossItem.GainLossPercent/100)).Append(")");
}
}
else sb.Append("You don't hold any shares of '").Append(selectedGainLossSummaryItem.Symbol).Append("'");
sb.Append(".");
DateGenerator dateGenerator=new DateGenerator();
DateTime priorDate=dateGenerator.FindPrevBusinessDay(currentDate);
Price p1=PricingDA.GetPrice(selectedGainLossSummaryItem.Symbol,currentDate);
Price p2=PricingDA.GetPrice(selectedGainLossSummaryItem.Symbol,priorDate);
if(null==p2&&null!=p1)
{
priorDate=dateGenerator.FindPrevBusinessDay(priorDate);
p2=PricingDA.GetPrice(selectedGainLossSummaryItem.Symbol,priorDate);
}
if(null==p1||null==p2)return sb.ToString();
sb.Append("\n");
double change=(p1.Close-p2.Close)/p2.Close;
sb.Append(String.Format("Latest Price {0} {1} ({2}{3})",Utility.DateTimeToStringMMSDDSYYYY(p1.Date),Utility.FormatCurrency(p1.Close),change<0?"-":"+",Utility.FormatPercent(Math.Abs(change))));
if(companyProfile.FreezePricing)sb.Append(" ").Append("**Frozen**");
sb.Append("\n").Append(String.Format("Source: {0}",p1.SourceAsString()));
return sb.ToString();
}
}
}
}