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 gainLossList=new List(); LocalPriceCache.GetInstance().Add(portfolioTrades); try { if(!ValidatePortfolioTrades(portfolioTrades))return null; DateTime minDate=portfolioTrades.GetMinTradeDate(); DateTime maxDate = LocalPriceCache.GetInstance().GetLatestDate(); if(null!=maxDateRef) maxDate=maxDateRef.Value; double prevGainLoss=double.NaN; List 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=LocalPriceCache.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()); } } public TotalGainLossCollection GenerateTotalGainLossWithDividends(PortfolioTrades portfolioTrades,DividendPayments dividendPayments,DateTime? maxDateRef=null) { DateGenerator dateGenerator=new DateGenerator(); ModelPerformanceSeries performanceSeries=new ModelPerformanceSeries(); List gainLossList=new List(); LocalPriceCache.GetInstance().Add(portfolioTrades); try { if(!ValidatePortfolioTrades(portfolioTrades)) return null; DateTime minDate=portfolioTrades.Min(x => x.TradeDate); DateTime maxDate = LocalPriceCache.GetInstance().GetLatestDate(); double prevGainLoss=double.NaN; List 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=LocalPriceCache.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()); } } 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; } } }