From c38923bf87501597a31f418ac0829ab863d7f00a Mon Sep 17 00:00:00 2001 From: Gavin Brennan Date: Fri, 5 Jul 2024 09:32:30 +0100 Subject: [PATCH] Basic activity pnl in attribution for MC --- .../Models/AttributionSteps/ActivityStep.cs | 101 ++++++++++++++++++ src/Qwack.Models/Models/PnLAttribution.cs | 8 +- version.props | 2 +- version.txt | 2 +- 4 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 src/Qwack.Models/Models/AttributionSteps/ActivityStep.cs diff --git a/src/Qwack.Models/Models/AttributionSteps/ActivityStep.cs b/src/Qwack.Models/Models/AttributionSteps/ActivityStep.cs new file mode 100644 index 00000000..b3bf6dfb --- /dev/null +++ b/src/Qwack.Models/Models/AttributionSteps/ActivityStep.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Linq; +using Qwack.Core.Basic; +using Qwack.Core.Cubes; +using Qwack.Core.Instruments; +using Qwack.Core.Models; +using static Qwack.Core.Basic.Consts.Cubes; + +namespace Qwack.Models.Models.AttributionSteps; + +public class ActivityStep(Portfolio startPortfolio, Portfolio endPortfolio) : IPnLAttributionStep +{ + public (ICube endOfStepPvCube, IPvModel model) Attribute(IPvModel model, IPvModel endModel, ResultCube resultsCube, ICube lastPvCube, + ICube riskCube, Currency reportingCcy) + { + var (newTrades, removedTrades, ammendedTradesStart, ammendedTradesEnd) = startPortfolio.ActivityBooks(endPortfolio, endModel.VanillaModel.BuildDate); + + var pfEndDict = endPortfolio.Instruments.ToDictionary(x => x.TradeId, x => x.PortfolioName); + var pfStartDict = startPortfolio.Instruments.ToDictionary(x => x.TradeId, x => x.PortfolioName); + + if (newTrades.Instruments.Count > 0) + { + model = model.Rebuild(model.VanillaModel, newTrades); + var newTradesPnL = model.PV(reportingCcy); + var tidIx = newTradesPnL.GetColumnIndex(TradeId); + var tTypeIx = newTradesPnL.GetColumnIndex(TradeType); + foreach (var t in newTradesPnL.GetAllRows()) + { + var tid = (string)t.MetaData[tidIx]; + var row = new Dictionary + { + { TradeId, tid}, + { TradeType, t.MetaData[tTypeIx] }, + { Step, "Activity" }, + { SubStep, "New" }, + { SubSubStep, string.Empty }, + { PointLabel, string.Empty }, + { "Portfolio", pfEndDict[tid]} + }; + resultsCube.AddRow(row, t.Value); + } + } + + if (removedTrades.Instruments.Count > 0) + { + model = model.Rebuild(model.VanillaModel, removedTrades); + var removedTradesPnL = model.PV(reportingCcy); + + var tidIx = removedTradesPnL.GetColumnIndex(TradeId); + var tTypeIx = removedTradesPnL.GetColumnIndex(TradeType); + + foreach (var t in removedTradesPnL.GetAllRows()) + { + var tid = (string)t.MetaData[tidIx]; + var row = new Dictionary + { + { TradeId, tid }, + { TradeType, t.MetaData[tTypeIx] }, + { Step, "Activity" }, + { SubStep, "Removed" }, + { SubSubStep, string.Empty }, + { PointLabel, string.Empty }, + { "Portfolio", pfStartDict[tid]} + }; + resultsCube.AddRow(row, -t.Value); + } + } + + if (ammendedTradesStart.Instruments.Count > 0) + { + model = model.Rebuild(model.VanillaModel, ammendedTradesStart); + var amendedTradesPnLStart = model.PV(reportingCcy); + model = model.Rebuild(model.VanillaModel, ammendedTradesEnd); + var amendedTradesPnLEnd = model.PV(reportingCcy); + var amendedPnL = amendedTradesPnLEnd.QuickDifference(amendedTradesPnLStart); + + var tidIx = amendedTradesPnLStart.GetColumnIndex(TradeId); + var tTypeIx = amendedTradesPnLStart.GetColumnIndex(TradeType); + + foreach (var t in amendedPnL.GetAllRows()) + { + var tid = (string)t.MetaData[tidIx]; + var row = new Dictionary + { + { TradeId, tid }, + { TradeType, t.MetaData[tTypeIx] }, + { Step, "Activity" }, + { SubStep, "Ammended" }, + { SubSubStep, string.Empty }, + { PointLabel, string.Empty }, + { "Portfolio", pfStartDict[tid]} + }; + resultsCube.AddRow(row, t.Value); + } + } + + model = model.Rebuild(model.VanillaModel, endPortfolio); + + return (lastPvCube, model); + } +} diff --git a/src/Qwack.Models/Models/PnLAttribution.cs b/src/Qwack.Models/Models/PnLAttribution.cs index 02c30c7c..b1799d38 100644 --- a/src/Qwack.Models/Models/PnLAttribution.cs +++ b/src/Qwack.Models/Models/PnLAttribution.cs @@ -1500,7 +1500,7 @@ private static ICube EnrichWithPortfolio(this ICube results, Portfolio pfolio) return o; } - public static ICube ExplainAttribution(this Portfolio portfolio, AssetFxMCModel startModel, AssetFxMCModel endModel, Currency reportingCcy, ICube startingGreeks, ICurrencyProvider currencyProvider, IFutureSettingsProvider futureSettings, ICalendarProvider calendarProvider, bool useSpreadDelta = false) + public static ICube ExplainAttribution(this Portfolio startPortfolio, Portfolio endPortfolio, AssetFxMCModel startModel, AssetFxMCModel endModel, Currency reportingCcy, ICube startingGreeks, ICurrencyProvider currencyProvider, IFutureSettingsProvider futureSettings, ICalendarProvider calendarProvider, bool useSpreadDelta = false) { var cube = new ResultCube(); var dataTypes = new Dictionary @@ -1543,10 +1543,14 @@ public static ICube ExplainAttribution(this Portfolio portfolio, AssetFxMCModel (lastPvCube, model) = new FxVolsStep().Attribute(model, endModel, cube, lastPvCube, startingGreeks, reportingCcy); - //finally unexplained step + //unexplained step (lastPvCube, model) = new FinalStep().Attribute(model, endModel, cube, lastPvCube, startingGreeks, reportingCcy); + //activity step + (lastPvCube, model) = + new ActivityStep(startPortfolio, endPortfolio).Attribute(model, endModel, cube, lastPvCube, startingGreeks, reportingCcy); + return cube; } diff --git a/version.props b/version.props index c472511a..2cd1c1b4 100644 --- a/version.props +++ b/version.props @@ -1,5 +1,5 @@ - 0.8.51 + 0.8.52 diff --git a/version.txt b/version.txt index bfbbd4ee..a76f8006 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.8.51 \ No newline at end of file +0.8.52 \ No newline at end of file