using MarketData.MarketDataModel; using MarketData.DataAccess; using MarketData.Utils; using MarketData.Generator.GainLoss; using MarketData.MarketDataModel.GainLoss; using MarketDataServer.Authorization; using MarketData.Cache; using MarketData.Generator; using MarketData; using LogLevel = MarketData.LogLevel; using Microsoft.AspNetCore.Mvc; namespace MarketDataServer.Controllers { /// /// GainLossController : /// GetGainLossByDate(String token,DateTime selectedDate) /// GetGainLossByDateAndAccount(String token,DateTime selectedDate,String account) /// GetGainLossWithDetailByDate(String token,DateTime selectedDate) /// GetGainLossWithDetailByDateAndAccount(String token, DateTime selectedDate, String account) /// GetCompoundGainLoss(String token, int selectedDays, bool includeDividends) /// [ApiController] [Route("api/[controller]/[action]")] public class GainLossController : ControllerBase { private ActiveGainLossGenerator gainLossGenerator=new ActiveGainLossGenerator(); [HttpGet] public IEnumerable GetGainLossByDate(String token,DateTime selectedDate) { Profiler profiler = new Profiler(); try { MDTrace.WriteLine(LogLevel.DEBUG,$"Start"); if (!Authorizations.GetInstance().IsAuthorized(token)) return null; GLPriceCache.GetInstance().Refresh(); PortfolioTrades portfolioTrades = PortfolioDA.GetTrades(); PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate); GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate); // **** Add an aggregate entry GainLossSummaryItem gainLossSummaryTotals=new GainLossSummaryItem(); gainLossSummaryTotals.Symbol=""; gainLossSummaryTotals.CompanyName="Account Summary"; if(null!=gainLossSummaryItems&&gainLossSummaryItems.Count>0) { gainLossSummaryTotals.Date=gainLossSummaryItems.Min(x => x.Date); gainLossSummaryTotals.Change=gainLossSummaryItems.Sum(x=>x.Change); gainLossSummaryTotals.CurrentGainLoss=gainLossSummaryItems.Sum(x => x.CurrentGainLoss); gainLossSummaryTotals.PreviousGainLoss = gainLossSummaryItems.Sum(x => x.PreviousGainLoss); gainLossSummaryTotals.ChangePercent=((gainLossSummaryTotals.CurrentGainLoss-gainLossSummaryTotals.PreviousGainLoss)/Math.Abs(gainLossSummaryTotals.PreviousGainLoss))*100.00; } else { gainLossSummaryTotals.Date = selectedDate; gainLossSummaryTotals.Change = 0.00; gainLossSummaryTotals.CurrentGainLoss = 0.00; gainLossSummaryTotals.PreviousGainLoss = 0.00; gainLossSummaryTotals.ChangePercent = 0.00; } gainLossSummaryItems.Insert(0,gainLossSummaryTotals); // **** return gainLossSummaryItems; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}"); return null; } finally { MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)"); } } [HttpGet] public IEnumerable GetGainLossByDateAndAccount(String token,DateTime selectedDate,String account) { Profiler profiler = new Profiler(); try { MDTrace.WriteLine(LogLevel.DEBUG,$"Start"); GLPriceCache.GetInstance().Refresh(); if (!Authorizations.GetInstance().IsAuthorized(token)) return null; PortfolioTrades portfolioTrades = PortfolioDA.GetTrades(); portfolioTrades=new PortfolioTrades(portfolioTrades.Where(x=>x.Account.Equals(account)).ToList()); PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate); GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate); // **** Add an aggregate entry GainLossSummaryItem gainLossSummaryTotals = new GainLossSummaryItem(); gainLossSummaryTotals.Symbol = ""; gainLossSummaryTotals.CompanyName="Account Summary"; if (null != gainLossSummaryItems && gainLossSummaryItems.Count > 0) { gainLossSummaryTotals.Date = gainLossSummaryItems.Min(x => x.Date); gainLossSummaryTotals.Change = gainLossSummaryItems.Sum(x => x.Change); gainLossSummaryTotals.CurrentGainLoss = gainLossSummaryItems.Sum(x => x.CurrentGainLoss); gainLossSummaryTotals.PreviousGainLoss = gainLossSummaryItems.Sum(x => x.PreviousGainLoss); gainLossSummaryTotals.ChangePercent = ((gainLossSummaryTotals.CurrentGainLoss - gainLossSummaryTotals.PreviousGainLoss) / Math.Abs(gainLossSummaryTotals.PreviousGainLoss)) * 100.00; } else { gainLossSummaryTotals.Date = selectedDate; gainLossSummaryTotals.Change = 0.00; gainLossSummaryTotals.CurrentGainLoss = 0.00; gainLossSummaryTotals.PreviousGainLoss = 0.00; gainLossSummaryTotals.ChangePercent = 0.00; } gainLossSummaryItems.Insert(0, gainLossSummaryTotals); // **** return gainLossSummaryItems; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}"); return null; } finally { MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)"); } } /// /// GetGainLossWithDetailByDate - Optimizing calls to DA methods /// /// /// /// [HttpGet] public IEnumerable GetGainLossWithDetailByDate(String token,DateTime selectedDate) { Profiler profiler = new Profiler(); try { MDTrace.WriteLine(LogLevel.DEBUG,$"Start"); if (!Authorizations.GetInstance().IsAuthorized(token)) return null; GLPriceCache.GetInstance().Refresh(); PortfolioTrades portfolioTrades = PortfolioDA.GetTrades(); PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate); GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate); List symbols = gainLossSummaryItems.Select(x => x.Symbol).ToList(); Dictionary latestDates = PricingDA.GetLatestDates(symbols); List gainLossSummaryItemDetailCollection = new List(); foreach (GainLossSummaryItem gainLossSummaryItem in gainLossSummaryItems) { GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem); portfolioTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol); double weightAdjustedDividendYield = portfolioTrades.GetWeightAdjustedDividendYield(); DateTime currentDate = latestDates[gainLossSummaryItem.Symbol]; if (null == portfolioTrades || 0 == portfolioTrades.Count) continue; double shares = (from PortfolioTrade portfolioTrade in portfolioTrades select portfolioTrade.Shares).Sum(); double exposure = portfolioTrades.Sum(x => x.Exposure()); if(null==gainLossGenerator) gainLossGenerator=new ActiveGainLossGenerator(); GainLossCollection gainLoss=gainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions GainLossItem gainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault(); gainLossSummaryItemDetail.Lots = portfolioTrades.Count; gainLossSummaryItemDetail.Shares = shares; gainLossSummaryItemDetail.Exposure = exposure; if (!double.IsNaN(weightAdjustedDividendYield)) { gainLossSummaryItemDetail.DividendYield = weightAdjustedDividendYield; gainLossSummaryItemDetail.AnnualDividend = exposure * weightAdjustedDividendYield; } Prices prices = GLPriceCache.GetInstance().GetPrices(gainLossSummaryItem.Symbol, currentDate, 3); // cache should be refreshed after GainLossSummaryItemCollection Price p1 = prices.Count>0?prices[0]:default; Price p2 = prices.Count>1?prices[1]:default; PortfolioTrades symbolTrades = new PortfolioTrades(portfolioTrades.Where(x=>x.Symbol.Equals(gainLossSummaryItem.Symbol)).ToList()); ParityElement parityElement = ParityGenerator.GenerateBreakEven(symbolTrades, p1); gainLossSummaryItemDetail.ParityElement = parityElement; if (null != parityElement) { gainLossSummaryItemDetail.AllTimeGainLossPercent = gainLossItem.GainLossPercent; gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent = parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100); } if (null != p1 && null != p2) { double change = (p1.Close - p2.Close) / p2.Close; gainLossSummaryItemDetail.LatestPrice = p1; gainLossSummaryItemDetail.PriceChange = change; } gainLossSummaryItemDetailCollection.Add(gainLossSummaryItemDetail); } // **** Add an aggregate entry GainLossSummaryItemDetail gainLossSummaryTotals = new GainLossSummaryItemDetail(); gainLossSummaryTotals.Symbol = ""; gainLossSummaryTotals.CompanyName = "Account Summary"; if (null != gainLossSummaryItemDetailCollection && gainLossSummaryItemDetailCollection.Count > 0) { gainLossSummaryTotals.Date = gainLossSummaryItemDetailCollection.Min(x => x.Date); gainLossSummaryTotals.Exposure = gainLossSummaryItemDetailCollection.Sum(x => x.Exposure); gainLossSummaryTotals.Change = gainLossSummaryItemDetailCollection.Sum(x => x.Change); gainLossSummaryTotals.CurrentGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.CurrentGainLoss); gainLossSummaryTotals.PreviousGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.PreviousGainLoss); gainLossSummaryTotals.ChangePercent = ((gainLossSummaryTotals.CurrentGainLoss - gainLossSummaryTotals.PreviousGainLoss) / Math.Abs(gainLossSummaryTotals.PreviousGainLoss)) * 100.00; gainLossSummaryTotals.LatestPrice = new Price(); gainLossSummaryTotals.PriceChange = 0; } else { gainLossSummaryTotals.Date = selectedDate; gainLossSummaryTotals.Change = 0.00; gainLossSummaryTotals.CurrentGainLoss = 0.00; gainLossSummaryTotals.PreviousGainLoss = 0.00; gainLossSummaryTotals.ChangePercent = 0.00; gainLossSummaryTotals.LatestPrice = new Price(); gainLossSummaryTotals.PriceChange = 0; } gainLossSummaryItemDetailCollection.Insert(0, gainLossSummaryTotals); // **** return gainLossSummaryItemDetailCollection; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}"); return null; } finally { MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)"); } } [HttpGet] public IEnumerable GetGainLossWithDetailByDateAndAccount(String token, DateTime selectedDate, String account) { Profiler profiler = new Profiler(); try { MDTrace.WriteLine(LogLevel.DEBUG,$"Start"); if (!Authorizations.GetInstance().IsAuthorized(token)) return null; GLPriceCache.GetInstance().Refresh(); PortfolioTrades portfolioTrades = PortfolioDA.GetTrades(); portfolioTrades = new PortfolioTrades(portfolioTrades.Where(x => x.Account.Equals(account)).ToList()); PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate); GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate); List symbols = gainLossSummaryItems.Select(x => x.Symbol).ToList(); Dictionary latestDates = PricingDA.GetLatestDates(symbols); List gainLossSummaryItemDetailCollection=new List(); foreach(GainLossSummaryItem gainLossSummaryItem in gainLossSummaryItems) { GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem); portfolioTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol); double weightAdjustedDividendYield = portfolioTrades.GetWeightAdjustedDividendYield(); DateTime currentDate = latestDates[gainLossSummaryItem.Symbol]; if(null==portfolioTrades||0==portfolioTrades.Count)continue; double shares = (from PortfolioTrade portfolioTrade in portfolioTrades select portfolioTrade.Shares).Sum(); double exposure = portfolioTrades.Sum(x => x.Exposure()); if(null==gainLossGenerator) gainLossGenerator=new ActiveGainLossGenerator(); GainLossCollection gainLoss = gainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions GainLossItem gainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault(); gainLossSummaryItemDetail.Lots=portfolioTrades.Count; gainLossSummaryItemDetail.Shares=shares; gainLossSummaryItemDetail.Exposure=exposure; if (!double.IsNaN(weightAdjustedDividendYield)) { gainLossSummaryItemDetail.DividendYield=weightAdjustedDividendYield; gainLossSummaryItemDetail.AnnualDividend=exposure * weightAdjustedDividendYield; } Prices prices = GLPriceCache.GetInstance().GetPrices(gainLossSummaryItem.Symbol, currentDate, 3); // cache should be refreshed after GainLossSummaryItemCollection Price p1 = prices.Count>0?prices[0]:default; Price p2 = prices.Count>1?prices[1]:default; PortfolioTrades symbolTrades = new PortfolioTrades(portfolioTrades.Where(x=>x.Symbol.Equals(gainLossSummaryItem.Symbol)).ToList()); ParityElement parityElement = ParityGenerator.GenerateBreakEven(symbolTrades, p1); gainLossSummaryItemDetail.ParityElement=parityElement; if (null != parityElement) { gainLossSummaryItemDetail.AllTimeGainLossPercent=gainLossItem.GainLossPercent; gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent=parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100); } if(null!=p1 && null!=p2) { double change = (p1.Close - p2.Close) / p2.Close; gainLossSummaryItemDetail.LatestPrice=p1; gainLossSummaryItemDetail.PriceChange=change; } gainLossSummaryItemDetailCollection.Add(gainLossSummaryItemDetail); } // **** Add an aggregate entry GainLossSummaryItemDetail gainLossSummaryTotals = new GainLossSummaryItemDetail(); gainLossSummaryTotals.Symbol = ""; gainLossSummaryTotals.CompanyName = "Account Summary"; if (null != gainLossSummaryItemDetailCollection && gainLossSummaryItemDetailCollection.Count > 0) { gainLossSummaryTotals.Date = gainLossSummaryItemDetailCollection.Min(x => x.Date); gainLossSummaryTotals.Exposure=gainLossSummaryItemDetailCollection.Sum(x=>x.Exposure); gainLossSummaryTotals.Change = gainLossSummaryItemDetailCollection.Sum(x => x.Change); gainLossSummaryTotals.CurrentGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.CurrentGainLoss); gainLossSummaryTotals.PreviousGainLoss = gainLossSummaryItemDetailCollection.Sum(x => x.PreviousGainLoss); gainLossSummaryTotals.ChangePercent = ((gainLossSummaryTotals.CurrentGainLoss - gainLossSummaryTotals.PreviousGainLoss) / Math.Abs(gainLossSummaryTotals.PreviousGainLoss)) * 100.00; gainLossSummaryTotals.LatestPrice=new Price(); gainLossSummaryTotals.PriceChange=0; } else { gainLossSummaryTotals.Date = selectedDate; gainLossSummaryTotals.Change = 0.00; gainLossSummaryTotals.CurrentGainLoss = 0.00; gainLossSummaryTotals.PreviousGainLoss = 0.00; gainLossSummaryTotals.ChangePercent = 0.00; gainLossSummaryTotals.LatestPrice = new Price(); gainLossSummaryTotals.PriceChange = 0; } gainLossSummaryItemDetailCollection.Insert(0, gainLossSummaryTotals); // **** return gainLossSummaryItemDetailCollection; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}"); return null; } finally { MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)"); } } [HttpGet(Name = "GetCompoundGainLoss")] public GainLossCompoundModelCollection GetCompoundGainLoss(String token, int selectedDays, bool includeDividends) { Profiler profiler = new Profiler(); try { MDTrace.WriteLine(LogLevel.DEBUG,$"Start"); if(!Authorizations.GetInstance().IsAuthorized(token)) return null; GLPriceCache.GetInstance().Refresh(); DividendPayments dividendPayments = null; PortfolioTrades portfolioTrades = PortfolioDA.GetTrades(); GainLossGenerator gainLossGenerator=new GainLossGenerator(); if(includeDividends)dividendPayments=DividendPaymentDA.GetDividendPayments(); ActiveGainLossGenerator activeGainLossGenerator=new ActiveGainLossGenerator(); GainLossCollection gainLoss=activeGainLossGenerator.GenerateGainLoss(portfolioTrades); // gainLoss contains the gain/loss from active positions. Never includes dividends .. just positions TotalGainLossCollection totalGainLoss=null; if(null!=dividendPayments)totalGainLoss=gainLossGenerator.GenerateTotalGainLossWithDividends(portfolioTrades,dividendPayments); else totalGainLoss=gainLossGenerator.GenerateTotalGainLoss(portfolioTrades); GainLossCompoundModelCollection gainLossModelCollection=null; gainLossModelCollection=new GainLossCompoundModelCollection(gainLoss,totalGainLoss); if(-1==selectedDays)return gainLossModelCollection; int skip=gainLossModelCollection.Count-selectedDays; if(skip<0)return gainLossModelCollection; return new GainLossCompoundModelCollection(gainLossModelCollection.Skip(skip).ToList()); } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,$"Exception:{exception.ToString()}"); return null; } finally { MDTrace.WriteLine(LogLevel.DEBUG,$"Done, total took {profiler.End()} (ms)"); } } } }