Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
pnlanalytic.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2023 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
26
28
30
31namespace ore {
32namespace analytics {
33
36
37 analytic()->configurations().todaysMarketParams = inputs_->todaysMarketParams();
38 analytic()->configurations().simMarketParams = inputs_->scenarioSimMarketParams();
39
41}
42
43void PnlAnalyticImpl::runAnalytic(const QuantLib::ext::shared_ptr<ore::data::InMemoryLoader>& loader,
44 const std::set<std::string>& runTypes) {
45
46 if (!analytic()->match(runTypes))
47 return;
48
49 Settings::instance().evaluationDate() = inputs_->asof();
51 ObservationMode::instance().setMode(inputs_->observationModel());
52
53 QL_REQUIRE(inputs_->portfolio(), "PnlAnalytic::run: No portfolio loaded.");
54 QL_REQUIRE(inputs_->portfolio()->size() > 0, "PnlAnalytic::run: Portfolio is empty.");
55
56 std::string effectiveResultCurrency =
57 inputs_->resultCurrency().empty() ? inputs_->baseCurrency() : inputs_->resultCurrency();
58
59 /*******************************
60 *
61 * 0. Build market and portfolio
62 *
63 *******************************/
64
65 analytic()->buildMarket(loader);
66
67 /****************************************************
68 *
69 * 1. Write the t0 NPV and Additional Results reports
70 *
71 ****************************************************/
72
73 // Build a simMarket on the asof date
74 QL_REQUIRE(analytic()->configurations().simMarketParams, "scenario sim market parameters not set");
75 QL_REQUIRE(analytic()->configurations().todaysMarketParams, "today's market parameters not set");
76
77 auto simMarket = QuantLib::ext::make_shared<ScenarioSimMarket>(
78 analytic()->market(), analytic()->configurations().simMarketParams, inputs_->marketConfig("pricing"),
79 *analytic()->configurations().curveConfig, *analytic()->configurations().todaysMarketParams,
80 inputs_->continueOnError(), useSpreadedTermStructures(), false, false, *inputs_->iborFallbackConfig());
81 auto sgen = QuantLib::ext::make_shared<StaticScenarioGenerator>();
82 simMarket->scenarioGenerator() = sgen;
83
84 analytic()->setMarket(simMarket);
86
87 boost::shared_ptr<InMemoryReport> t0NpvReport = boost::make_shared<InMemoryReport>();
88 ReportWriter(inputs_->reportNaString())
89 .writeNpv(*t0NpvReport, effectiveResultCurrency, analytic()->market(), inputs_->marketConfig("pricing"),
90 analytic()->portfolio());
91 analytic()->reports()[LABEL]["pnl_npv_t0"] = t0NpvReport;
92
93 if (inputs_->outputAdditionalResults()) {
94 CONSOLEW("Pricing: Additional t0 Results");
95 boost::shared_ptr<InMemoryReport> t0AddReport = boost::make_shared<InMemoryReport>();
96 ReportWriter(inputs_->reportNaString())
97 .writeAdditionalResultsReport(*t0AddReport, analytic()->portfolio(), analytic()->market(),
98 effectiveResultCurrency);
99 analytic()->reports()[LABEL]["pnl_additional_results_t0"] = t0AddReport;
100 CONSOLE("OK");
101 }
102
103 /****************************************************
104 *
105 * 2. Write cash flow report for the clean actual P&L
106 *
107 ****************************************************/
108
109 boost::shared_ptr<InMemoryReport> t0CashFlowReport = boost::make_shared<InMemoryReport>();
110 string marketConfig = inputs_->marketConfig("pricing");
111 ReportWriter(inputs_->reportNaString())
112 .writeCashflow(*t0CashFlowReport, effectiveResultCurrency, analytic()->portfolio(),
113 analytic()->market(),
114 marketConfig, inputs_->includePastCashflows());
115 analytic()->reports()[LABEL]["pnl_cashflow"] = t0CashFlowReport;
116
117 /*******************************************************************************************
118 *
119 * 3. Prepare "NPV lagged" calculations by creating shift scenarios
120 * - to price the t0 portfolio as of t0 using the t1 market (risk hypothetical clean P&L)
121 * - to price the t0 portfolio as of t1 using the t0 market (theta, time decay)
122 *
123 *******************************************************************************************/
124
125 // Set eveluationDate to t1 > t0
126 Settings::instance().evaluationDate() = mporDate();
127
128 // Set the configurations asof date for the mpor analytic to t1, too
129 auto mporAnalytic = dependentAnalytic(mporLookupKey);
130 mporAnalytic->configurations().asofDate = mporDate();
131 mporAnalytic->configurations().todaysMarketParams = analytic()->configurations().todaysMarketParams;
132 mporAnalytic->configurations().simMarketParams = analytic()->configurations().simMarketParams;
133
134 // Run the mpor analytic to generate the market scenario as of t1
135 mporAnalytic->runAnalytic(loader);
136
137 // Set the evaluation date back to t0
138 Settings::instance().evaluationDate() = inputs_->asof();
139
140 QuantLib::ext::shared_ptr<Scenario> asofBaseScenario = simMarket->baseScenarioAbsolute();
141 auto sai = static_cast<ScenarioAnalyticImpl*>(mporAnalytic->impl().get());
142 QuantLib::ext::shared_ptr<Scenario> mporBaseScenario = sai->scenarioSimMarket()->baseScenarioAbsolute();
143
144 QuantLib::ext::shared_ptr<ore::analytics::Scenario> t0Scenario =
145 getDifferenceScenario(asofBaseScenario, mporBaseScenario, inputs_->asof(), 1.0);
146 setT0Scenario(asofBaseScenario);
147
148 // Create the inverse shift scenario as spread between t0 market and t1 market, to be applied to t1
149
150 QuantLib::ext::shared_ptr<ore::analytics::Scenario> t1Scenario =
151 getDifferenceScenario(mporBaseScenario, asofBaseScenario, mporDate(), 1.0);
152 setT1Scenario(mporBaseScenario);
153
154 /********************************************************************************************
155 *
156 * 4. Price the t0 portfolio as of t0 using the t1 market for the risk-hypothetical clean P&L
157 *
158 ********************************************************************************************/
159
160 // Now update simMarket on asof date t0, with the t0 shift scenario
161 sgen->setScenario(t0Scenario);
162 simMarket->update(simMarket->asofDate());
163 analytic()->setMarket(simMarket);
164
165 // Build the portfolio, linked to the shifted market
167
168 // This hook allows modifying the portfolio in derived classes before running the analytics below
170
171 QuantLib::ext::shared_ptr<InMemoryReport> t0NpvLaggedReport = QuantLib::ext::make_shared<InMemoryReport>();
172 ReportWriter(inputs_->reportNaString())
173 .writeNpv(*t0NpvLaggedReport, effectiveResultCurrency, analytic()->market(), inputs_->marketConfig("pricing"),
174 analytic()->portfolio());
175
176 if (inputs_->outputAdditionalResults()) {
177 CONSOLEW("Pricing: Additional Results, t0 lagged");
178 boost::shared_ptr<InMemoryReport> t0LaggedAddReport = boost::make_shared<InMemoryReport>();
179 ReportWriter(inputs_->reportNaString())
180 .writeAdditionalResultsReport(*t0LaggedAddReport, analytic()->portfolio(), analytic()->market(),
181 effectiveResultCurrency);
182 analytic()->reports()[LABEL]["pnl_additional_results_lagged_t0"] = t0LaggedAddReport;
183 CONSOLE("OK");
184 }
185 analytic()->reports()[LABEL]["pnl_npv_lagged_t0"] = t0NpvLaggedReport;
186
187 /***********************************************************************************************
188 *
189 * 5. Price the t0 portfolio as of t1 using the t0 market for the theta / time decay calculation
190 * Reusing the mpor analytic setup here which is as of t1 already.
191 *
192 ***********************************************************************************************/
193
194 Date d1 = mporDate();
195 Settings::instance().evaluationDate() = d1;
197 auto simMarket1 = sai->scenarioSimMarket();
198 auto sgen1 = QuantLib::ext::make_shared<StaticScenarioGenerator>();
199 analytic()->setMarket(simMarket1);
200 sgen1->setScenario(t1Scenario);
201 simMarket1->scenarioGenerator() = sgen1;
202 simMarket1->update(d1);
204
205 QuantLib::ext::shared_ptr<InMemoryReport> t1NpvLaggedReport = QuantLib::ext::make_shared<InMemoryReport>();
206 ReportWriter(inputs_->reportNaString())
207 .writeNpv(*t1NpvLaggedReport, effectiveResultCurrency, analytic()->market(), inputs_->marketConfig("pricing"),
208 analytic()->portfolio());
209
210 analytic()->reports()[LABEL]["pnl_npv_lagged_t1"] = t1NpvLaggedReport;
211
212 if (inputs_->outputAdditionalResults()) {
213 CONSOLEW("Pricing: Additional Results t1");
214 boost::shared_ptr<InMemoryReport> t1AddReport = boost::make_shared<InMemoryReport>();
215 ReportWriter(inputs_->reportNaString())
216 .writeAdditionalResultsReport(*t1AddReport, analytic()->portfolio(), analytic()->market(),
217 effectiveResultCurrency);
218 analytic()->reports()[LABEL]["pnl_additional_results_lagged_t1"] = t1AddReport;
219 CONSOLE("OK");
220 }
221
222 /***************************************************************************************
223 *
224 * 6. Price the t0 portfolio as of t1 using the t1 market for the actual P&L calculation
225 * TODO: This should use the t1 portfolio instead.
226 *
227 ***************************************************************************************/
228
229 sgen1->setScenario(sai->scenarioSimMarket()->baseScenario());
230 simMarket1->scenarioGenerator() = sgen1;
231 simMarket1->update(d1);
233
234 QuantLib::ext::shared_ptr<InMemoryReport> t1NpvReport = QuantLib::ext::make_shared<InMemoryReport>();
235 ReportWriter(inputs_->reportNaString())
236 .writeNpv(*t1NpvReport, effectiveResultCurrency, analytic()->market(), inputs_->marketConfig("pricing"),
237 analytic()->portfolio());
238
239 analytic()->reports()[LABEL]["pnl_npv_t1"] = t1NpvReport;
240
241 if (inputs_->outputAdditionalResults()) {
242 CONSOLEW("Pricing: Additional t1 Results");
243 boost::shared_ptr<InMemoryReport> t1AddReport = boost::make_shared<InMemoryReport>();
244 ReportWriter(inputs_->reportNaString())
245 .writeAdditionalResultsReport(*t1AddReport, analytic()->portfolio(), analytic()->market(),
246 effectiveResultCurrency);
247 analytic()->reports()[LABEL]["pnl_additional_results_t1"] = t1AddReport;
248 CONSOLE("OK");
249 }
250
251 /****************************
252 *
253 * 7. Generate the P&L report
254 *
255 ****************************/
256
257 // FIXME: check which market and which portfolio to pass to the report writer
258 QuantLib::ext::shared_ptr<InMemoryReport> pnlReport = QuantLib::ext::make_shared<InMemoryReport>();
259 ReportWriter(inputs_->reportNaString())
260 .writePnlReport(*pnlReport, t0NpvReport, t0NpvLaggedReport, t1NpvLaggedReport, t1NpvReport,
261 t0CashFlowReport, inputs_->asof(), mporDate(),
262 effectiveResultCurrency, analytic()->market(), inputs_->marketConfig("pricing"), analytic()->portfolio());
263 analytic()->reports()[LABEL]["pnl"] = pnlReport;
264
265 /***************************
266 *
267 * 8. Write Scenario Reports
268 *
269 ***************************/
270
271 boost::shared_ptr<InMemoryReport> t0ScenarioReport = boost::make_shared<InMemoryReport>();
272 auto t0sw = ScenarioWriter(nullptr, t0ScenarioReport);
273 t0sw.writeScenario(asofBaseScenario, true);
274 analytic()->reports()[label()]["pnl_scenario_t0"] = t0ScenarioReport;
275
276 boost::shared_ptr<InMemoryReport> t1ScenarioReport = boost::make_shared<InMemoryReport>();
277 auto t1sw = ScenarioWriter(nullptr, t1ScenarioReport);
278 t1sw.writeScenario(mporBaseScenario, true);
279 analytic()->reports()[label()]["pnl_scenario_t1"] = t1ScenarioReport;
280}
281
282} // namespace analytics
283} // namespace ore
Analytic * analytic() const
Definition: analytic.hpp:193
const std::string & label() const
Definition: analytic.hpp:190
void setGenerateAdditionalResults(const bool generateAdditionalResults)
Definition: analytic.hpp:197
QuantLib::ext::shared_ptr< T > dependentAnalytic(const std::string &key) const
Definition: analytic.hpp:251
QuantLib::ext::shared_ptr< InputParameters > inputs_
Definition: analytic.hpp:216
analytic_reports & reports()
Result reports.
Definition: analytic.hpp:131
Configurations & configurations()
Definition: analytic.hpp:128
virtual void modifyPortfolio()
Definition: analytic.hpp:110
virtual void buildMarket(const QuantLib::ext::shared_ptr< ore::data::InMemoryLoader > &loader, const bool marketRequired=true)
Definition: analytic.cpp:178
void setMarket(const QuantLib::ext::shared_ptr< ore::data::Market > &market)
Definition: analytic.hpp:124
virtual void buildPortfolio()
Definition: analytic.cpp:222
void setUpConfigurations() override
Definition: pnlanalytic.cpp:34
const QuantLib::ext::shared_ptr< ore::analytics::Scenario > & t1Scenario() const
Definition: pnlanalytic.hpp:62
void runAnalytic(const QuantLib::ext::shared_ptr< ore::data::InMemoryLoader > &loader, const std::set< std::string > &runTypes={}) override
Definition: pnlanalytic.cpp:43
void setT1Scenario(const QuantLib::ext::shared_ptr< ore::analytics::Scenario > &scenario)
Definition: pnlanalytic.hpp:64
void setT0Scenario(const QuantLib::ext::shared_ptr< ore::analytics::Scenario > &scenario)
Definition: pnlanalytic.hpp:63
static constexpr const char * mporLookupKey
Definition: pnlanalytic.hpp:35
const QuantLib::Date & mporDate() const
Definition: pnlanalytic.hpp:58
const QuantLib::ext::shared_ptr< ore::analytics::Scenario > & t0Scenario() const
Definition: pnlanalytic.hpp:61
static constexpr const char * LABEL
Definition: pnlanalytic.hpp:34
Write ORE outputs to reports.
virtual void writePnlReport(ore::data::Report &report, const ext::shared_ptr< InMemoryReport > &t0NpvReport, const ext::shared_ptr< InMemoryReport > &t0NpvLaggedReport, const ext::shared_ptr< InMemoryReport > &t1NpvLaggedReport, const ext::shared_ptr< InMemoryReport > &t1NpvReport, const ext::shared_ptr< InMemoryReport > &t0CashFlowReport, const Date &startDate, const Date &endDate, const std::string &baseCurrency, const ext::shared_ptr< ore::data::Market > &market, const std::string &configuration, const ext::shared_ptr< Portfolio > &portfolio)
virtual void writeAdditionalResultsReport(ore::data::Report &report, QuantLib::ext::shared_ptr< ore::data::Portfolio > portfolio, QuantLib::ext::shared_ptr< Market > market, const std::string &baseCurrency, const std::size_t precision=6)
virtual void writeCashflow(ore::data::Report &report, const std::string &baseCurrency, QuantLib::ext::shared_ptr< ore::data::Portfolio > portfolio, QuantLib::ext::shared_ptr< ore::data::Market > market=QuantLib::ext::shared_ptr< ore::data::Market >(), const std::string &configuration=ore::data::Market::defaultConfiguration, const bool includePastCashflows=false)
virtual void writeNpv(ore::data::Report &report, const std::string &baseCurrency, QuantLib::ext::shared_ptr< ore::data::Market > market, const std::string &configuration, QuantLib::ext::shared_ptr< Portfolio > portfolio)
KeyType
Risk Factor types.
Definition: scenario.hpp:51
const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarket > & scenarioSimMarket() const
Class for writing scenarios to file.
#define CONSOLEW(text)
#define CONSOLE(text)
Real getDifferenceScenario(const RiskFactorKey::KeyType keyType, const Real v1, const Real v2)
Singleton class to hold global Observation Mode.
ORE NPV Lagged Analytic.
A Class to write ORE outputs to reports.
ORE Scenario Analytic.
Scenario utility functions.
ScenarioWriter class.
Simple scenario class.
QuantLib::ext::shared_ptr< ore::data::TodaysMarketParameters > todaysMarketParams
Definition: analytic.hpp:68
bool simulationConfigRequired
Booleans to determine if these configs are needed.
Definition: analytic.hpp:64
QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarketParameters > simMarketParams
Definition: analytic.hpp:69