Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
pricinganalytic.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2022 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
25
26using namespace ore::data;
27using namespace boost::filesystem;
28
29namespace ore {
30namespace analytics {
31
32/*******************************************************************
33 * PRICING Analytic: NPV, CASHFLOW, CASHFLOWNPV, SENSITIVITY, STRESS
34 *******************************************************************/
35
37 if (find(begin(analytic()->analyticTypes()), end(analytic()->analyticTypes()), "SENSITIVITY") !=
38 end(analytic()->analyticTypes())) {
41 }
42
43 analytic()->configurations().todaysMarketParams = inputs_->todaysMarketParams();
44 analytic()->configurations().simMarketParams = inputs_->sensiSimMarketParams();
45 analytic()->configurations().sensiScenarioData = inputs_->sensiScenarioData();
46
48}
49
51 const QuantLib::ext::shared_ptr<ore::data::InMemoryLoader>& loader,
52 const std::set<std::string>& runTypes) {
53
54 Settings::instance().evaluationDate() = inputs_->asof();
55 ObservationMode::instance().setMode(inputs_->observationModel());
56
57 QL_REQUIRE(inputs_->portfolio(), "PricingAnalytic::run: No portfolio loaded.");
58
59 CONSOLEW("Pricing: Build Market");
60 analytic()->buildMarket(loader);
61 CONSOLE("OK");
62
63 CONSOLEW("Pricing: Build Portfolio");
65 CONSOLE("OK");
66
67 // Check coverage
68 for (const auto& rt : runTypes) {
69 if (std::find(analytic()->analyticTypes().begin(), analytic()->analyticTypes().end(), rt) ==
70 analytic()->analyticTypes().end()) {
71 DLOG("requested analytic " << rt << " not covered by the PricingAnalytic");
72 }
73 }
74
75 // This hook allows modifying the portfolio in derived classes before running the analytics below,
76 // e.g. to apply SIMM exemptions.
78
79 for (const auto& type : analytic()->analyticTypes()) {
80 QuantLib::ext::shared_ptr<InMemoryReport> report = QuantLib::ext::make_shared<InMemoryReport>();
81 InMemoryReport tmpReport;
82 // skip analytics not requested
83 if (runTypes.find(type) == runTypes.end())
84 continue;
85
86 std::string effectiveResultCurrency =
87 inputs_->resultCurrency().empty() ? inputs_->baseCurrency() : inputs_->resultCurrency();
88 if (type == "NPV") {
89 CONSOLEW("Pricing: NPV Report");
90 ReportWriter(inputs_->reportNaString())
91 .writeNpv(*report, effectiveResultCurrency, analytic()->market(), inputs_->marketConfig("pricing"),
92 analytic()->portfolio());
93 analytic()->reports()[type]["npv"] = report;
94 CONSOLE("OK");
95 if (inputs_->outputAdditionalResults()) {
96 CONSOLEW("Pricing: Additional Results");
97 QuantLib::ext::shared_ptr<InMemoryReport> addReport = QuantLib::ext::make_shared<InMemoryReport>();;
98 ReportWriter(inputs_->reportNaString())
99 .writeAdditionalResultsReport(*addReport, analytic()->portfolio(), analytic()->market(),
100 effectiveResultCurrency, inputs_->additionalResultsReportPrecision());
101 analytic()->reports()[type]["additional_results"] = addReport;
102 CONSOLE("OK");
103 }
104 if (inputs_->outputCurves()) {
105 CONSOLEW("Pricing: Curves Report");
106 LOG("Write curves report");
107 QuantLib::ext::shared_ptr<InMemoryReport> curvesReport = QuantLib::ext::make_shared<InMemoryReport>();
108 DateGrid grid(inputs_->curvesGrid());
109 std::string config = inputs_->curvesMarketConfig();
110 ReportWriter(inputs_->reportNaString())
111 .writeCurves(*curvesReport, config, grid, *inputs_->todaysMarketParams(),
112 analytic()->market(), inputs_->continueOnError());
113 analytic()->reports()[type]["curves"] = curvesReport;
114 CONSOLE("OK");
115 }
116 }
117 else if (type == "CASHFLOW") {
118 CONSOLEW("Pricing: Cashflow Report");
119 string marketConfig = inputs_->marketConfig("pricing");
120 ReportWriter(inputs_->reportNaString())
121 .writeCashflow(*report, effectiveResultCurrency, analytic()->portfolio(),
122 analytic()->market(),
123 marketConfig, inputs_->includePastCashflows());
124 analytic()->reports()[type]["cashflow"] = report;
125 CONSOLE("OK");
126 }
127 else if (type == "CASHFLOWNPV") {
128 CONSOLEW("Pricing: Cashflow NPV report");
129 string marketConfig = inputs_->marketConfig("pricing");
130 ReportWriter(inputs_->reportNaString())
131 .writeCashflow(tmpReport, effectiveResultCurrency, analytic()->portfolio(),
132 analytic()->market(),
133 marketConfig, inputs_->includePastCashflows());
134 ReportWriter(inputs_->reportNaString())
135 .writeCashflowNpv(*report, tmpReport, analytic()->market(), marketConfig,
136 effectiveResultCurrency, inputs_->cashflowHorizon());
137 analytic()->reports()[type]["cashflownpv"] = report;
138 CONSOLE("OK");
139 }
140 else if (type == "SENSITIVITY") {
141 CONSOLEW("Risk: Sensitivity Report");
142 LOG("Sensi Analysis - Initialise");
143 bool recalibrateModels = true;
144 bool ccyConv = false;
145 std::string configuration = inputs_->marketConfig("pricing");
146 QuantLib::ext::shared_ptr<SensitivityAnalysis> sensiAnalysis;
147 if (inputs_->nThreads() == 1) {
148 LOG("Single-threaded sensi analysis");
149 sensiAnalysis = QuantLib::ext::make_shared<SensitivityAnalysis>(
150 analytic()->portfolio(), analytic()->market(), configuration, inputs_->pricingEngine(),
151 analytic()->configurations().simMarketParams, analytic()->configurations().sensiScenarioData,
152 recalibrateModels, analytic()->configurations().curveConfig,
153 analytic()->configurations().todaysMarketParams, ccyConv, inputs_->refDataManager(),
154 *inputs_->iborFallbackConfig(), true, inputs_->dryRun());
155 LOG("Single-threaded sensi analysis created");
156 }
157 else {
158 LOG("Multi-threaded sensi analysis");
159 sensiAnalysis = QuantLib::ext::make_shared<SensitivityAnalysis>(
160 inputs_->nThreads(), inputs_->asof(), loader, analytic()->portfolio(), configuration,
161 inputs_->pricingEngine(), analytic()->configurations().simMarketParams,
162 analytic()->configurations().sensiScenarioData, recalibrateModels,
163 analytic()->configurations().curveConfig, analytic()->configurations().todaysMarketParams, ccyConv,
164 inputs_->refDataManager(), *inputs_->iborFallbackConfig(), true, inputs_->dryRun());
165 LOG("Multi-threaded sensi analysis created");
166 }
167 // FIXME: Why are these disabled?
168 set<RiskFactorKey::KeyType> typesDisabled{RiskFactorKey::KeyType::OptionletVolatility};
169 QuantLib::ext::shared_ptr<ParSensitivityAnalysis> parAnalysis = nullptr;
170 if (inputs_->parSensi() || inputs_->alignPillars()) {
171 parAnalysis= QuantLib::ext::make_shared<ParSensitivityAnalysis>(
172 inputs_->asof(), analytic()->configurations().simMarketParams,
173 *analytic()->configurations().sensiScenarioData, "",
174 true, typesDisabled);
175 if (inputs_->alignPillars()) {
176 LOG("Sensi analysis - align pillars (for the par conversion or because alignPillars is enabled)");
177 parAnalysis->alignPillars();
178 sensiAnalysis->overrideTenors(true);
179 } else {
180 LOG("Sensi analysis - skip aligning pillars");
181 }
182 }
183
184 LOG("Sensi analysis - generate");
185 sensiAnalysis->registerProgressIndicator(QuantLib::ext::make_shared<ProgressLog>("sensitivities", 100, oreSeverity::notice));
186 sensiAnalysis->generateSensitivities();
187
188 LOG("Sensi analysis - write sensitivity report in memory");
189 auto baseCurrency = sensiAnalysis->simMarketData()->baseCcy();
190 auto ss = QuantLib::ext::make_shared<SensitivityCubeStream>(sensiAnalysis->sensiCubes(), baseCurrency);
191 ReportWriter(inputs_->reportNaString())
192 .writeSensitivityReport(*report, ss, inputs_->sensiThreshold());
193 analytic()->reports()[type]["sensitivity"] = report;
194
195 LOG("Sensi analysis - write sensitivity scenario report in memory");
196 QuantLib::ext::shared_ptr<InMemoryReport> scenarioReport = QuantLib::ext::make_shared<InMemoryReport>();
197 ReportWriter(inputs_->reportNaString())
198 .writeScenarioReport(*scenarioReport, sensiAnalysis->sensiCubes(),
199 inputs_->sensiThreshold());
200 analytic()->reports()[type]["sensitivity_scenario"] = scenarioReport;
201
202 auto simmSensitivityConfigReport = QuantLib::ext::make_shared<InMemoryReport>();
203 ReportWriter(inputs_->reportNaString())
204 .writeSensitivityConfigReport(*simmSensitivityConfigReport,
205 sensiAnalysis->scenarioGenerator()->shiftSizes(),
206 sensiAnalysis->scenarioGenerator()->baseValues(),
207 sensiAnalysis->scenarioGenerator()->keyToFactor());
208 analytic()->reports()[type]["sensitivity_config"] = simmSensitivityConfigReport;
209
210 if (inputs_->parSensi()) {
211 LOG("Sensi analysis - par conversion");
212
213 if (inputs_->optimiseRiskFactors()){
214 std::set<RiskFactorKey> collectRiskFactors;
215 // collect risk factors of all cubes ...
216 for(auto const& c : sensiAnalysis->sensiCubes()){
217 auto currentRF = c->relevantRiskFactors();
218 // ... and combine for the par analysis
219 collectRiskFactors.insert(currentRF.begin(), currentRF.end());
220 }
221 parAnalysis->relevantRiskFactors() = collectRiskFactors;
222 LOG("optimiseRiskFactors active : parSensi risk factors set to zeroSensi risk factors");
223 }
224 parAnalysis->computeParInstrumentSensitivities(sensiAnalysis->simMarket());
225 QuantLib::ext::shared_ptr<ParSensitivityConverter> parConverter =
226 QuantLib::ext::make_shared<ParSensitivityConverter>(parAnalysis->parSensitivities(), parAnalysis->shiftSizes());
227 auto parCube = QuantLib::ext::make_shared<ZeroToParCube>(sensiAnalysis->sensiCubes(), parConverter, typesDisabled, true);
228 LOG("Sensi analysis - write par sensitivity report in memory");
229 QuantLib::ext::shared_ptr<ParSensitivityCubeStream> pss =
230 QuantLib::ext::make_shared<ParSensitivityCubeStream>(parCube, baseCurrency);
231 // If the stream is going to be reused - wrap it into a buffered stream to gain some
232 // performance. The cost for this is the memory footpring of the buffer.
233 QuantLib::ext::shared_ptr<InMemoryReport> parSensiReport = QuantLib::ext::make_shared<InMemoryReport>();
234 ReportWriter(inputs_->reportNaString())
235 .writeSensitivityReport(*parSensiReport, pss, inputs_->sensiThreshold());
236 analytic()->reports()[type]["par_sensitivity"] = parSensiReport;
237
238 if (inputs_->outputJacobi()) {
239 QuantLib::ext::shared_ptr<InMemoryReport> jacobiReport = QuantLib::ext::make_shared<InMemoryReport>();
240 writeParConversionMatrix(parAnalysis->parSensitivities(), *jacobiReport);
241 analytic()->reports()[type]["jacobi"] = jacobiReport;
242
243 QuantLib::ext::shared_ptr<InMemoryReport> jacobiInverseReport = QuantLib::ext::make_shared<InMemoryReport>();
244 parConverter->writeConversionMatrix(*jacobiInverseReport);
245 analytic()->reports()[type]["jacobi_inverse"] = jacobiInverseReport;
246 }
247 }
248 else {
249 LOG("Sensi Analysis - skip par conversion");
250 }
251
252 LOG("Sensi Analysis - Completed");
253 CONSOLE("OK");
254 }
255 else {
256 QL_FAIL("PricingAnalytic type " << type << " invalid");
257 }
258 }
259}
260
261} // namespace analytics
262} // namespace ore
Analytic * analytic() const
Definition: analytic.hpp:193
void setGenerateAdditionalResults(const bool generateAdditionalResults)
Definition: analytic.hpp:197
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
virtual void buildPortfolio()
Definition: analytic.cpp:222
void runAnalytic(const QuantLib::ext::shared_ptr< ore::data::InMemoryLoader > &loader, const std::set< std::string > &runTypes={}) override
Write ORE outputs to reports.
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 writeCashflowNpv(ore::data::Report &report, const ore::data::InMemoryReport &cashflowReport, QuantLib::ext::shared_ptr< ore::data::Market > market, const std::string &configuration, const std::string &baseCcy, const Date &horizon=Date::maxDate())
virtual void writeCurves(ore::data::Report &report, const std::string &configID, const DateGrid &grid, const TodaysMarketParameters &marketConfig, const QuantLib::ext::shared_ptr< Market > &market, const bool continueOnError=false)
virtual void writeSensitivityReport(ore::data::Report &report, const QuantLib::ext::shared_ptr< SensitivityStream > &ss, QuantLib::Real outputThreshold=0.0, QuantLib::Size outputPrecision=2)
virtual void writeScenarioReport(ore::data::Report &report, const std::vector< QuantLib::ext::shared_ptr< SensitivityCube > > &sensitivityCubes, QuantLib::Real outputThreshold=0.0)
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 writeSensitivityConfigReport(ore::data::Report &report, const std::map< RiskFactorKey, QuantLib::Real > &shiftSizes, const std::map< RiskFactorKey, QuantLib::Real > &baseValues, const std::map< RiskFactorKey, std::string > &keyToFactor)
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)
#define LOG(text)
#define DLOG(text)
#define CONSOLEW(text)
#define CONSOLE(text)
void writeParConversionMatrix(const ParSensitivityAnalysis::ParContainer &parSensitivities, Report &report)
Write par instrument sensitivity report.
Singleton class to hold global Observation Mode.
Perfrom sensitivity analysis for a given portfolio.
Class for streaming SensitivityRecords from a par sensitivity cube.
A Class to write ORE outputs to reports.
QuantLib::ext::shared_ptr< ore::analytics::SensitivityScenarioData > sensiScenarioData
Definition: analytic.hpp:70
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