414 lines
19 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|