Files
TradeBlotter/ViewModels/RiskProfileViewModel.cs
2024-02-23 06:58:53 -05:00

414 lines
19 KiB
C#

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<CategoricalDataPointWithDesc> betaContributionDataPoints = null;
private List<CategoricalDataPointWithDesc> betaDataPoints = null;
private PortfolioHoldingsWithBeta portfolioHoldingsWithBeta = null;
private List<CategoricalDataPointWithDesc> sharpeRatioContributionDataPoints = null;
private List<CategoricalDataPointWithDesc> 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<DateTime> openTradeDates;
private List<CalendarDateRange> 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<CalendarDateRange>();
Dictionary<DateTime,DateTime> openTradeDatesDict = new Dictionary<DateTime, DateTime>();
List<DateTime> 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<CategoricalDataPointWithDesc>();
betaDataPoints = new List<CategoricalDataPointWithDesc>();
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<CategoricalDataPointWithDesc>();
sharpeRatioSharpeRatioDataPoints = new List<CategoricalDataPointWithDesc>();
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<CategoricalDataPoint> CartesianChartDataBetaContribution
{
get
{
if (null == betaContributionDataPoints) return null;
return new ObservableCollection<CategoricalDataPoint>(betaContributionDataPoints);
}
}
public ObservableCollection<CategoricalDataPoint> CartesianChartDataBeta
{
get
{
if (null == betaDataPoints) return null;
return new ObservableCollection<CategoricalDataPoint>(betaDataPoints);
}
}
public ObservableCollection<CategoricalDataPoint> CartesianChartDataSharpeRatioContribution
{
get
{
if (null == sharpeRatioContributionDataPoints) return null;
return new ObservableCollection<CategoricalDataPoint>(sharpeRatioContributionDataPoints);
}
}
public ObservableCollection<CategoricalDataPoint> CartesianChartDataSharpeRatioSharpeRatio
{
get
{
if (null == sharpeRatioSharpeRatioDataPoints) return null;
return new ObservableCollection<CategoricalDataPoint>(sharpeRatioSharpeRatioDataPoints);
}
}
public List<String> Accounts
{
get
{
if (null == portfolioTrades)
{
portfolioTrades = PortfolioDA.GetOpenTradesAsOf(selectedDate);
portfolioTrades = portfolioTrades.RemoveClosedTradesWhereClosedOn(selectedDate);
}
List<String> 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<CalendarDateRange> BlackoutDates
{
get
{
return blackoutDates;
}
}
}
}