188 lines
8.6 KiB
C#
188 lines
8.6 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using MarketData;
|
|
using MarketData.MarketDataModel;
|
|
using MarketData.MarketDataModel.GainLoss;
|
|
using MarketData.Utils;
|
|
using MarketData.DataAccess;
|
|
using MarketData.Cache;
|
|
|
|
namespace MarketData.Generator.GainLoss
|
|
{
|
|
public class GainLossGeneratorCum : ITotalGainLossGenerator
|
|
{
|
|
private DateGenerator dateGenerator=new DateGenerator();
|
|
|
|
public TotalGainLossCollection GenerateTotalGainLoss(PortfolioTrades portfolioTrades,DateTime? maxDateRef=null)
|
|
{
|
|
DateGenerator dateGenerator=new DateGenerator();
|
|
ModelPerformanceSeries performanceSeries=new ModelPerformanceSeries();
|
|
List<TotalGainLossItem> gainLossList=new List<TotalGainLossItem>();
|
|
GLPriceCache.GetInstance().Add(portfolioTrades);
|
|
try
|
|
{
|
|
if(!ValidatePortfolioTrades(portfolioTrades))return null;
|
|
DateTime minDate=portfolioTrades.GetMinTradeDate();
|
|
DateTime maxDate = GLPriceCache.GetInstance().GetLatestDate();
|
|
if(null!=maxDateRef) maxDate=maxDateRef.Value;
|
|
double prevGainLoss=double.NaN;
|
|
List<DateTime> historicalDates=dateGenerator.GenerateHistoricalDates(minDate,maxDate);
|
|
|
|
foreach(DateTime currentDate in historicalDates)
|
|
{
|
|
PortfolioTrades openPositions=portfolioTrades.GetOpenTradesOn(currentDate);
|
|
PortfolioTrades closedPositions=portfolioTrades.GetClosedTradesOn(currentDate);
|
|
if(0==openPositions.Count&&0==closedPositions.Count) continue;
|
|
|
|
double gainLoss=0.00;
|
|
double gainLossClosedPositions=0.00;
|
|
double exposure=0.00;
|
|
double marketValue=0.00;
|
|
|
|
if(!dateGenerator.IsMarketOpen(currentDate)) continue;
|
|
ModelPerformanceItem performanceItem=new ModelPerformanceItem();
|
|
|
|
foreach(PortfolioTrade openPosition in openPositions)
|
|
{
|
|
exposure+=openPosition.Shares*openPosition.Price;
|
|
Price price=GLPriceCache.GetInstance().GetPrice(openPosition.Symbol,currentDate);
|
|
if(null==price)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("No price for {0} on {1}",openPosition.Symbol,currentDate.ToShortDateString()));
|
|
continue;
|
|
}
|
|
gainLoss+=((price.Close*openPosition.Shares)-(openPosition.Price*openPosition.Shares));
|
|
marketValue+=(price.Close*openPosition.Shares);
|
|
}
|
|
foreach(PortfolioTrade closedPosition in closedPositions)
|
|
{
|
|
double gainLossPosition=(closedPosition.SellPrice*closedPosition.Shares)-(closedPosition.Price*closedPosition.Shares);
|
|
gainLossClosedPositions+=gainLossPosition;
|
|
}
|
|
performanceItem.Date=currentDate;
|
|
performanceItem.Exposure=exposure;
|
|
performanceItem.MarketValue=marketValue;
|
|
performanceItem.GainLossDOD=double.IsNaN(prevGainLoss)?gainLoss:(gainLoss-prevGainLoss)+gainLossClosedPositions;
|
|
performanceItem.GainLoss=gainLoss+gainLossClosedPositions;
|
|
performanceItem.ClosedPositions=closedPositions.Count>0?true:false;
|
|
performanceSeries.Add(performanceItem);
|
|
prevGainLoss=gainLoss;
|
|
}
|
|
performanceSeries.CalculatePerformance();
|
|
double totalGainLoss=double.NaN;
|
|
foreach(ModelPerformanceItem performanceItem in performanceSeries)
|
|
{
|
|
if(double.IsNaN(totalGainLoss))totalGainLoss=performanceItem.GainLossDOD;
|
|
else totalGainLoss+=performanceItem.GainLossDOD;
|
|
TotalGainLossItem totalGainLossItem=new TotalGainLossItem(
|
|
performanceItem.Date,
|
|
totalGainLoss,
|
|
performanceItem.CumProdMinusOne*100.00,
|
|
performanceItem.Exposure,
|
|
performanceItem.MarketValue);
|
|
gainLossList.Add(totalGainLossItem);
|
|
}
|
|
TotalGainLossCollection totalGainLossCollection= new TotalGainLossCollection(gainLossList);
|
|
totalGainLossCollection.Sort();
|
|
return totalGainLossCollection;
|
|
}
|
|
catch(Exception exception)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception: {0}",exception.ToString()));
|
|
return new TotalGainLossCollection(new List<TotalGainLossItem>());
|
|
}
|
|
}
|
|
public TotalGainLossCollection GenerateTotalGainLossWithDividends(PortfolioTrades portfolioTrades,DividendPayments dividendPayments,DateTime? maxDateRef=null)
|
|
{
|
|
DateGenerator dateGenerator=new DateGenerator();
|
|
ModelPerformanceSeries performanceSeries=new ModelPerformanceSeries();
|
|
List<TotalGainLossItem> gainLossList=new List<TotalGainLossItem>();
|
|
GLPriceCache.GetInstance().Add(portfolioTrades);
|
|
try
|
|
{
|
|
if(!ValidatePortfolioTrades(portfolioTrades)) return null;
|
|
DateTime minDate=portfolioTrades.Min(x => x.TradeDate);
|
|
DateTime maxDate = GLPriceCache.GetInstance().GetLatestDate();
|
|
double prevGainLoss=double.NaN;
|
|
List<DateTime> historicalDates=dateGenerator.GenerateHistoricalDates(minDate,maxDate);
|
|
|
|
foreach(DateTime currentDate in historicalDates)
|
|
{
|
|
PortfolioTrades openPositions=portfolioTrades.GetOpenTradesOn(currentDate);
|
|
PortfolioTrades closedPositions=portfolioTrades.GetClosedTradesOn(currentDate);
|
|
if(0==openPositions.Count&&0==closedPositions.Count) continue;
|
|
|
|
double gainLoss=0.00;
|
|
double gainLossClosedPositions=0.00;
|
|
double exposure=0.00;
|
|
double marketValue=0.00;
|
|
if(!dateGenerator.IsMarketOpen(currentDate)) continue;
|
|
ModelPerformanceItem performanceItem=new ModelPerformanceItem();
|
|
|
|
foreach(PortfolioTrade openPosition in openPositions)
|
|
{
|
|
exposure+=openPosition.Shares*openPosition.Price;
|
|
Price price=GLPriceCache.GetInstance().GetPrice(openPosition.Symbol,currentDate);
|
|
if(null==price)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("No price for {0} on {1}",openPosition.Symbol,currentDate.ToShortDateString()));
|
|
}
|
|
gainLoss+=((price.Close*openPosition.Shares)-(openPosition.Price*openPosition.Shares));
|
|
marketValue+=(price.Close*openPosition.Shares);
|
|
}
|
|
foreach(PortfolioTrade closedPosition in closedPositions)
|
|
{
|
|
double gainLossPosition=(closedPosition.SellPrice*closedPosition.Shares)-(closedPosition.Price*closedPosition.Shares);
|
|
gainLossClosedPositions+=gainLossPosition;
|
|
}
|
|
double dividendPaymentsToDate=dividendPayments.GetDividendPaymentsToDate(currentDate);
|
|
marketValue+=dividendPaymentsToDate;
|
|
gainLoss+=dividendPaymentsToDate;
|
|
performanceItem.Date=currentDate;
|
|
performanceItem.Exposure=exposure;
|
|
performanceItem.MarketValue=marketValue;
|
|
performanceItem.GainLossDOD=double.IsNaN(prevGainLoss)?gainLoss:(gainLoss-prevGainLoss)+gainLossClosedPositions;
|
|
performanceItem.GainLoss=gainLoss+gainLossClosedPositions;
|
|
performanceItem.ClosedPositions=closedPositions.Count>0?true:false;
|
|
performanceSeries.Add(performanceItem);
|
|
prevGainLoss=gainLoss;
|
|
}
|
|
performanceSeries.CalculatePerformance();
|
|
double totalGainLoss=double.NaN;
|
|
foreach(ModelPerformanceItem performanceItem in performanceSeries)
|
|
{
|
|
double dividendPaymentsToDate=dividendPayments.GetDividendPaymentsToDate(performanceItem.Date);
|
|
if(double.IsNaN(totalGainLoss))totalGainLoss=performanceItem.GainLossDOD;
|
|
else totalGainLoss+=performanceItem.GainLossDOD;
|
|
TotalGainLossItem totalGainLossItem=new TotalGainLossItem(
|
|
performanceItem.Date,
|
|
totalGainLoss,
|
|
performanceItem.CumProdMinusOne*100.00,
|
|
performanceItem.Exposure,
|
|
performanceItem.MarketValue,
|
|
dividendPaymentsToDate);
|
|
gainLossList.Add(totalGainLossItem);
|
|
}
|
|
TotalGainLossCollection totalGainLossCollection= new TotalGainLossCollection(gainLossList);
|
|
totalGainLossCollection.Sort();
|
|
return totalGainLossCollection;
|
|
}
|
|
catch(Exception exception)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception: {0}",exception.ToString()));
|
|
return new TotalGainLossCollection(new List<TotalGainLossItem>());
|
|
}
|
|
}
|
|
public bool ValidatePortfolioTrades(PortfolioTrades portfolioTrades)
|
|
{
|
|
foreach(PortfolioTrade portfolioTrade in portfolioTrades)
|
|
{
|
|
if(!dateGenerator.IsMarketOpen(portfolioTrade.TradeDate))return false;
|
|
if(!dateGenerator.IsMarketOpen(portfolioTrade.SellDate)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|