@@ -27,6 +27,21 @@ using namespace std;
2727namespace ore {
2828namespace 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+
3045StressScenarioGenerator::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+
84126void 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
123171void 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
143197void 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
199258void 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
259323void 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
319388void 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
380454void 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
445524void 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
565649void 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
627716void 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
699793void 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
792891void 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
880984void 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
9001010void 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 ;
0 commit comments