Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
parstressconverter.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2024 AcadiaSoft Inc.
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
27namespace ore {
28namespace analytics {
29
30namespace{
31 //! Build a bi-graph from the parSensitivites and sort the graph by their dependency
32std::vector<RiskFactorKey>
33sortParRiskFactorByDependency(const ParSensitivityAnalysis::ParContainer& parWithRespectToZero) {
34
35 std::map<RiskFactorKey, std::set<RiskFactorKey>> parToZeroEdges;
36 std::map<RiskFactorKey, std::set<RiskFactorKey>> zeroToParEdges;
37 std::vector<RiskFactorKey> orderedKeys;
38 std::map<RiskFactorKey, size_t> order;
39 std::map<RiskFactorKey, std::set<RiskFactorKey>> dependencies;
40 for (const auto& [key, value] : parWithRespectToZero) {
41 const auto& [parKey, zeroKey] = key;
42 if (order.count(parKey) == 0) {
43 order[parKey] = 0;
44 }
45 if (!QuantLib::close_enough(value, 0.0)) {
46 parToZeroEdges[parKey].insert(zeroKey);
47 if (zeroKey != parKey) {
48 order[parKey] = order[parKey] + 1;
49 dependencies[zeroKey].insert(parKey);
50 }
51 }
52 }
53
54 std::queue<RiskFactorKey> zeroOrderParKeys;
55 for (const auto& [key, n] : order) {
56 if (n == 0) {
57 zeroOrderParKeys.push(key);
58 }
59 }
60
61 while (!zeroOrderParKeys.empty()) {
62 auto key = zeroOrderParKeys.front();
63 zeroOrderParKeys.pop();
64 orderedKeys.push_back(key);
65 for (const auto& dependentKey : dependencies[key]) {
66 order[dependentKey] -= 1;
67 if (order[dependentKey] == 0) {
68 zeroOrderParKeys.push(dependentKey);
69 }
70 }
71 }
72 return orderedKeys;
73}
74
75}
76
78 const QuantLib::Date& asof, QuantLib::ext::shared_ptr<ore::data::TodaysMarketParameters>& todaysMarketParams,
79 const QuantLib::ext::shared_ptr<ore::analytics::ScenarioSimMarketParameters>& simMarketParams,
80 const QuantLib::ext::shared_ptr<ore::analytics::SensitivityScenarioData>& sensiScenarioData,
81 const QuantLib::ext::shared_ptr<ore::data::CurveConfigurations>& curveConfigs,
82 const QuantLib::ext::shared_ptr<ore::data::Market>& todaysMarket,
83 const QuantLib::ext::shared_ptr<ore::data::IborFallbackConfig>& iborFallbackConfig)
84 : asof_(asof), todaysMarketParams_(todaysMarketParams), simMarketParams_(simMarketParams),
85 sensiScenarioData_(sensiScenarioData), curveConfigs_(curveConfigs), todaysMarket_(todaysMarket),
86 iborFallbackConfig_(iborFallbackConfig) {}
87
88QuantLib::ext::shared_ptr<ore::analytics::StressTestScenarioData> ParStressTestConverter::convertStressScenarioData(
89 const QuantLib::ext::shared_ptr<ore::analytics::StressTestScenarioData>& stressTestData) const {
90 // Exit early if we have dont have any par stress shifts in any scenario
91 if (!stressTestData->hasScenarioWithParShifts()) {
92 LOG("ParStressConverter: No scenario with par shifts found, use it as is");
93 return stressTestData;
94 }
95 QuantLib::ext::shared_ptr<StressTestScenarioData> results = QuantLib::ext::make_shared<StressTestScenarioData>();
96 results->useSpreadedTermStructures() = stressTestData->useSpreadedTermStructures();
97 // Identify all required parInstruments, ignore if a risk factor is a zeroshift in all scenarios
98 // The following risk factors arent supported in the par stress
99 std::set<RiskFactorKey::KeyType> disabledRiskFactors{
102
103 auto disabled = disabledParRates(stressTestData->withIrCurveParShifts(), stressTestData->withIrCapFloorParShifts(),
104 stressTestData->withCreditCurveParShifts());
105 disabledRiskFactors.insert(disabled.begin(), disabled.end());
106
107 DLOG("ParStressConverter: The following risk factors will be not converted:")
108 for (const auto& keyType : disabledRiskFactors) {
109 DLOG(keyType);
110 }
111 LOG("ParStressConverter: Compute Par Sensitivities")
112 auto [simMarket, parAnalysis] = computeParSensitivity(disabledRiskFactors);
113 // Loop over scenarios
114 LOG("ParStressConverter: Build dependency graph of par instruments")
115 auto dependencyGraph = sortParRiskFactorByDependency(parAnalysis->parSensitivities());
116 ParStressScenarioConverter converter(asof_, dependencyGraph, simMarketParams_, sensiScenarioData_, simMarket,
117 parAnalysis->parInstruments(), stressTestData->useSpreadedTermStructures());
118
119 for (const auto& scenario : stressTestData->data()) {
120 DLOG("ParStressConverter: Scenario" << scenario.label);
121 if (scenario.containsParShifts()) {
122 try {
123 LOG("ParStressConverter: Scenario " << scenario.label << " Convert par shifts to zero shifts");
124 auto convertedScenario = converter.convertScenario(scenario);
125 results->data().push_back(std::move(convertedScenario));
126 } catch (const std::exception& e) {
127 StructuredAnalyticsWarningMessage("ParStressConversion", "ScenarioConversionFailed",
128 "Skip Scenario " + scenario.label + ", got :" + e.what())
129 .log();
130 }
131 } else {
132 LOG("ParStressConverter: Skip scenario " << scenario.label << ", it contains only zero shifts");
133 results->data().push_back(scenario);
134 }
135 }
136 return results;
137}
138
139//! Creates a SimMarket, aligns the pillars and strikes of sim and sensitivity scenario market, computes par
140//! sensitivites
141std::pair<QuantLib::ext::shared_ptr<ScenarioSimMarket>, QuantLib::ext::shared_ptr<ParSensitivityAnalysis>>
142ParStressTestConverter::computeParSensitivity(const std::set<RiskFactorKey::KeyType>& typesDisabled) const {
143 QL_REQUIRE(simMarketParams_ != nullptr, "computeParSensitivity: simMarketData required to compute par sensitivity before "
144 "converting par to zero stress test shifts");
145 QL_REQUIRE(sensiScenarioData_ != nullptr,
146 "computeParSensitivity: sensiScenarioData required to compute par sensitivity before "
147 "converting par to zero stress test shifts");
148 auto parAnalysis = ext::make_shared<ParSensitivityAnalysis>(asof_, simMarketParams_, *sensiScenarioData_,
149 Market::defaultConfiguration, true, typesDisabled);
150 QL_REQUIRE(parAnalysis != nullptr, "ParStressConverter: failed to generate parAnalysis");
151 LOG("ParStressConverter: Allign Pillars for par sensitivity analysis");
152 parAnalysis->alignPillars();
153 // Align Cap Floor Strikes
154 if (typesDisabled.count(RiskFactorKey::KeyType::OptionletVolatility) == 0) {
155 LOG("ParStressConverter: Allign CapFloor strikes and adjust optionletPillars");
156 for (const auto& [index, data] : sensiScenarioData_->capFloorVolShiftData()) {
157 simMarketParams_->setCapFloorVolStrikes(index, data->shiftStrikes);
158 simMarketParams_->setCapFloorVolAdjustOptionletPillars(true);
159 }
160 }
161 LOG("ParStressConverter: Build SimMarket");
162 auto simMarket = QuantLib::ext::make_shared<ScenarioSimMarket>(
166 sensiScenarioData_->useSpreadedTermStructures(), false, true, *iborFallbackConfig_);
167 LOG("ParStressConverter: Build ScenarioGenerator");
168 auto scnearioFactory = QuantLib::ext::make_shared<ore::analytics::DeltaScenarioFactory>(simMarket->baseScenario());
169 auto scenarioGenerator = QuantLib::ext::make_shared<SensitivityScenarioGenerator>(
170 sensiScenarioData_, simMarket->baseScenario(), simMarketParams_, simMarket, scnearioFactory, true, "", false,
171 simMarket->baseScenarioAbsolute());
172 simMarket->scenarioGenerator() = scenarioGenerator;
173 LOG("ParStressConverter: Compute ParInstrumentSensitivities");
174 parAnalysis->computeParInstrumentSensitivities(simMarket);
175 return {simMarket, parAnalysis};
176}
177
178} // namespace analytics
179
180} // namespace ore
std::map< std::pair< ore::analytics::RiskFactorKey, ore::analytics::RiskFactorKey >, Real > ParContainer
Convert all par shifts in a single stress test scenario to zero shifts.
ore::analytics::StressTestScenarioData::StressTestData convertScenario(const StressTestScenarioData::StressTestData &scenario) const
Convert par shifts in a stress scenario to zero shifts.
QuantLib::ext::shared_ptr< ore::data::CurveConfigurations > curveConfigs_
QuantLib::ext::shared_ptr< ore::data::TodaysMarketParameters > todaysMarketParams_
QuantLib::ext::shared_ptr< ore::data::Market > todaysMarket_
QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarketParameters > simMarketParams_
std::pair< QuantLib::ext::shared_ptr< ScenarioSimMarket >, QuantLib::ext::shared_ptr< ParSensitivityAnalysis > > computeParSensitivity(const std::set< RiskFactorKey::KeyType > &typesDisabled) const
ParStressTestConverter(const QuantLib::Date &asof, QuantLib::ext::shared_ptr< ore::data::TodaysMarketParameters > &todaysMarketParams, const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarketParameters > &simMarketParams, const QuantLib::ext::shared_ptr< ore::analytics::SensitivityScenarioData > &sensiScenarioData, const QuantLib::ext::shared_ptr< ore::data::CurveConfigurations > &curveConfigs, const QuantLib::ext::shared_ptr< ore::data::Market > &todaysMarket, const QuantLib::ext::shared_ptr< ore::data::IborFallbackConfig > &iborFallbackConfig)
QuantLib::ext::shared_ptr< ore::data::IborFallbackConfig > iborFallbackConfig_
QuantLib::ext::shared_ptr< ore::analytics::SensitivityScenarioData > sensiScenarioData_
QuantLib::ext::shared_ptr< ore::analytics::StressTestScenarioData > convertStressScenarioData(const QuantLib::ext::shared_ptr< ore::analytics::StressTestScenarioData > &scenarioData) const
Convert all par shifts to zero shifts for all scenarios defined in the stresstest.
static const string defaultConfiguration
factory class for cloning a cached scenario
data
#define LOG(text)
#define DLOG(text)
std::set< RiskFactorKey::KeyType > disabledParRates(bool irCurveParRates, bool irCapFloorParRates, bool creditParRates)
Perfrom sensitivity analysis for a given portfolio.
Convert all par shifts in a stress test to a zero shifts.
Convert all par shifts in a single stress test scenario to a zero shifts.
Class for structured analytics warnings.
vector< string > curveConfigs
Date asof(14, Jun, 2018)