Skip to content

Commit d0bc0af

Browse files
mgronckijenkins
authored andcommitted
Merge remote-tracking branch 'origin/master' into QPR-12437
1 parent 592f87d commit d0bc0af

4 files changed

Lines changed: 257 additions & 0 deletions

File tree

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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+
19+
#include <orea/app/analytics/xvaanalytic.hpp>
20+
#include <orea/app/analytics/xvasensitivityanalytic.hpp>
21+
#include <orea/app/structuredanalyticserror.hpp>
22+
#include <orea/app/structuredanalyticswarning.hpp>
23+
#include <orea/cube/cube_io.hpp>
24+
#include <orea/scenario/clonescenariofactory.hpp>
25+
#include <orea/scenario/scenariosimmarket.hpp>
26+
#include <orea/scenario/sensitivityscenariogenerator.hpp>
27+
#include <orea/scenario/stressscenariogenerator.hpp>
28+
#include <ored/report/utilities.hpp>
29+
namespace ore {
30+
namespace analytics {
31+
32+
XvaSensitivityAnalyticImpl::XvaSensitivityAnalyticImpl(const QuantLib::ext::shared_ptr<InputParameters>& inputs)
33+
: Analytic::Impl(inputs) {
34+
setLabel(LABEL);
35+
}
36+
37+
void XvaSensitivityAnalyticImpl::runAnalytic(const QuantLib::ext::shared_ptr<ore::data::InMemoryLoader>& loader,
38+
const std::set<std::string>& runTypes) {
39+
40+
// basic setup
41+
42+
LOG("Running XVA Stress analytic.");
43+
44+
Settings::instance().evaluationDate() = inputs_->asof();
45+
46+
QL_REQUIRE(inputs_->portfolio(), "XvaSensitivityAnalytic::run: No portfolio loaded.");
47+
48+
Settings::instance().evaluationDate() = inputs_->asof();
49+
std::string marketConfig = inputs_->marketConfig("pricing"); // FIXME
50+
51+
auto xvaAnalytic = dependentAnalytic<XvaAnalytic>("XVA");
52+
53+
// build t0, sim market, stress scenario generator
54+
55+
CONSOLEW("XVA_STRESS: Build T0 and Sim Markets and Stress Scenario Generator");
56+
57+
analytic()->buildMarket(loader);
58+
59+
LOG("XVA Stress: Build SimMarket and StressTestScenarioGenerator")
60+
auto simMarket = QuantLib::ext::make_shared<ScenarioSimMarket>(
61+
analytic()->market(), analytic()->configurations().simMarketParams, marketConfig,
62+
*analytic()->configurations().curveConfig, *analytic()->configurations().todaysMarketParams,
63+
inputs_->continueOnError(), analytic()->configurations().sensiScenarioData->useSpreadedTermStructures(), false,
64+
false, *inputs_->iborFallbackConfig(), true);
65+
66+
auto baseScenario = simMarket->baseScenario();
67+
auto scenarioFactory = QuantLib::ext::make_shared<CloneScenarioFactory>(baseScenario);
68+
auto scenarioGenerator = QuantLib::ext::make_shared<SensitivityScenarioGenerator>(
69+
analytic()->configurations().sensiScenarioData, baseScenario, analytic()->configurations().simMarketParams,
70+
simMarket, scenarioFactory, simMarket->baseScenarioAbsolute());
71+
simMarket->scenarioGenerator() = scenarioGenerator;
72+
73+
CONSOLE("OK");
74+
75+
// generate the stress scenarios and run dependent xva analytic under each of them
76+
77+
CONSOLE("XVA_STRESS: Running sensi scenarios");
78+
79+
// run stress test
80+
LOG("Run XVA Sensitivity")
81+
runSensitivity(scenarioGenerator, loader);
82+
83+
LOG("Running XVA Sensitivity analytic finished.");
84+
}
85+
86+
void XvaSensitivityAnalyticImpl::runSensitivity(
87+
const QuantLib::ext::shared_ptr<SensitivityScenarioGenerator>& scenarioGenerator,
88+
const QuantLib::ext::shared_ptr<ore::data::InMemoryLoader>& loader) {
89+
90+
std::map<std::string, std::vector<QuantLib::ext::shared_ptr<ore::data::InMemoryReport>>> xvaReports;
91+
for (size_t i = 0; i < scenarioGenerator->samples(); ++i) {
92+
auto scenario = scenarioGenerator->next(inputs_->asof());
93+
auto desc = scenarioGenerator->scenarioDescriptions()[i];
94+
QuantLib::ext::shared_ptr<ore::data::InMemoryReport> descReport =
95+
QuantLib::ext::make_shared<ore::data::InMemoryReport>();
96+
descReport->addColumn("IsPar", string());
97+
descReport->addColumn("Factor_1", string());
98+
descReport->addColumn("ShiftSize_1", double(), 6);
99+
descReport->addColumn("Factor_2", string());
100+
descReport->addColumn("ShiftSize_2", double(), 6);
101+
descReport->addColumn("Currency", string());
102+
descReport->next();
103+
descReport->add("false");
104+
descReport->add(desc.factor1());
105+
descReport->add(scenarioGenerator->shiftSizes().at(desc.key1()));
106+
descReport->add(desc.factor2());
107+
descReport->add(scenarioGenerator->shiftSizes().at(desc.key2()));
108+
descReport->add(inputs_->baseCurrency());
109+
descReport->end();
110+
const std::string& label = scenario != nullptr ? scenario->label() : std::string();
111+
try {
112+
DLOG("Calculate XVA for scenario " << label);
113+
CONSOLE("XVA_STRESS: Apply scenario " << label);
114+
auto newAnalytic = ext::make_shared<XvaAnalytic>(
115+
inputs_, (label == "BASE" ? nullptr : scenario),
116+
(label == "BASE" ? nullptr : analytic()->configurations().simMarketParams));
117+
CONSOLE("XVA_STRESS: Calculate Exposure and XVA")
118+
newAnalytic->runAnalytic(loader, {"EXPOSURE", "XVA"});
119+
// Collect exposure and xva reports
120+
for (auto& [name, rpt] : newAnalytic->reports()["XVA"]) {
121+
// add scenario column to report and copy it, concat it later
122+
if (boost::starts_with(name, "exposure") || boost::starts_with(name, "xva")) {
123+
DLOG("Save and extend report " << name);
124+
xvaReports[name].push_back(addColumnsToExisitingReport(descReport, rpt));
125+
}
126+
}
127+
// writeCubes(label, newAnalytic);
128+
} catch (const std::exception& e) {
129+
StructuredAnalyticsErrorMessage("XvaSensitivity", "XVACalc",
130+
"Error during XVA calc under scenario " + label + ", got " + e.what() +
131+
". Skip it")
132+
.log();
133+
}
134+
}
135+
for (auto& [name, reports] : xvaReports) {
136+
auto report = concatenateReports(reports);
137+
if (report != nullptr) {
138+
analytic()->reports()[label()][name] = report;
139+
}
140+
}
141+
}
142+
143+
void XvaSensitivityAnalyticImpl::setUpConfigurations() {
144+
analytic()->configurations().todaysMarketParams = inputs_->todaysMarketParams();
145+
analytic()->configurations().simMarketParams = inputs_->xvaSensiSimMarketParams();
146+
analytic()->configurations().sensiScenarioData = inputs_->xvaSensiScenarioData();
147+
}
148+
149+
XvaSensitivityAnalytic::XvaSensitivityAnalytic(const QuantLib::ext::shared_ptr<InputParameters>& inputs)
150+
: Analytic(std::make_unique<XvaSensitivityAnalyticImpl>(inputs), {"XVA_STRESS"}, inputs, true, false, false,
151+
false) {
152+
impl()->addDependentAnalytic("XVA", QuantLib::ext::make_shared<XvaAnalytic>(inputs));
153+
}
154+
155+
} // namespace analytics
156+
} // namespace ore
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
19+
/*! \file orea/app/analytics/xvasensitivityanalytic.hpp
20+
\brief xva sensitivity analytic
21+
*/
22+
23+
#pragma once
24+
25+
#include <orea/app/analytic.hpp>
26+
#include <ored/report/inmemoryreport.hpp>
27+
28+
29+
namespace ore {
30+
namespace analytics {
31+
32+
class XvaSensitivityAnalyticImpl : public Analytic::Impl {
33+
public:
34+
static constexpr const char* LABEL = "XVA_SENSI";
35+
explicit XvaSensitivityAnalyticImpl(const QuantLib::ext::shared_ptr<InputParameters>& inputs);
36+
void runAnalytic(const QuantLib::ext::shared_ptr<ore::data::InMemoryLoader>& loader,
37+
const std::set<std::string>& runTypes = {}) override;
38+
void setUpConfigurations() override;
39+
40+
private:
41+
void runSensitivity(const QuantLib::ext::shared_ptr<SensitivityScenarioGenerator>& scenarioGenerator,
42+
const QuantLib::ext::shared_ptr<ore::data::InMemoryLoader>& loader);
43+
};
44+
45+
class XvaSensitivityAnalytic : public Analytic {
46+
public:
47+
explicit XvaSensitivityAnalytic(const QuantLib::ext::shared_ptr<InputParameters>& inputs);
48+
49+
};
50+
51+
52+
53+
} // namespace analytics
54+
} // namespace ore

OREAnalytics/orea/app/inputparameters.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,18 @@ class InputParameters {
707707
double parStressUpperBoundRatesDiscountFactor() const { return parStressUpperBoundRatesDiscountFactor_; }
708708
double parStressAccurary() const { return parStressAccurary_; };
709709

710+
/*************************************
711+
* XVA Sensitivity
712+
*************************************/
713+
714+
const QuantLib::ext::shared_ptr<ore::analytics::ScenarioSimMarketParameters>& xvaSensiSimMarketParams() const {
715+
return xvaSensiSimMarketParams_;
716+
}
717+
const QuantLib::ext::shared_ptr<ore::analytics::SensitivityScenarioData>& xvaSensiScenarioData() const {
718+
return xvaSensiScenarioData_;
719+
}
720+
const QuantLib::ext::shared_ptr<ore::data::EngineData>& xvaSensiPricingEngine() const { return xvaSensiPricingEngine_; }
721+
710722
/*************************************
711723
* List of analytics that shall be run
712724
*************************************/
@@ -996,6 +1008,13 @@ class InputParameters {
9961008
double parStressLowerBoundRatesDiscountFactor_;
9971009
double parStressUpperBoundRatesDiscountFactor_;
9981010
double parStressAccurary_;
1011+
1012+
/*****************
1013+
* XVA Sensitivity analytic
1014+
*****************/
1015+
QuantLib::ext::shared_ptr<ore::analytics::ScenarioSimMarketParameters> xvaSensiSimMarketParams_;
1016+
QuantLib::ext::shared_ptr<ore::analytics::SensitivityScenarioData> xvaSensiScenarioData_;
1017+
QuantLib::ext::shared_ptr<ore::data::EngineData> xvaSensiPricingEngine_;
9991018
};
10001019

10011020
inline const std::string& InputParameters::marketConfig(const std::string& context) {

OREData/ored/report/utilities.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,34 @@ addColumnToExisitingReport(const std::string& columnName, const std::string& val
5353
return newReport;
5454
}
5555

56+
QuantLib::ext::shared_ptr<ore::data::InMemoryReport>
57+
addColumnsToExisitingReport(const QuantLib::ext::shared_ptr<ore::data::InMemoryReport>& newColsReport,
58+
const QuantLib::ext::shared_ptr<ore::data::InMemoryReport>& report) {
59+
QuantLib::ext::shared_ptr<ore::data::InMemoryReport> newReport =
60+
QuantLib::ext::make_shared<ore::data::InMemoryReport>();
61+
if (report != nullptr && newColsReport->rows() == 1) {
62+
63+
for (size_t i = 0; i < newColsReport->columns(); ++i) {
64+
newReport->addColumn(newColsReport->header(i), newColsReport->columnType(i),
65+
newColsReport->columnPrecision(i));
66+
}
67+
for (size_t i = 0; i < report->columns(); i++) {
68+
newReport->addColumn(report->header(i), report->columnType(i), report->columnPrecision(i));
69+
}
70+
for (size_t row = 0; row < report->rows(); row++) {
71+
newReport->next();
72+
for (size_t i = 0; i < newColsReport->columns(); ++i) {
73+
newReport->add(newColsReport->data(i)[0]);
74+
}
75+
for (size_t col = 0; col < report->columns(); col++) {
76+
newReport->add(report->data(col)[row]);
77+
}
78+
}
79+
newReport->end();
80+
}
81+
return newReport;
82+
}
83+
5684
QuantLib::ext::shared_ptr<ore::data::InMemoryReport>
5785
concatenateReports(const std::vector<QuantLib::ext::shared_ptr<ore::data::InMemoryReport>>& reports) {
5886
if (!reports.empty() && reports.front() != nullptr) {

0 commit comments

Comments
 (0)