Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
pnlexplainreport.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2024 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
22
23namespace ore {
24namespace analytics {
25
26void populateResults(QuantLib::ext::shared_ptr<MarketRiskGroup> mrg, PnlExplainReport::PnlExplainResults& result,
27 QuantLib::Real deltaPnl, QuantLib::Real gammaPnl, QuantLib::Real pnl) {
28 if (mrg->riskClass() == MarketRiskConfiguration::RiskClass::All) {
29 if (mrg->riskType() == MarketRiskConfiguration::RiskType::DeltaGamma) {
30 result.delta = deltaPnl;
31 result.gamma = gammaPnl;
32 } else if (mrg->riskType() == MarketRiskConfiguration::RiskType::Vega)
33 result.vega = pnl;
34 else if (mrg->riskType() == MarketRiskConfiguration::RiskType::All)
35 result.pnl = pnl;
36 }
37 if (mrg->riskClass() == MarketRiskConfiguration::RiskClass::InterestRate) {
38 if (mrg->riskType() == MarketRiskConfiguration::RiskType::DeltaGamma) {
39 result.irDelta = deltaPnl;
40 result.irGamma = gammaPnl;
41 } else if (mrg->riskType() == MarketRiskConfiguration::RiskType::Vega)
42 result.irVega = pnl;
43 }
44 if (mrg->riskClass() == MarketRiskConfiguration::RiskClass::Equity) {
45 if (mrg->riskType() == MarketRiskConfiguration::RiskType::DeltaGamma) {
46 result.eqDelta = deltaPnl;
47 result.eqGamma = gammaPnl;
48 } else if (mrg->riskType() == MarketRiskConfiguration::RiskType::Vega)
49 result.eqVega = pnl;
50 }
51 if (mrg->riskClass() == MarketRiskConfiguration::RiskClass::FX) {
52 if (mrg->riskType() == MarketRiskConfiguration::RiskType::DeltaGamma) {
53 result.fxDelta = deltaPnl;
54 result.fxGamma = gammaPnl;
55 } else if (mrg->riskType() == MarketRiskConfiguration::RiskType::Vega)
56 result.fxVega = pnl;
57 }
58 if (mrg->riskClass() == MarketRiskConfiguration::RiskClass::Inflation) {
59 if (mrg->riskType() == MarketRiskConfiguration::RiskType::DeltaGamma) {
60 result.infDelta = deltaPnl;
61 result.infGamma = gammaPnl;
62 } else if (mrg->riskType() == MarketRiskConfiguration::RiskType::Vega)
63 result.infVega = pnl;
64 }
65 if (mrg->riskClass() == MarketRiskConfiguration::RiskClass::Credit) {
66 if (mrg->riskType() == MarketRiskConfiguration::RiskType::DeltaGamma) {
67 result.creditDelta = deltaPnl;
68 result.creditGamma = gammaPnl;
69 } else if (mrg->riskType() == MarketRiskConfiguration::RiskType::Vega)
70 result.creditVega = pnl;
71 }
72 if (mrg->riskClass() == MarketRiskConfiguration::RiskClass::Commodity) {
73 if (mrg->riskType() == MarketRiskConfiguration::RiskType::DeltaGamma) {
74 result.comDelta = deltaPnl;
75 result.comGamma = gammaPnl;
76 } else if (mrg->riskType() == MarketRiskConfiguration::RiskType::Vega)
77 result.comVega = pnl;
78 }
79}
80
81void PnlExplainReport::createReports(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports) {
82 QL_REQUIRE(reports->reports().size() == 1, "We should only report for PNL Explain");
83 QL_REQUIRE(reports->reports().size() == 1, "We should only report for PNL Explain");
84 QuantLib::ext::shared_ptr<InMemoryReport> report =
85 QuantLib::ext::dynamic_pointer_cast<ore::data::InMemoryReport>(reports->reports().at(0));
86 QL_REQUIRE(report, "PNL report must be an InMemoryReport");
87
88 pnlReportColumnSize_ = report->columns();
89
90 report->addColumn("ScenarioPnl", double(), 6)
91 .addColumn("TotalDelta", double(), 6)
92 .addColumn("TotalGamma", double(), 6)
93 .addColumn("TotalVega", double(), 6)
94 .addColumn("IrDelta", double(), 6)
95 .addColumn("IrGamma", double(), 6)
96 .addColumn("IrVega", double(), 6)
97 .addColumn("EqDelta", double(), 6)
98 .addColumn("EqGamma", double(), 6)
99 .addColumn("EqVega", double(), 6)
100 .addColumn("FxDelta", double(), 6)
101 .addColumn("FxGamma", double(), 6)
102 .addColumn("FxVega", double(), 6)
103 .addColumn("InfDelta", double(), 6)
104 .addColumn("InfGamma", double(), 6)
105 .addColumn("InfVega", double(), 6)
106 .addColumn("CreditDelta", double(), 6)
107 .addColumn("CreditGamma", double(), 6)
108 .addColumn("CreditVega", double(), 6)
109 .addColumn("CommDelta", double(), 6)
110 .addColumn("CommGamma", double(), 6)
111 .addColumn("CommVega", double(), 6)
112 ;
113}
114
115void PnlExplainReport::handleSensiResults(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& report,
116 const QuantLib::ext::shared_ptr<MarketRiskGroupBase>& riskGroup,
117 const QuantLib::ext::shared_ptr<TradeGroupBase>& tradeGroup) {
118}
119
120void PnlExplainReport::addPnlCalculators(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports) {
121 pnlCalculators_.push_back(QuantLib::ext::make_shared<PNLCalculator>(period_.get()));
122}
123
124void PnlExplainReport::writeReports(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports,
125 const QuantLib::ext::shared_ptr<MarketRiskGroupBase>& riskGroup,
126 const QuantLib::ext::shared_ptr<TradeGroupBase>& tradeGroup) {
127
128 std::vector<QuantLib::Real> sensiPnls = pnlCalculators_[0]->pnls();
129 std::vector<QuantLib::Real> foSensiPnls = pnlCalculators_[0]->foPnls();
130 TradePnLStore tradeSensiPnls = pnlCalculators_[0]->tradePnls();
131 TradePnLStore foTradeSensiPnls = pnlCalculators_[0]->foTradePnls();
132
133 QL_REQUIRE(sensiPnls.size() == 1, "PNLExplainReport::writeReports - should have exactly 1 sensi pnl");
134 QL_REQUIRE(foSensiPnls.size() == 1, "PNLExplainReport::writeReports - should have exactly 1 fo sensi pnl");
135 Real pnl = sensiPnls[0];
136 Real deltaPnl = foSensiPnls[0];
137 Real gammaPnl = pnl - deltaPnl;
138
139 auto pId = portfolioId(tradeGroup);
140 auto it = results_.find(pId);
141 if (it == results_.end())
143
144 auto mrg = ext::dynamic_pointer_cast<MarketRiskGroup>(riskGroup);
145 QL_REQUIRE(mrg, "Require a group of type MarketRiskGroup");
146
147 populateResults(mrg, results_[pId], deltaPnl, gammaPnl, pnl);
148
149 if (runTradeDetail(reports)) {
150 QL_REQUIRE(tradeSensiPnls.size() == 1,
151 "PNLExplainReport::writeReports - should have exactly 1 sensi pnl for each trade");
152 QL_REQUIRE(foTradeSensiPnls.size() == 1,
153 "PNLExplainReport::writeReports - should have exactly 1 fo sensi pnl for each trade");
154 QL_REQUIRE(tradeSensiPnls[0].size() == tradeIds_.size(),
155 "PNLExplainReport::writeReports - tradeSensiPNLs do not match portfolio size");
156 QL_REQUIRE(foTradeSensiPnls[0].size() == tradeIds_.size(),
157 "PNLExplainReport::writeReports - foTradeSensiPNLs do not match portfolio size");
158
159 for (QuantLib::Size i = 0; i < tradeIds_.size(); i++) {
160 auto tId = tradeIds_.at(i);
161 Real tpnl = tradeSensiPnls[0].at(i);
162 Real tdeltaPnl = foTradeSensiPnls[0].at(i);
163 Real tgammaPnl = tpnl - tdeltaPnl;
164 auto itt = results_.find(tId);
165 if (itt == results_.end())
167
168 populateResults(mrg, results_[tId], tdeltaPnl, tgammaPnl, tpnl);
169 }
170 }
171}
172
174 const QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup) const {
175 return true;
176}
178 const QuantLib::ext::shared_ptr<ore::analytics::MarketRiskGroupBase>& riskGroup) const {
179 return true;
180}
181
182void PnlExplainReport::closeReports(const QuantLib::ext::shared_ptr<MarketRiskReport::Reports>& reports) {
183 QuantLib::ext::shared_ptr<InMemoryReport> report =
184 QuantLib::ext::dynamic_pointer_cast<ore::data::InMemoryReport>(reports->reports().at(0));
185
186 const vector<ore::data::Report::ReportType>& tradeIds = report->data(0);
187 for (Size j = 0; j < tradeIds.size(); j++) {
188 string tradeId = QuantLib::ext::get<std::string>(tradeIds[j]);
189 const auto& r = results_.find(tradeId);
190 if (r == results_.end()) {
191 StructuredAnalyticsWarningMessage("Pnl Explain", "Failed to generate Pnl Explain Records",
192 "Could not find Pnl Explain record for trade ID: " + tradeId)
193 .log();
194 } else {
195 report->next();
196 report->jumpToColumn(pnlReportColumnSize_);
197 report->add(r->second.pnl)
198 .add(r->second.delta)
199 .add(r->second.gamma)
200 .add(r->second.vega)
201 .add(r->second.irDelta)
202 .add(r->second.irGamma)
203 .add(r->second.irVega)
204 .add(r->second.eqDelta)
205 .add(r->second.eqGamma)
206 .add(r->second.eqVega)
207 .add(r->second.fxDelta)
208 .add(r->second.fxGamma)
209 .add(r->second.fxVega)
210 .add(r->second.infDelta)
211 .add(r->second.infGamma)
212 .add(r->second.infVega)
213 .add(r->second.creditDelta)
214 .add(r->second.creditGamma)
215 .add(r->second.creditVega)
216 .add(r->second.comDelta)
217 .add(r->second.comGamma)
218 .add(r->second.comVega);
219 }
220 }
221
223}
224
225} // namespace analytics
226} // namespace ore
virtual void closeReports(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports)
std::vector< QuantLib::ext::shared_ptr< PNLCalculator > > pnlCalculators_
boost::optional< ore::data::TimePeriod > period_
virtual std::string portfolioId(const QuantLib::ext::shared_ptr< TradeGroupBase > &tradeGroup) const
std::vector< std::string > tradeIds_
virtual bool runTradeDetail(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports)
void createReports(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports) override
void closeReports(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports) override
void addPnlCalculators(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports) override
std::map< std::string, PnlExplainResults > results_
bool includeDeltaMargin(const QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > &riskGroup) const override
bool includeGammaMargin(const QuantLib::ext::shared_ptr< ore::analytics::MarketRiskGroupBase > &riskGroup) const override
void writeReports(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &reports, const QuantLib::ext::shared_ptr< MarketRiskGroupBase > &riskGroup, const QuantLib::ext::shared_ptr< TradeGroupBase > &tradeGroup) override
void handleSensiResults(const QuantLib::ext::shared_ptr< MarketRiskReport::Reports > &report, const QuantLib::ext::shared_ptr< MarketRiskGroupBase > &riskGroup, const QuantLib::ext::shared_ptr< TradeGroupBase > &tradeGroup) override
void populateResults(QuantLib::ext::shared_ptr< MarketRiskGroup > mrg, PnlExplainReport::PnlExplainResults &result, QuantLib::Real deltaPnl, QuantLib::Real gammaPnl, QuantLib::Real pnl)
std::vector< std::vector< QuantLib::Real > > TradePnLStore
Size size(const ValueType &v)
Class for structured analytics warnings.