Skip to content

Commit 004a885

Browse files
pcaspersjenkins
authored andcommitted
Merge branch 'QPR-13347' into 'master'
QPR-13347 Add wildcard support in stress test for eq names, eq vols, survival... Closes QPR-13347 See merge request qs/oreplus!2731
1 parent c62a204 commit 004a885

2 files changed

Lines changed: 136 additions & 14 deletions

File tree

OREAnalytics/orea/scenario/stressscenariogenerator.cpp

Lines changed: 130 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ using namespace std;
2727
namespace ore {
2828
namespace analytics {
2929

30+
namespace {
31+
template<class StressTestShifts>
32+
std::vector<Wildcard> wildcardList(
33+
const map<string, QuantLib::ext::shared_ptr<StressTestShifts>>& shifts) {
34+
std::vector<Wildcard> wcs;
35+
for (auto const& shift : shifts) {
36+
Wildcard wc(shift.first);
37+
if (wc.hasWildcard()) {
38+
wcs.push_back(wc);
39+
}
40+
}
41+
return wcs;
42+
}
43+
}
44+
3045
StressScenarioGenerator::StressScenarioGenerator(const QuantLib::ext::shared_ptr<StressTestScenarioData>& stressData,
3146
const QuantLib::ext::shared_ptr<Scenario>& baseScenario,
3247
const QuantLib::ext::shared_ptr<ScenarioSimMarketParameters>& simMarketData,
@@ -81,9 +96,42 @@ void StressScenarioGenerator::generateScenarios() {
8196
DLOG("stress scenario generator: all scenarios generated.");
8297
}
8398

99+
template<class StressTestShifts>
100+
map<string, QuantLib::ext::shared_ptr<StressTestShifts>>
101+
StressScenarioGenerator::populateShiftData(
102+
const map<string, QuantLib::ext::shared_ptr<StressTestShifts>>& stressTestShifts,
103+
const vector<Wildcard>& wildcardKeys,
104+
RiskFactorKey::KeyType keyType) const {
105+
if (wildcardKeys.empty()) {
106+
return stressTestShifts;
107+
}
108+
auto data = stressTestShifts;
109+
const auto& keys = baseScenarioAbsolute_->keys();
110+
for(const auto& key : keys) {
111+
if (key.keytype == keyType && data.find(key.name) == data.end()) {
112+
for (const auto& wildcardKey : wildcardKeys) {
113+
if (wildcardKey.matches(key.name)) {
114+
data[key.name] = stressTestShifts.at(wildcardKey.pattern());
115+
break;
116+
}
117+
}
118+
}
119+
}
120+
for (const auto& key : wildcardKeys) {
121+
data.erase(key.pattern());
122+
}
123+
return data;
124+
}
125+
84126
void StressScenarioGenerator::addFxShifts(StressTestScenarioData::StressTestData& std,
85127
QuantLib::ext::shared_ptr<Scenario>& scenario) {
86-
for (auto d : std.fxShifts) {
128+
auto& data = std.fxShifts;
129+
auto wildcards = wildcardList(data);
130+
if (wildcards.size() > 0) {
131+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::FXSpot);
132+
}
133+
134+
for (auto d : data) {
87135
string ccypair = d.first; // foreign + domestic;
88136

89137
// Is this too strict?
@@ -122,12 +170,18 @@ void StressScenarioGenerator::addFxShifts(StressTestScenarioData::StressTestData
122170

123171
void StressScenarioGenerator::addEquityShifts(StressTestScenarioData::StressTestData& std,
124172
QuantLib::ext::shared_ptr<Scenario>& scenario) {
125-
for (auto d : std.equityShifts) {
173+
auto& data = std.equityShifts;
174+
auto wildcards = wildcardList(data);
175+
if (wildcards.size() > 0) {
176+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::EquitySpot);
177+
}
178+
179+
for(const auto& d : data) {
126180
string equity = d.first;
127181
StressTestScenarioData::SpotShiftData data = *d.second;
128182
ShiftType type = data.shiftType;
129183
bool relShift = (type == ShiftType::Relative);
130-
// QL_REQUIRE(type == ShiftType::Relative, "FX scenario type must be relative");
184+
// QL_REQUIRE(type == ShiftType::Relative, "EQ scenario type must be relative");
131185
Real size = data.shiftSize;
132186

133187
RiskFactorKey key(RiskFactorKey::KeyType::EquitySpot, equity);
@@ -143,6 +197,11 @@ void StressScenarioGenerator::addEquityShifts(StressTestScenarioData::StressTest
143197
void StressScenarioGenerator::addCommodityCurveShifts(StressTestScenarioData::StressTestData& std,
144198
QuantLib::ext::shared_ptr<Scenario>& scenario) {
145199
Date asof = baseScenario_->asof();
200+
auto& data = std.commodityCurveShifts;
201+
auto wildcards = wildcardList(data);
202+
if (wildcards.size() > 0) {
203+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::CommodityCurve);
204+
}
146205

147206
for (auto d : std.commodityCurveShifts) {
148207
string commodity = d.first;
@@ -199,8 +258,13 @@ void StressScenarioGenerator::addCommodityCurveShifts(StressTestScenarioData::St
199258
void StressScenarioGenerator::addDiscountCurveShifts(StressTestScenarioData::StressTestData& std,
200259
QuantLib::ext::shared_ptr<Scenario>& scenario) {
201260
Date asof = baseScenario_->asof();
261+
auto& data = std.discountCurveShifts;
262+
auto wildcards = wildcardList(data);
263+
if (wildcards.size() > 0) {
264+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::DiscountCurve);
265+
}
202266

203-
for (auto d : std.discountCurveShifts) {
267+
for (auto d : data) {
204268
string ccy = d.first;
205269
TLOG("Apply stress scenario to discount curve " << ccy);
206270

@@ -259,8 +323,13 @@ void StressScenarioGenerator::addDiscountCurveShifts(StressTestScenarioData::Str
259323
void StressScenarioGenerator::addSurvivalProbabilityShifts(StressTestScenarioData::StressTestData& std,
260324
QuantLib::ext::shared_ptr<Scenario>& scenario) {
261325
Date asof = baseScenario_->asof();
326+
auto& data = std.survivalProbabilityShifts;
327+
auto wildcards = wildcardList(data);
328+
if (wildcards.size() > 0) {
329+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::SurvivalProbability);
330+
}
262331

263-
for (auto d : std.survivalProbabilityShifts) {
332+
for(const auto& d : data) {
264333
string name = d.first;
265334
TLOG("Apply stress scenario to " << name);
266335

@@ -319,8 +388,13 @@ void StressScenarioGenerator::addSurvivalProbabilityShifts(StressTestScenarioDat
319388
void StressScenarioGenerator::addIndexCurveShifts(StressTestScenarioData::StressTestData& std,
320389
QuantLib::ext::shared_ptr<Scenario>& scenario) {
321390
Date asof = baseScenario_->asof();
391+
auto& data = std.indexCurveShifts;
392+
auto wildcards = wildcardList(data);
393+
if (wildcards.size() > 0) {
394+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::IndexCurve);
395+
}
322396

323-
for (auto d : std.indexCurveShifts) {
397+
for (auto d : data) {
324398
string indexName = d.first;
325399
TLOG("Apply stress scenario to index curve " << indexName);
326400

@@ -380,8 +454,13 @@ void StressScenarioGenerator::addIndexCurveShifts(StressTestScenarioData::Stress
380454
void StressScenarioGenerator::addYieldCurveShifts(StressTestScenarioData::StressTestData& std,
381455
QuantLib::ext::shared_ptr<Scenario>& scenario) {
382456
Date asof = baseScenario_->asof();
457+
auto& data = std.yieldCurveShifts;
458+
auto wildcards = wildcardList(data);
459+
if (wildcards.size() > 0) {
460+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::YieldCurve);
461+
}
383462

384-
for (auto d : std.yieldCurveShifts) {
463+
for (auto d : data) {
385464
string name = d.first;
386465
TLOG("Apply stress scenario to yield curve " << name);
387466

@@ -445,8 +524,13 @@ void StressScenarioGenerator::addYieldCurveShifts(StressTestScenarioData::Stress
445524
void StressScenarioGenerator::addFxVolShifts(StressTestScenarioData::StressTestData& std,
446525
QuantLib::ext::shared_ptr<Scenario>& scenario) {
447526
Date asof = baseScenario_->asof();
527+
auto& data = std.fxVolShifts;
528+
auto wildcards = wildcardList(data);
529+
if (wildcards.size() > 0) {
530+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::FXVolatility);
531+
}
448532

449-
for (auto d : std.fxVolShifts) {
533+
for (auto d : data) {
450534
string ccypair = d.first;
451535
if(simMarketData_->fxVolIsSurface(ccypair)){
452536
StructuredConfigurationErrorMessage("Simulation Market", "Fx Volatility",
@@ -565,8 +649,13 @@ void StressScenarioGenerator::addFxVolShifts(StressTestScenarioData::StressTestD
565649
void StressScenarioGenerator::addEquityVolShifts(StressTestScenarioData::StressTestData& std,
566650
QuantLib::ext::shared_ptr<Scenario>& scenario) {
567651
Date asof = baseScenario_->asof();
652+
auto& data = std.equityVolShifts;
653+
auto wildcards = wildcardList(data);
654+
if (wildcards.size() > 0) {
655+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::EquityVolatility);
656+
}
568657

569-
for (auto d : std.equityVolShifts) {
658+
for(const auto& d : data) {
570659
string equity = d.first;
571660
TLOG("Apply stress scenario to equity vol structure " << equity);
572661
Size n_eqvol_exp = simMarketData_->equityVolExpiries(equity).size();
@@ -627,8 +716,13 @@ void StressScenarioGenerator::addEquityVolShifts(StressTestScenarioData::StressT
627716
void StressScenarioGenerator::addCommodityVolShifts(StressTestScenarioData::StressTestData& std,
628717
QuantLib::ext::shared_ptr<Scenario>& scenario) {
629718
Date asof = baseScenario_->asof();
719+
auto& data = std.commodityVolShifts;
720+
auto wildcards = wildcardList(data);
721+
if (wildcards.size() > 0) {
722+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::CommodityVolatility);
723+
}
630724

631-
for (auto d : std.commodityVolShifts) {
725+
for (auto d : data) {
632726
string commodity = d.first;
633727
TLOG("Apply stress scenario to commodity vol structure " << commodity);
634728
vector<Period> expiries = simMarketData_->commodityVolExpiries(commodity);
@@ -699,8 +793,13 @@ void StressScenarioGenerator::addCommodityVolShifts(StressTestScenarioData::Stre
699793
void StressScenarioGenerator::addSwaptionVolShifts(StressTestScenarioData::StressTestData& std,
700794
QuantLib::ext::shared_ptr<Scenario>& scenario) {
701795
Date asof = baseScenario_->asof();
796+
auto& data = std.swaptionVolShifts;
797+
auto wildcards = wildcardList(data);
798+
if (wildcards.size() > 0) {
799+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::SwaptionVolatility);
800+
}
702801

703-
for (auto d : std.swaptionVolShifts) {
802+
for (auto d : data) {
704803
std::string key = d.first;
705804
TLOG("Apply stress scenario to swaption vol structure '" << key << "'");
706805

@@ -792,8 +891,13 @@ void StressScenarioGenerator::addSwaptionVolShifts(StressTestScenarioData::Stres
792891
void StressScenarioGenerator::addCapFloorVolShifts(StressTestScenarioData::StressTestData& std,
793892
QuantLib::ext::shared_ptr<Scenario>& scenario) {
794893
Date asof = baseScenario_->asof();
894+
auto& data = std.capVolShifts;
895+
auto wildcards = wildcardList(data);
896+
if (wildcards.size() > 0) {
897+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::OptionletVolatility);
898+
}
795899

796-
for (auto d : std.capVolShifts) {
900+
for (auto d : data) {
797901
std::string key = d.first;
798902
TLOG("Apply stress scenario to cap/floor vol structure " << key);
799903

@@ -879,7 +983,13 @@ void StressScenarioGenerator::addCapFloorVolShifts(StressTestScenarioData::Stres
879983

880984
void StressScenarioGenerator::addSecuritySpreadShifts(StressTestScenarioData::StressTestData& std,
881985
QuantLib::ext::shared_ptr<Scenario>& scenario) {
882-
for (auto d : std.securitySpreadShifts) {
986+
auto& data = std.securitySpreadShifts;
987+
auto wildcards = wildcardList(data);
988+
if (wildcards.size() > 0) {
989+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::SecuritySpread);
990+
}
991+
992+
for(const auto& d : data) {
883993
string bond = d.first;
884994
TLOG("Apply stress scenario to security spread " << bond);
885995
StressTestScenarioData::SpotShiftData data = *d.second;
@@ -899,7 +1009,13 @@ void StressScenarioGenerator::addSecuritySpreadShifts(StressTestScenarioData::St
8991009

9001010
void StressScenarioGenerator::addRecoveryRateShifts(StressTestScenarioData::StressTestData& std,
9011011
QuantLib::ext::shared_ptr<Scenario>& scenario) {
902-
for (auto d : std.recoveryRateShifts) {
1012+
auto& data = std.recoveryRateShifts;
1013+
auto wildcards = wildcardList(data);
1014+
if (wildcards.size() > 0) {
1015+
data = populateShiftData(data, wildcards, RiskFactorKey::KeyType::RecoveryRate);
1016+
}
1017+
1018+
for(const auto& d : data) {
9031019
string isin = d.first;
9041020
TLOG("Apply stress scenario to recovery rate " << isin);
9051021
StressTestScenarioData::SpotShiftData data = *d.second;

OREAnalytics/orea/scenario/stressscenariogenerator.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <orea/scenario/shiftscenariogenerator.hpp>
3030
#include <orea/scenario/stressscenariodata.hpp>
3131
#include <ored/marketdata/market.hpp>
32+
#include <ored/utilities/wildcard.hpp>
3233

3334
namespace ore {
3435
namespace analytics {
@@ -96,6 +97,11 @@ class StressScenarioGenerator : public ShiftScenarioGenerator {
9697
void addRecoveryRateShifts(StressTestScenarioData::StressTestData& data, QuantLib::ext::shared_ptr<Scenario>& scenario);
9798
void addSurvivalProbabilityShifts(StressTestScenarioData::StressTestData& data,
9899
QuantLib::ext::shared_ptr<Scenario>& scenario);
100+
template<class StressTestShifts>
101+
map<string, QuantLib::ext::shared_ptr<StressTestShifts>>
102+
populateShiftData(const map<string, QuantLib::ext::shared_ptr<StressTestShifts>>& stressTestShifts,
103+
const vector<Wildcard>& wildcardKeys,
104+
RiskFactorKey::KeyType keyType) const;
99105

100106
QuantLib::ext::shared_ptr<StressTestScenarioData> stressData_;
101107
QuantLib::ext::shared_ptr<ScenarioFactory> stressScenarioFactory_;

0 commit comments

Comments
 (0)