From eff2a7a953339beafefe1c3b8c83006694ad9239 Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 29 Apr 2025 23:13:41 -0400 Subject: [PATCH] Optimize GainLossController --- MarketData/MarketData/.vscode/launch.json | 12 +- .../Generator/ParityGenerator.cs | 31 +++++ .../GainLoss/GainLossSummaryItemCollection.cs | 2 - .../Controllers/GainLossController.cs | 121 +++++++++++++++++- 4 files changed, 149 insertions(+), 17 deletions(-) diff --git a/MarketData/MarketData/.vscode/launch.json b/MarketData/MarketData/.vscode/launch.json index a916fde..bb72ac6 100644 --- a/MarketData/MarketData/.vscode/launch.json +++ b/MarketData/MarketData/.vscode/launch.json @@ -5,20 +5,14 @@ "version": "0.2.0", "configurations": [ { - "name": ".NET Core Launch (console)", + "name": ".NET Core Launch (mk)", "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceFolder}/bin/Debug/net8.0/MarketData.dll", + "program": "${workspaceFolder}/bin/Debug/net8.0/mk.dll", "args": [], - "cwd": "${workspaceFolder}", "console": "internalConsole", "stopAtEntry": false - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach" } ] -} \ No newline at end of file +} diff --git a/MarketData/MarketDataLib/Generator/ParityGenerator.cs b/MarketData/MarketDataLib/Generator/ParityGenerator.cs index 86c2ca4..f511eea 100755 --- a/MarketData/MarketDataLib/Generator/ParityGenerator.cs +++ b/MarketData/MarketDataLib/Generator/ParityGenerator.cs @@ -17,6 +17,37 @@ namespace MarketData.Generator private ParityGenerator() { } + + /// + /// Given PortfolioTrades for a symbol and corresponding latestPrice gives us the breakeven element. + /// This call avoid calling the database. Used by GetGainLossWithDetailByDate in the GainLossController + /// + /// + /// + /// + public static ParityElement GenerateBreakEven(PortfolioTrades symbolTrades,Price latestPrice) + { + try + { + ParityElement parityElement=new ParityElement(); + Price zeroPrice=null; + if(null==symbolTrades||0==symbolTrades.Count)return null; + PortfolioTrades openTrades=symbolTrades.GetOpenTrades(); + GainLossGenerator gainLossGenerator=new GainLossGenerator(); + zeroPrice=ParityGenerator.GenerateGainLossValue(openTrades,latestPrice); + parityElement.ParityOffsetPrice=zeroPrice.Close; + parityElement.ParityOffsetPercent=((latestPrice.Close-zeroPrice.Close)/zeroPrice.Close); + parityElement.Symbol=latestPrice.Symbol; + parityElement.PricingDate=latestPrice.Date; + return parityElement; + } + catch(Exception exception) + { + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0}",exception)); + return null; + } + } + public static ParityElement GenerateBreakEven(String symbol) { try diff --git a/MarketData/MarketDataLib/MarketDataModel/GainLoss/GainLossSummaryItemCollection.cs b/MarketData/MarketDataLib/MarketDataModel/GainLoss/GainLossSummaryItemCollection.cs index 2e2440c..5bcb4e5 100755 --- a/MarketData/MarketDataLib/MarketDataModel/GainLoss/GainLossSummaryItemCollection.cs +++ b/MarketData/MarketDataLib/MarketDataModel/GainLoss/GainLossSummaryItemCollection.cs @@ -114,7 +114,6 @@ namespace MarketData.MarketDataModel.GainLoss GainLossSummaryItem gainLossSummaryItem=new GainLossSummaryItem(); gainLossSummaryItem.Date=gainLossCompoundModelCollection[gainLossCompoundModelCollection.Count-1].Date; gainLossSummaryItem.Symbol=symbol; -// gainLossSummaryItem.CompanyName=PricingDA.GetNameForSymbol(symbol); gainLossSummaryItem.CompanyName=namesDictionary.ContainsKey(symbol)?namesDictionary[symbol]:""; gainLossSummaryItem.CurrentGainLoss=gainLossCompoundModelCollection[gainLossCompoundModelCollection.Count-1].ActiveGainLoss; double previousGainLoss=1==gainLossCompoundModelCollection.Count?0.00:gainLossCompoundModelCollection[gainLossCompoundModelCollection.Count-2].ActiveGainLoss; @@ -150,7 +149,6 @@ namespace MarketData.MarketDataModel.GainLoss if(!portfolioTrades.HasOpenPositions(symbol)) continue; } gainLossSummaryItem.HasStopLimit = stopLimits.ContainsKey(symbol); -// gainLossSummaryItem.HasStopLimit=PortfolioDA.HasStopLimit(symbol); Add(gainLossSummaryItem); } GainLossSummaryItemCollection gainLossSummaryCollection=new GainLossSummaryItemCollection((from GainLossSummaryItem gainLossSummaryItem in this orderby gainLossSummaryItem.Date descending,gainLossSummaryItem.Change descending,gainLossSummaryItem.Symbol descending select gainLossSummaryItem).ToList()); diff --git a/MarketDataServer/Controllers/GainLossController.cs b/MarketDataServer/Controllers/GainLossController.cs index 90a9291..fbf3419 100755 --- a/MarketDataServer/Controllers/GainLossController.cs +++ b/MarketDataServer/Controllers/GainLossController.cs @@ -115,6 +115,12 @@ namespace MarketDataServer.Controllers } } + /// + /// GetGainLossWithDetailByDate - Optimizing calls to DA methods + /// + /// + /// + /// [HttpGet] public IEnumerable GetGainLossWithDetailByDate(String token,DateTime selectedDate) { @@ -127,6 +133,8 @@ namespace MarketDataServer.Controllers 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) @@ -134,7 +142,7 @@ namespace MarketDataServer.Controllers GainLossSummaryItemDetail gainLossSummaryItemDetail = new GainLossSummaryItemDetail(gainLossSummaryItem); portfolioTrades = PortfolioDA.GetOpenTradesSymbol(gainLossSummaryItem.Symbol); double weightAdjustedDividendYield = portfolioTrades.GetWeightAdjustedDividendYield(); - DateTime currentDate = PricingDA.GetLatestDate(gainLossSummaryItem.Symbol); + 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()); @@ -149,17 +157,19 @@ namespace MarketDataServer.Controllers gainLossSummaryItemDetail.DividendYield = weightAdjustedDividendYield; gainLossSummaryItemDetail.AnnualDividend = exposure * weightAdjustedDividendYield; } - ParityElement parityElement = ParityGenerator.GenerateBreakEven(gainLossSummaryItem.Symbol); + DateGenerator dateGenerator = new DateGenerator(); + DateTime priorDate = dateGenerator.FindPrevBusinessDay(currentDate); + Price p1 = PricingDA.GetPrice(gainLossSummaryItem.Symbol, currentDate); + Price p2 = PricingDA.GetPrice(gainLossSummaryItem.Symbol, priorDate); + + 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); } - DateGenerator dateGenerator = new DateGenerator(); - DateTime priorDate = dateGenerator.FindPrevBusinessDay(currentDate); - Price p1 = PricingDA.GetPrice(gainLossSummaryItem.Symbol, currentDate); - Price p2 = PricingDA.GetPrice(gainLossSummaryItem.Symbol, priorDate); if (null == p2 && null != p1) { priorDate = dateGenerator.FindPrevBusinessDay(priorDate); @@ -214,6 +224,105 @@ namespace MarketDataServer.Controllers } } + // [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; + // LocalPriceCache.GetInstance().Refresh(); + // PortfolioTrades portfolioTrades = PortfolioDA.GetTrades(); + // PortfolioTrades tradesOnOrBefore = portfolioTrades.GetTradesOnOrBefore(selectedDate); + // GainLossSummaryItemCollection gainLossSummaryItems = new GainLossSummaryItemCollection(tradesOnOrBefore, selectedDate); + + // 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 = PricingDA.GetLatestDate(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; + // } + // ParityElement parityElement = ParityGenerator.GenerateBreakEven(gainLossSummaryItem.Symbol); + // gainLossSummaryItemDetail.ParityElement = parityElement; + // if (null != parityElement) + // { + // gainLossSummaryItemDetail.AllTimeGainLossPercent = gainLossItem.GainLossPercent; + // gainLossSummaryItemDetail.PercentDistanceFromAllTimeGainLossPercent = parityElement.ParityOffsetPercent - (gainLossItem.GainLossPercent / 100); + // } + // DateGenerator dateGenerator = new DateGenerator(); + // DateTime priorDate = dateGenerator.FindPrevBusinessDay(currentDate); + // Price p1 = PricingDA.GetPrice(gainLossSummaryItem.Symbol, currentDate); + // Price p2 = PricingDA.GetPrice(gainLossSummaryItem.Symbol, priorDate); + // if (null == p2 && null != p1) + // { + // priorDate = dateGenerator.FindPrevBusinessDay(priorDate); + // p2 = PricingDA.GetPrice(gainLossSummaryItem.Symbol, priorDate); + // } + // 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) {