using System; using System.Windows.Input; using System.ComponentModel; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Windows; using System.Text; using System.Linq; using System.Threading.Tasks; using System.Threading; using MarketData.DataAccess; using MarketData.MarketDataModel; using TradeBlotter.Command; using TradeBlotter.Cache; using TradeBlotter.Model; using Telerik.Charting; using Telerik.Windows.Controls.Charting; using MarketData; using MarketData.ValueAtRisk; using MarketData.Utils; using System.Windows.Controls; using TradeBlotter.UIUtils; namespace TradeBlotter.ViewModels { public class CategoricalDataPointWithDesc : CategoricalDataPoint { public String CustomLabel { get; set; } } public class RiskProfileViewModel : WorkspaceViewModel { private PortfolioTrades portfolioTrades = null; private List betaContributionDataPoints = null; private List betaDataPoints = null; private PortfolioHoldingsWithBeta portfolioHoldingsWithBeta = null; private List sharpeRatioContributionDataPoints = null; private List sharpeRatioSharpeRatioDataPoints = null; private PortfolioHoldingsWithSharpeRatio portfolioHoldingsWithSharpeRatio = null; // Command Targets private RelayCommand resetCommand; private RelayCommand proformaAddPositionCommand; private RelayCommand chooseDateCommand; private RelayCommand chooseDateLostFocusCommand; private String selectedAccount = Constants.CONST_ALL; private bool busyIndicator = false; private List openTradeDates; private List blackoutDates; private DateTime selectedDate; private DateTime displayDate; private bool isCalendarOpen = false; public RiskProfileViewModel() { base.DisplayName = "Risk Profile"; BusyIndicator = true; portfolioTrades = PortfolioDA.GetTrades(); openTradeDates = PortfolioTrades.GetOpenTradeDates(); GetBlackoutDates(); selectedDate = openTradeDates[0]; displayDate = selectedDate; PropertyChanged += OnViewModelPropertyChanged; SelectedAccount = Constants.CONST_ALL; BusyIndicator = false; } private void GetBlackoutDates() { DateGenerator dateGenerator = new DateGenerator(); blackoutDates=new List(); Dictionary openTradeDatesDict = new Dictionary(); List historicalDates=dateGenerator.GenerateHistoricalDatesActual(openTradeDates[0], openTradeDates[openTradeDates.Count - 1]); foreach(DateTime openTradeDate in openTradeDates)if(!openTradeDatesDict.ContainsKey(openTradeDate))openTradeDatesDict.Add(openTradeDate,openTradeDate); foreach(DateTime historicalDate in historicalDates)if(!openTradeDatesDict.ContainsKey(historicalDate))blackoutDates.Add(new CalendarDateRange(historicalDate,historicalDate)); } public override SaveParameters GetSaveParameters() { return null; } public override void SetSaveParameters(SaveParameters saveParameters) { } public override String Title { get { if (!Constants.CONST_ALL.Equals(selectedAccount)) return base.DisplayName + " - " + selectedAccount; return base.DisplayName; } } public override bool CanPersist() { return false; } protected override void OnDispose() { } public bool BusyIndicator { get { return busyIndicator; } set { busyIndicator = value; base.OnPropertyChanged("BusyIndicator"); } } private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs) { if (eventArgs.PropertyName.Equals("SelectedAccount") || eventArgs.PropertyName.Equals("Accounts")) { BusyIndicator = true; Task workerTask = Task.Factory.StartNew(() => { portfolioTrades = PortfolioDA.GetOpenTradesAsOf(selectedDate); portfolioTrades = portfolioTrades.RemoveClosedTradesWhereClosedOn(selectedDate); CreateBetaContribution(portfolioTrades,selectedDate); CreateSharpeRatioContribution(portfolioTrades,selectedDate); }); workerTask.ContinueWith((continuation) => { BusyIndicator = false; base.OnPropertyChanged("CartesianChartDataSharpeRatioContribution"); base.OnPropertyChanged("CartesianChartDataSharpeRatioSharpeRatio"); base.OnPropertyChanged("CartesianChartDataBetaContribution"); base.OnPropertyChanged("CartesianChartDataBeta"); base.OnPropertyChanged("TitleBetaContribution"); base.OnPropertyChanged("TitleSharpeRationContribution"); base.OnPropertyChanged("BetaDescription"); }); } else if (eventArgs.PropertyName.Equals("SelectedDate")) { BusyIndicator = true; Task workerTask = Task.Factory.StartNew(() => { portfolioTrades = PortfolioDA.GetOpenTradesAsOf(selectedDate); portfolioTrades = portfolioTrades.RemoveClosedTradesWhereClosedOn(selectedDate); CreateBetaContribution(portfolioTrades, selectedDate); CreateSharpeRatioContribution(portfolioTrades, selectedDate); }); workerTask.ContinueWith((continuation) => { BusyIndicator = false; base.OnPropertyChanged("CartesianChartDataSharpeRatioContribution"); base.OnPropertyChanged("CartesianChartDataSharpeRatioSharpeRatio"); base.OnPropertyChanged("CartesianChartDataBetaContribution"); base.OnPropertyChanged("CartesianChartDataBeta"); base.OnPropertyChanged("TitleBetaContribution"); base.OnPropertyChanged("TitleSharpeRationContribution"); base.OnPropertyChanged("BetaDescription"); }); } } private void CreateBetaContribution(PortfolioTrades portfolioTrades, DateTime analysisDate) { PortfolioTrades accountTrades = GetAccountTrades(); PortfolioHoldings portfolioHoldings = PortfolioHoldings.GetPortfolioHoldings(accountTrades, 5, analysisDate); betaContributionDataPoints = new List(); betaDataPoints = new List(); portfolioHoldingsWithBeta = new PortfolioHoldingsWithBeta(portfolioHoldings, analysisDate); portfolioHoldingsWithBeta = new PortfolioHoldingsWithBeta((from PortfolioHoldingWithBeta portfolioHoldingWithBeta in portfolioHoldingsWithBeta select portfolioHoldingWithBeta).OrderByDescending(x => x.BetaContribution).ToList()); foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in portfolioHoldingsWithBeta) { CategoricalDataPointWithDesc categoricalDataPoint = new CategoricalDataPointWithDesc(); categoricalDataPoint.Category = portfolioHoldingWithBeta.Symbol; categoricalDataPoint.Value = double.IsNaN(portfolioHoldingWithBeta.BetaContribution)?double.NaN:double.Parse(Utility.FormatNumber(portfolioHoldingWithBeta.BetaContribution*100, 2)); categoricalDataPoint.CustomLabel = "cR=" + Utility.FormatPercent(portfolioHoldingWithBeta.BetaContribution); betaContributionDataPoints.Add(categoricalDataPoint); } foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in portfolioHoldingsWithBeta) { CategoricalDataPointWithDesc categoricalDataPoint = new CategoricalDataPointWithDesc(); categoricalDataPoint.Category = portfolioHoldingWithBeta.Symbol; categoricalDataPoint.Value = double.IsNaN(portfolioHoldingWithBeta.Beta) ? double.NaN : double.Parse(Utility.FormatNumber(portfolioHoldingWithBeta.Beta * 100.00, 2)); categoricalDataPoint.CustomLabel = "b="+Utility.FormatNumber(portfolioHoldingWithBeta.Beta,2); betaDataPoints.Add(categoricalDataPoint); } } private void CreateSharpeRatioContribution(PortfolioTrades portfolioTrades,DateTime analysisDate) { PortfolioTrades accountTrades = GetAccountTrades(); PortfolioHoldings portfolioHoldings = PortfolioHoldings.GetPortfolioHoldings(accountTrades, 5, analysisDate); sharpeRatioContributionDataPoints = new List(); sharpeRatioSharpeRatioDataPoints = new List(); portfolioHoldingsWithSharpeRatio = new PortfolioHoldingsWithSharpeRatio(portfolioHoldings,analysisDate); portfolioHoldingsWithSharpeRatio = new PortfolioHoldingsWithSharpeRatio((from PortfolioHoldingWithSharpeRatio portfolioHoldingWithSharpeRatio in portfolioHoldingsWithSharpeRatio select portfolioHoldingWithSharpeRatio).OrderByDescending(x => x.SharpeRatioContribution).ToList()); foreach (PortfolioHoldingWithSharpeRatio portfolioHoldingWithSharpeRatio in portfolioHoldingsWithSharpeRatio) { CategoricalDataPointWithDesc categoricalDataPoint = new CategoricalDataPointWithDesc(); categoricalDataPoint.Category = portfolioHoldingWithSharpeRatio.Symbol; categoricalDataPoint.Value = double.IsNaN(portfolioHoldingWithSharpeRatio.SharpeRatioContribution)?double.NaN:double.Parse(Utility.FormatNumber(portfolioHoldingWithSharpeRatio.SharpeRatioContribution*100, 2)); categoricalDataPoint.CustomLabel = "cR=" + Utility.FormatPercent(portfolioHoldingWithSharpeRatio.SharpeRatioContribution); sharpeRatioContributionDataPoints.Add(categoricalDataPoint); } foreach (PortfolioHoldingWithSharpeRatio portfolioHoldingWithSharpeRatio in portfolioHoldingsWithSharpeRatio) { CategoricalDataPointWithDesc categoricalDataPoint = new CategoricalDataPointWithDesc(); categoricalDataPoint.Category = portfolioHoldingWithSharpeRatio.Symbol; categoricalDataPoint.Value = double.IsNaN(portfolioHoldingWithSharpeRatio.SharpeRatio) ? double.NaN : double.Parse(Utility.FormatNumber(portfolioHoldingWithSharpeRatio.SharpeRatio * 100.00, 2)); categoricalDataPoint.CustomLabel = "sR="+Utility.FormatNumber(portfolioHoldingWithSharpeRatio.SharpeRatio,2); sharpeRatioSharpeRatioDataPoints.Add(categoricalDataPoint); } } public PortfolioTrades GetAccountTrades() { if (Constants.CONST_ALL.Equals(selectedAccount)) return portfolioTrades; return portfolioTrades.FilterAccount(selectedAccount); } // *************************************************************************************************************************************************** // ************************************************************* C H A R T I N G C O L L E C T I O N S ********************************************* // *************************************************************************************************************************************************** public ObservableCollection CartesianChartDataBetaContribution { get { if (null == betaContributionDataPoints) return null; return new ObservableCollection(betaContributionDataPoints); } } public ObservableCollection CartesianChartDataBeta { get { if (null == betaDataPoints) return null; return new ObservableCollection(betaDataPoints); } } public ObservableCollection CartesianChartDataSharpeRatioContribution { get { if (null == sharpeRatioContributionDataPoints) return null; return new ObservableCollection(sharpeRatioContributionDataPoints); } } public ObservableCollection CartesianChartDataSharpeRatioSharpeRatio { get { if (null == sharpeRatioSharpeRatioDataPoints) return null; return new ObservableCollection(sharpeRatioSharpeRatioDataPoints); } } public List Accounts { get { if (null == portfolioTrades) { portfolioTrades = PortfolioDA.GetOpenTradesAsOf(selectedDate); portfolioTrades = portfolioTrades.RemoveClosedTradesWhereClosedOn(selectedDate); } List accounts = portfolioTrades.Accounts; accounts.Insert(0, Constants.CONST_ALL); return accounts; } } public String TitleBetaContribution { get { StringBuilder sb = new StringBuilder(); sb.Append("Beta Contribution - "); sb.Append(String.Format("{0}",selectedDate.ToShortDateString())).Append(" "); if (Constants.CONST_ALL.Equals(selectedAccount)) sb.Append("All Accounts "); else sb.Append("Account ").Append(selectedAccount); sb.Append(" (beta="); if (null != portfolioHoldingsWithBeta) sb.Append(Utility.FormatNumber(portfolioHoldingsWithBeta.PortfolioBeta)); sb.Append(")"); return sb.ToString(); } } public String TitleSharpeRationContribution { get { StringBuilder sb = new StringBuilder(); sb.Append("Sharpe Ratio (Contribution to Risk Adjusted Return) - "); sb.Append(String.Format("{0}",selectedDate.ToShortDateString())).Append(" "); if (Constants.CONST_ALL.Equals(selectedAccount)) sb.Append("All Accounts "); else sb.Append("Account ").Append(selectedAccount); sb.Append(" (Sharpe Ratio="); if (null != portfolioHoldingsWithSharpeRatio) sb.Append(Utility.FormatNumber(portfolioHoldingsWithSharpeRatio.TotalSharpeRatio)); sb.Append(")"); return sb.ToString(); } } public String BetaDescription { get { if (null == portfolioHoldingsWithBeta) return ""; StringBuilder sb = new StringBuilder(); sb.Append("This portfolio is expected to rise or fall by a multiple of ").Append(Utility.FormatNumber(portfolioHoldingsWithBeta.PortfolioBeta,3)); sb.Append(" or ").Append(Utility.FormatCurrency(.01 * portfolioHoldingsWithBeta.PortfolioBeta * portfolioHoldingsWithBeta.Exposure)).Append(""); sb.Append(" for every 1% of market movement. ** weight / beta contribution / beta **"); return sb.ToString(); } } //***************************************************************************************************************************************************************** // ******************************************************************* I C O M M A N D ************************************************************************** //***************************************************************************************************************************************************************** public ICommand ResetCommand { get { if (null == resetCommand) { resetCommand = new RelayCommand(param => { selectedDate = displayDate=openTradeDates[0]; base.OnPropertyChanged("SelectedDate"); base.OnPropertyChanged("DisplayDate"); }, param => { return true; }); } return resetCommand; } } public ICommand ChooseDateCommand { get { if (null == chooseDateCommand) { chooseDateCommand = new RelayCommand(param => { isCalendarOpen = !isCalendarOpen; base.OnPropertyChanged("IsCalendarOpen"); }, param => { return true; }); } return chooseDateCommand; } } public ICommand ProformaAddPositionCommand { get { if (null == proformaAddPositionCommand) { proformaAddPositionCommand = new RelayCommand(param => { portfolioTrades=ProformaAddPositionDialog.Prompt("Proforma Add Position", SelectedAccount, SelectedDate, portfolioTrades); CreateBetaContribution(portfolioTrades, selectedDate); CreateSharpeRatioContribution(portfolioTrades, selectedDate); base.OnPropertyChanged("CartesianChartDataSharpeRatioContribution"); base.OnPropertyChanged("CartesianChartDataSharpeRatioSharpeRatio"); base.OnPropertyChanged("CartesianChartDataBetaContribution"); base.OnPropertyChanged("CartesianChartDataBeta"); base.OnPropertyChanged("TitleBetaContribution"); base.OnPropertyChanged("TitleSharpeRationContribution"); base.OnPropertyChanged("BetaDescription"); }, param => { return true; }); } return proformaAddPositionCommand; } } //***************************************************************************************************************************************************************** // ************************************************************************** A C C O U N T ********************************************************************* //***************************************************************************************************************************************************************** public String SelectedAccount { get { return selectedAccount; } set { selectedAccount = value; isCalendarOpen = false; base.OnPropertyChanged("IsCalendarOpen"); base.OnPropertyChanged("SelectedAccount"); } } //***************************************************************************************************************************************************************** // ******************************************************************* C A L E N D A R M A N A G E M E N T ***************************************************** //***************************************************************************************************************************************************************** public bool IsCalendarOpen { get { return isCalendarOpen; } set { isCalendarOpen = value; base.OnPropertyChanged("IsCalendarOpen"); } } public DateTime SelectedDate { get{return selectedDate;} set { isCalendarOpen = false; selectedDate = value; displayDate = value; base.OnPropertyChanged("IsCalendarOpen"); base.OnPropertyChanged("DisplayDate"); base.OnPropertyChanged("SelectedDate"); } } public DateTime DisplayDateStart { get{return openTradeDates[openTradeDates.Count-1];} } public DateTime DisplayDateEnd { get{return openTradeDates[0];} } public DateTime DisplayDate { get { return displayDate; } set { displayDate = value;base.OnPropertyChanged("DisplayDate");} } public List BlackoutDates { get { return blackoutDates; } } } }