Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes | List of all members
StressScenarioGenerator Class Reference

Stress Scenario Generator. More...

#include <orea/scenario/stressscenariogenerator.hpp>

+ Inheritance diagram for StressScenarioGenerator:
+ Collaboration diagram for StressScenarioGenerator:

Public Member Functions

 StressScenarioGenerator (const QuantLib::ext::shared_ptr< StressTestScenarioData > &stressData, const QuantLib::ext::shared_ptr< Scenario > &baseScenario, const QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > &simMarketData, const QuantLib::ext::shared_ptr< ScenarioSimMarket > &simMarket, const QuantLib::ext::shared_ptr< ScenarioFactory > &stressScenarioFactory, const QuantLib::ext::shared_ptr< Scenario > &baseScenarioAbsolute=nullptr)
 Constructor. More...
 
 ~StressScenarioGenerator ()
 Default destructor. More...
 
- Public Member Functions inherited from ShiftScenarioGenerator
 ShiftScenarioGenerator (const QuantLib::ext::shared_ptr< Scenario > &baseScenario, const QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > &simMarketData, const QuantLib::ext::weak_ptr< ScenarioSimMarket > &simMarket)
 Constructor. More...
 
 ~ShiftScenarioGenerator ()
 Default destructor. More...
 
QuantLib::ext::shared_ptr< Scenarionext (const Date &d) override
 Scenario Generator interface. More...
 
void reset () override
 Reset the generator so calls to next() return the first scenario. More...
 
Size samples ()
 Inspectors. More...
 
const QuantLib::ext::shared_ptr< Scenario > & baseScenario ()
 Return the base scenario, i.e. cached initial values of all relevant market points. More...
 
const std::vector< QuantLib::ext::shared_ptr< Scenario > > & scenarios ()
 Return vector of sensitivity scenarios, scenario 0 is the base scenario. More...
 
std::vector< ScenarioDescriptionscenarioDescriptions ()
 Return vector of scenario descriptions. More...
 
const std::map< RiskFactorKey, std::string > & keyToFactor ()
 
const std::map< std::string, RiskFactorKey > & factorToKey ()
 Return revers map of factors to RiskFactorKeys. More...
 
void applyShift (Size j, Real shiftSize, bool up, ShiftType type, const vector< Time > &shiftTimes, const vector< Real > &values, const vector< Time > &times, vector< Real > &shiftedValues, bool initialise)
 Apply 1d triangular shift to 1d data such as yield curves, public to allow test suite access. More...
 
void applyShift (Size j, Size k, Real shiftSize, bool up, ShiftType type, const vector< Time > &shiftX, const vector< Time > &shiftY, const vector< Time > &dataX, const vector< Time > &dataY, const vector< vector< Real > > &data, vector< vector< Real > > &shiftedData, bool initialise)
 Apply 2d shift to 2d matrix such as swaption volatilities, public to allow test suite access. More...
 
QuantLib::ext::shared_ptr< ScenariobaseScenario () const
 return the base scenario More...
 
- Public Member Functions inherited from ScenarioGenerator
virtual ~ScenarioGenerator ()
 Default destructor. More...
 
virtual QuantLib::ext::shared_ptr< Scenarionext (const Date &d)=0
 Return the next scenario for the given date. More...
 
virtual void reset ()=0
 Reset the generator so calls to next() return the first scenario. More...
 

Private Member Functions

void generateScenarios ()
 
void addFxShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addEquityShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addDiscountCurveShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addIndexCurveShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addYieldCurveShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addFxVolShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addEquityVolShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addSwaptionVolShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addCapFloorVolShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addSecuritySpreadShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addDefaultCurveShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addRecoveryRateShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 
void addSurvivalProbabilityShifts (StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
 

Private Attributes

QuantLib::ext::shared_ptr< StressTestScenarioDatastressData_
 
QuantLib::ext::shared_ptr< ScenarioFactorystressScenarioFactory_
 
QuantLib::ext::shared_ptr< ScenariobaseScenarioAbsolute_
 

Additional Inherited Members

- Protected Attributes inherited from ShiftScenarioGenerator
const QuantLib::ext::shared_ptr< ScenariobaseScenario_
 
const QuantLib::ext::shared_ptr< ScenarioSimMarketParameterssimMarketData_
 
const QuantLib::ext::weak_ptr< ScenarioSimMarketsimMarket_
 
std::vector< QuantLib::ext::shared_ptr< Scenario > > scenarios_
 
Size counter_
 
std::vector< ScenarioDescriptionscenarioDescriptions_
 
std::map< RiskFactorKey, std::string > keyToFactor_
 
std::map< std::string, RiskFactorKeyfactorToKey_
 

Detailed Description

Stress Scenario Generator.

This class builds a vector of stress scenarios based on instructions in StressScenarioData and ScenarioSimMarketParameters objects passed.

The ScenarioSimMarketParameters object determines the scope and structure of a "simulation" market (currencies, currency pairs, curve tenor points, vol matrix expiries and terms/strikes etc) to which sensitivity scenarios are applied in order to compute their NPV impact.

The StressScenarioData object determines the structure of shift curves (shift tenor points can differ from the simulation market's tenor points), as well as type (relative/absolute) and size of shifts applied.

The generator then produces comprehensive scenarios that can be applied to the simulation market, i.e. covering all quotes in the simulation market, possibly filled with "base" scenario values.

The generator currently covers the IR/FX asset class, with shifts for the following term structure types:

Note:

Definition at line 69 of file stressscenariogenerator.hpp.

Constructor & Destructor Documentation

◆ StressScenarioGenerator()

StressScenarioGenerator ( const QuantLib::ext::shared_ptr< StressTestScenarioData > &  stressData,
const QuantLib::ext::shared_ptr< Scenario > &  baseScenario,
const QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > &  simMarketData,
const QuantLib::ext::shared_ptr< ScenarioSimMarket > &  simMarket,
const QuantLib::ext::shared_ptr< ScenarioFactory > &  stressScenarioFactory,
const QuantLib::ext::shared_ptr< Scenario > &  baseScenarioAbsolute = nullptr 
)

Constructor.

Definition at line 30 of file stressscenariogenerator.cpp.

36 : ShiftScenarioGenerator(baseScenario, simMarketData, simMarket), stressData_(stressData),
37 stressScenarioFactory_(stressScenarioFactory),
38 baseScenarioAbsolute_(baseScenarioAbsolute == nullptr ? baseScenario : baseScenarioAbsolute) {
39
40 QL_REQUIRE(stressData_, "StressScenarioGenerator: stressData is null");
41
43}
ShiftScenarioGenerator(const QuantLib::ext::shared_ptr< Scenario > &baseScenario, const QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > &simMarketData, const QuantLib::ext::weak_ptr< ScenarioSimMarket > &simMarket)
Constructor.
const QuantLib::ext::shared_ptr< Scenario > & baseScenario()
Return the base scenario, i.e. cached initial values of all relevant market points.
QuantLib::ext::shared_ptr< Scenario > baseScenarioAbsolute_
QuantLib::ext::shared_ptr< ScenarioFactory > stressScenarioFactory_
QuantLib::ext::shared_ptr< StressTestScenarioData > stressData_
+ Here is the call graph for this function:

◆ ~StressScenarioGenerator()

Default destructor.

Definition at line 79 of file stressscenariogenerator.hpp.

79{}

Member Function Documentation

◆ generateScenarios()

void generateScenarios ( )
private

Definition at line 45 of file stressscenariogenerator.cpp.

45 {
46 Date asof = baseScenario_->asof();
47 for (Size i = 0; i < stressData_->data().size(); ++i) {
48 StressTestScenarioData::StressTestData data = stressData_->data().at(i);
49 DLOG("Generate stress scenario #" << i << " '" << data.label << "'");
50 QuantLib::ext::shared_ptr<Scenario> scenario =
51 stressScenarioFactory_->buildScenario(asof, !stressData_->useSpreadedTermStructures(), data.label);
52
53 if (simMarketData_->simulateFxSpots())
54 addFxShifts(data, scenario);
55 addEquityShifts(data, scenario);
56 addDiscountCurveShifts(data, scenario);
57 addIndexCurveShifts(data, scenario);
58 addYieldCurveShifts(data, scenario);
59 if (simMarketData_->simulateFXVols())
60 addFxVolShifts(data, scenario);
61 if (simMarketData_->simulateEquityVols())
62 addEquityVolShifts(data, scenario);
63 if (simMarketData_->simulateSwapVols())
64 addSwaptionVolShifts(data, scenario);
65 if (simMarketData_->simulateCapFloorVols())
66 addCapFloorVolShifts(data, scenario);
67 if (simMarketData_->securitySpreadsSimulate())
68 addSecuritySpreadShifts(data, scenario);
69 if (simMarketData_->simulateRecoveryRates())
70 addRecoveryRateShifts(data, scenario);
71 if (simMarketData_->simulateSurvivalProbabilities())
72 addSurvivalProbabilityShifts(data, scenario);
73
74 scenarios_.push_back(scenario);
75 }
76
77 DLOG("stress scenario generator: all scenarios generated.");
78}
std::vector< QuantLib::ext::shared_ptr< Scenario > > scenarios_
const QuantLib::ext::shared_ptr< Scenario > baseScenario_
const QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > simMarketData_
void addCapFloorVolShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addFxVolShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addSwaptionVolShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addDiscountCurveShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addIndexCurveShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addYieldCurveShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addEquityShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addEquityVolShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addSecuritySpreadShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addRecoveryRateShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addSurvivalProbabilityShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
void addFxShifts(StressTestScenarioData::StressTestData &data, QuantLib::ext::shared_ptr< Scenario > &scenario)
data
#define DLOG(text)
Size size(const ValueType &v)
Date asof(14, Jun, 2018)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addFxShifts()

void addFxShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 80 of file stressscenariogenerator.cpp.

81 {
82 for (auto d : std.fxShifts) {
83 string ccypair = d.first; // foreign + domestic;
84
85 // Is this too strict?
86 // - implemented to avoid cases where input cross FX rates are not consistent
87 // - Consider an example (baseCcy = EUR) of a GBPUSD FX trade - two separate routes to pricing
88 // - (a) call GBPUSD FX rate from sim market
89 // - (b) call GBPEUR and EURUSD FX rates, manually join them to obtain GBPUSD
90 // - now, if GBPUSD is an explicit risk factor in sim market, consider what happens
91 // - if we bump GBPUSD value and leave other FX rates unchanged (for e.g. a sensitivity analysis)
92 // - (a) the value of the trade changes
93 // - (b) the value of the GBPUSD trade stays the same
94 // in light of the above we restrict the universe of FX pairs that we support here for the time being
95 string baseCcy = simMarketData_->baseCcy();
96 string foreign = ccypair.substr(0, 3);
97 string domestic = ccypair.substr(3);
98 QL_REQUIRE((domestic == baseCcy) || (foreign == baseCcy),
99 "SensitivityScenarioGenerator does not support cross FX pairs("
100 << ccypair << ", but base currency is " << baseCcy << ")");
101
102 TLOG("Apply stress scenario to fx " << ccypair);
103
104 StressTestScenarioData::SpotShiftData data = d.second;
105 ShiftType type = data.shiftType;
106 bool relShift = (type == ShiftType::Relative);
107 // QL_REQUIRE(type == ShiftType::Relative, "FX scenario type must be relative");
108 Real size = data.shiftSize;
109
110 RiskFactorKey key(RiskFactorKey::KeyType::FXSpot, ccypair);
111 Real rate = scenario->get(key);
112 Real newRate = relShift ? rate * (1.0 + size) : (rate + size);
113 scenario->add(RiskFactorKey(RiskFactorKey::KeyType::FXSpot, ccypair),
114 stressData_->useSpreadedTermStructures() ? newRate / rate : newRate);
115 }
116 DLOG("FX scenarios done");
117}
#define TLOG(text)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addEquityShifts()

void addEquityShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 119 of file stressscenariogenerator.cpp.

120 {
121 for (auto d : std.equityShifts) {
122 string equity = d.first;
123 StressTestScenarioData::SpotShiftData data = d.second;
124 ShiftType type = data.shiftType;
125 bool relShift = (type == ShiftType::Relative);
126 // QL_REQUIRE(type == ShiftType::Relative, "FX scenario type must be relative");
127 Real size = data.shiftSize;
128
129 RiskFactorKey key(RiskFactorKey::KeyType::EquitySpot, equity);
130 Real rate = baseScenarioAbsolute_->get(key);
131
132 Real newRate = relShift ? rate * (1.0 + size) : (rate + size);
133 scenario->add(RiskFactorKey(RiskFactorKey::KeyType::EquitySpot, equity),
134 stressData_->useSpreadedTermStructures() ? newRate / rate : newRate);
135 }
136 DLOG("Equity scenarios done");
137}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addDiscountCurveShifts()

void addDiscountCurveShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 139 of file stressscenariogenerator.cpp.

140 {
141 Date asof = baseScenario_->asof();
142
143 for (auto d : std.discountCurveShifts) {
144 string ccy = d.first;
145 TLOG("Apply stress scenario to discount curve " << ccy);
146
147 Size n_ten = simMarketData_->yieldCurveTenors(ccy).size();
148 // original curves' buffer
149 std::vector<Real> zeros(n_ten);
150 std::vector<Real> times(n_ten);
151 // buffer for shifted zero curves
152 std::vector<Real> shiftedZeros(n_ten);
153
154 StressTestScenarioData::CurveShiftData data = d.second;
155 ShiftType shiftType = data.shiftType;
156 //DayCounter dc = parseDayCounter(simMarketData_->yieldCurveDayCounter(ccy));
157 DayCounter dc;
158 if(auto s = simMarket_.lock()) {
159 dc = s->discountCurve(ccy)->dayCounter();
160 } else {
161 QL_FAIL("Internal error: could not lock simMarket. Contact dev.");
162 }
163
164 for (Size j = 0; j < n_ten; ++j) {
165 Date d = asof + simMarketData_->yieldCurveTenors(ccy)[j];
166 times[j] = dc.yearFraction(asof, d);
167 RiskFactorKey key(RiskFactorKey::KeyType::DiscountCurve, ccy, j);
168 Real quote = baseScenarioAbsolute_->get(key);
169 zeros[j] = -std::log(quote) / times[j];
170 }
171
172 std::vector<Period> shiftTenors = data.shiftTenors;
173 QL_REQUIRE(shiftTenors.size() > 0, "Discount shift tenors not specified");
174 std::vector<Real> shifts = data.shifts;
175 QL_REQUIRE(shiftTenors.size() == shifts.size(), "shift tenor and shift size vectors do not match");
176 std::vector<Time> shiftTimes(shiftTenors.size());
177 for (Size j = 0; j < shiftTenors.size(); ++j)
178 shiftTimes[j] = dc.yearFraction(asof, asof + shiftTenors[j]);
179
180 // apply zero rate shift at tenor point j
181 for (Size j = 0; j < shiftTenors.size(); ++j)
182 applyShift(j, shifts[j], true, shiftType, shiftTimes, zeros, times, shiftedZeros, j == 0 ? true : false);
183
184 // store shifted discount curve in the scenario
185 for (Size k = 0; k < n_ten; ++k) {
186 RiskFactorKey key(RiskFactorKey::KeyType::DiscountCurve, ccy, k);
187 Real shiftedDiscount = exp(-shiftedZeros[k] * times[k]);
188 if (stressData_->useSpreadedTermStructures()) {
189 Real discount = exp(-zeros[k] * times[k]);
190 scenario->add(key, shiftedDiscount / discount);
191 } else {
192 scenario->add(key, shiftedDiscount);
193 }
194 }
195 }
196 DLOG("Discount curve stress scenarios done");
197}
void applyShift(Size j, Real shiftSize, bool up, ShiftType type, const vector< Time > &shiftTimes, const vector< Real > &values, const vector< Time > &times, vector< Real > &shiftedValues, bool initialise)
Apply 1d triangular shift to 1d data such as yield curves, public to allow test suite access.
const QuantLib::ext::weak_ptr< ScenarioSimMarket > simMarket_
RandomVariable exp(RandomVariable x)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addIndexCurveShifts()

void addIndexCurveShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 259 of file stressscenariogenerator.cpp.

260 {
261 Date asof = baseScenario_->asof();
262
263 for (auto d : std.indexCurveShifts) {
264 string indexName = d.first;
265 TLOG("Apply stress scenario to index curve " << indexName);
266
267 Size n_ten = simMarketData_->yieldCurveTenors(indexName).size();
268
269 // original curves' buffer
270 std::vector<Real> zeros(n_ten);
271 std::vector<Real> times(n_ten);
272
273 // buffer for shifted zero curves
274 std::vector<Real> shiftedZeros(n_ten);
275
276 StressTestScenarioData::CurveShiftData data = d.second;
277 ShiftType shiftType = data.shiftType;
278 //DayCounter dc = parseDayCounter(simMarketData_->yieldCurveDayCounter(indexName));
279 DayCounter dc;
280 if(auto s = simMarket_.lock()) {
281 dc = s->iborIndex(indexName)->forwardingTermStructure()->dayCounter();
282 } else {
283 QL_FAIL("Internal error: could not lock simMarket. Contact dev.");
284 }
285
286 for (Size j = 0; j < n_ten; ++j) {
287 Date d = asof + simMarketData_->yieldCurveTenors(indexName)[j];
288 times[j] = dc.yearFraction(asof, d);
289 RiskFactorKey key(RiskFactorKey::KeyType::IndexCurve, indexName, j);
290 Real quote = baseScenarioAbsolute_->get(key);
291 zeros[j] = -std::log(quote) / times[j];
292 }
293
294 std::vector<Period> shiftTenors = data.shiftTenors;
295 QL_REQUIRE(shiftTenors.size() > 0, "Index curve shift tenors not specified");
296 std::vector<Real> shifts = data.shifts;
297 QL_REQUIRE(shiftTenors.size() == shifts.size(), "shift tenor and shift size vectors do not match");
298 std::vector<Time> shiftTimes(shiftTenors.size());
299 for (Size j = 0; j < shiftTenors.size(); ++j)
300 shiftTimes[j] = dc.yearFraction(asof, asof + shiftTenors[j]);
301
302 for (Size j = 0; j < shiftTenors.size(); ++j)
303 applyShift(j, shifts[j], true, shiftType, shiftTimes, zeros, times, shiftedZeros, j == 0 ? true : false);
304
305 // store shifted discount curve for this index in the scenario
306 for (Size k = 0; k < n_ten; ++k) {
307 RiskFactorKey key(RiskFactorKey::KeyType::IndexCurve, indexName, k);
308 Real shiftedDiscount = exp(-shiftedZeros[k] * times[k]);
309 if (stressData_->useSpreadedTermStructures()) {
310 Real discount = exp(-zeros[k] * times[k]);
311 scenario->add(key, shiftedDiscount / discount);
312 } else {
313 scenario->add(key, shiftedDiscount);
314 }
315 }
316 }
317 DLOG("Index curve scenarios done");
318}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addYieldCurveShifts()

void addYieldCurveShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 320 of file stressscenariogenerator.cpp.

321 {
322 Date asof = baseScenario_->asof();
323
324 for (auto d : std.yieldCurveShifts) {
325 string name = d.first;
326 TLOG("Apply stress scenario to yield curve " << name);
327
328 Size n_ten = simMarketData_->yieldCurveTenors(name).size();
329
330 // original curves' buffer
331 std::vector<Real> zeros(n_ten);
332 std::vector<Real> times(n_ten);
333
334 // buffer for shifted zero curves
335 std::vector<Real> shiftedZeros(n_ten);
336
337 StressTestScenarioData::CurveShiftData data = d.second;
338 ShiftType shiftType = data.shiftType;
339 //DayCounter dc = parseDayCounter(simMarketData_->yieldCurveDayCounter(name));
340 DayCounter dc;
341 if(auto s = simMarket_.lock()) {
342 dc = s->yieldCurve(name)->dayCounter();
343 } else {
344 QL_FAIL("Internal error: could not lock simMarket. Contact dev.");
345 }
346
347 for (Size j = 0; j < n_ten; ++j) {
348 Date d = asof + simMarketData_->yieldCurveTenors(name)[j];
349 times[j] = dc.yearFraction(asof, d);
350 RiskFactorKey key(RiskFactorKey::KeyType::YieldCurve, name, j);
351 Real quote = baseScenarioAbsolute_->get(key);
352 zeros[j] = -std::log(quote) / times[j];
353 }
354
355 std::vector<Period> shiftTenors = data.shiftTenors;
356 QL_REQUIRE(shiftTenors.size() > 0, "Yield curve shift tenors not specified");
357 std::vector<Real> shifts = data.shifts;
358 QL_REQUIRE(shiftTenors.size() == shifts.size(), "shift tenor and shift size vectors do not match");
359 std::vector<Time> shiftTimes(shiftTenors.size());
360 for (Size j = 0; j < shiftTenors.size(); ++j)
361 shiftTimes[j] = dc.yearFraction(asof, asof + shiftTenors[j]);
362
363 for (Size j = 0; j < shiftTenors.size(); ++j) {
364 // DLOG("apply yield curve shift " << shifts[j] << " to curve " << name << " at tenor " << shiftTenors[j]
365 // << ", time " << shiftTimes[j]);
366 // apply zero rate shift at tenor point j
367 applyShift(j, shifts[j], true, shiftType, shiftTimes, zeros, times, shiftedZeros, j == 0 ? true : false);
368 }
369
370 // store shifted discount curve in the scenario
371 for (Size k = 0; k < n_ten; ++k) {
372 RiskFactorKey key(RiskFactorKey::KeyType::YieldCurve, name, k);
373 Real shiftedDiscount = exp(-shiftedZeros[k] * times[k]);
374 if (stressData_->useSpreadedTermStructures()) {
375 Real discount = exp(-zeros[k] * times[k]);
376 scenario->add(key, shiftedDiscount / discount);
377 } else {
378 scenario->add(key, shiftedDiscount);
379 }
380 }
381 } // end of shift curve tenors
382 DLOG("Yield curve scenarios done");
383}
string name
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addFxVolShifts()

void addFxVolShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 385 of file stressscenariogenerator.cpp.

386 {
387 Date asof = baseScenario_->asof();
388
389 for (auto d : std.fxVolShifts) {
390 string ccypair = d.first;
391 TLOG("Apply stress scenario to fx vol structure " << ccypair);
392
393 Size n_fxvol_exp = simMarketData_->fxVolExpiries(ccypair).size();
394
395 std::vector<Real> values(n_fxvol_exp);
396 std::vector<Real> times(n_fxvol_exp);
397
398 // buffer for shifted zero curves
399 std::vector<Real> shiftedValues(n_fxvol_exp);
400
401 StressTestScenarioData::VolShiftData data = d.second;
402
403 //DayCounter dc = parseDayCounter(simMarketData_->fxVolDayCounter(ccypair));
404 DayCounter dc;
405 if (auto s = simMarket_.lock()) {
406 dc = s->fxVol(ccypair)->dayCounter();
407 } else {
408 QL_FAIL("Internal error: could not lock simMarket. Contact dev.");
409 }
410 for (Size j = 0; j < n_fxvol_exp; ++j) {
411 Date d = asof + simMarketData_->fxVolExpiries(ccypair)[j];
412
413 RiskFactorKey key(RiskFactorKey::KeyType::FXVolatility, ccypair, j);
414 values[j] = baseScenarioAbsolute_->get(key);
415
416 times[j] = dc.yearFraction(asof, d);
417 }
418
419 ShiftType shiftType = data.shiftType;
420 std::vector<Period> shiftTenors = data.shiftExpiries;
421 std::vector<Time> shiftTimes(shiftTenors.size());
422 vector<Real> shifts = data.shifts;
423 QL_REQUIRE(shiftTenors.size() > 0, "FX vol shift tenors not specified");
424 QL_REQUIRE(shiftTenors.size() == shifts.size(), "shift tenor and shift size vectors do not match");
425
426 for (Size j = 0; j < shiftTenors.size(); ++j)
427 shiftTimes[j] = dc.yearFraction(asof, asof + shiftTenors[j]);
428
429 // FIXME: Apply same shifts to non-ATM vectors if present
430 for (Size j = 0; j < shiftTenors.size(); ++j) {
431 // apply shift at tenor point j
432 applyShift(j, shifts[j], true, shiftType, shiftTimes, values, times, shiftedValues, j == 0 ? true : false);
433 }
434
435 for (Size k = 0; k < n_fxvol_exp; ++k) {
436 RiskFactorKey key(RiskFactorKey::KeyType::FXVolatility, ccypair, k);
437 if (stressData_->useSpreadedTermStructures()) {
438 scenario->add(key, shiftedValues[k] - values[k]);
439 } else {
440 scenario->add(key, shiftedValues[k]);
441 }
442 }
443 }
444 DLOG("FX vol scenarios done");
445}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addEquityVolShifts()

void addEquityVolShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 447 of file stressscenariogenerator.cpp.

448 {
449 Date asof = baseScenario_->asof();
450
451 for (auto d : std.equityVolShifts) {
452 string equity = d.first;
453 TLOG("Apply stress scenario to equity vol structure " << equity);
454 Size n_eqvol_exp = simMarketData_->equityVolExpiries(equity).size();
455
456 std::vector<Real> values(n_eqvol_exp);
457 std::vector<Real> times(n_eqvol_exp);
458
459 // buffer for shifted zero curves
460 std::vector<Real> shiftedValues(n_eqvol_exp);
461
462 StressTestScenarioData::VolShiftData data = d.second;
463
464 //DayCounter dc = parseDayCounter(simMarketData_->equityVolDayCounter(equity));
465 DayCounter dc;
466 if(auto s = simMarket_.lock()) {
467 dc = s->equityVol(equity)->dayCounter();
468 } else {
469 QL_FAIL("Internal error: could not lock simMarket. Contact dev.");
470 }
471 for (Size j = 0; j < n_eqvol_exp; ++j) {
472 Date d = asof + simMarketData_->equityVolExpiries(equity)[j];
473
474 RiskFactorKey key(RiskFactorKey::KeyType::EquityVolatility, equity, j);
475 values[j] = baseScenarioAbsolute_->get(key);
476
477 times[j] = dc.yearFraction(asof, d);
478 }
479
480 ShiftType shiftType = data.shiftType;
481 std::vector<Period> shiftTenors = data.shiftExpiries;
482 std::vector<Time> shiftTimes(shiftTenors.size());
483 vector<Real> shifts = data.shifts;
484 QL_REQUIRE(shiftTenors.size() > 0, "Equity vol shift tenors not specified");
485 QL_REQUIRE(shiftTenors.size() == shifts.size(), "shift tenor and shift size vectors do not match");
486
487 for (Size j = 0; j < shiftTenors.size(); ++j)
488 shiftTimes[j] = dc.yearFraction(asof, asof + shiftTenors[j]);
489
490 // FIXME: Apply same shifts to non-ATM vectors if present
491 for (Size j = 0; j < shiftTenors.size(); ++j) {
492 // apply shift at tenor point j
493 applyShift(j, shifts[j], true, shiftType, shiftTimes, values, times, shiftedValues, j == 0 ? true : false);
494 }
495
496 for (Size k = 0; k < n_eqvol_exp; ++k) {
497 RiskFactorKey key(RiskFactorKey::KeyType::EquityVolatility, equity, k);
498 if (stressData_->useSpreadedTermStructures()) {
499 scenario->add(key, shiftedValues[k] - values[k]);
500 } else {
501 scenario->add(key, shiftedValues[k]);
502 }
503 }
504 }
505 DLOG("Equity vol scenarios done");
506}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addSwaptionVolShifts()

void addSwaptionVolShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 508 of file stressscenariogenerator.cpp.

509 {
510 Date asof = baseScenario_->asof();
511
512 for (auto d : std.swaptionVolShifts) {
513 std::string key = d.first;
514 TLOG("Apply stress scenario to swaption vol structure '" << key << "'");
515
516 Size n_swvol_term = simMarketData_->swapVolTerms(key).size();
517 Size n_swvol_exp = simMarketData_->swapVolExpiries(key).size();
518
519 vector<vector<Real>> volData(n_swvol_exp, vector<Real>(n_swvol_term, 0.0));
520 vector<Real> volExpiryTimes(n_swvol_exp, 0.0);
521 vector<Real> volTermTimes(n_swvol_term, 0.0);
522 vector<vector<Real>> shiftedVolData(n_swvol_exp, vector<Real>(n_swvol_term, 0.0));
523
524 StressTestScenarioData::SwaptionVolShiftData data = d.second;
525 ShiftType shiftType = data.shiftType;
526 map<pair<Period, Period>, Real> shifts = data.shifts;
527
528 vector<Real> shiftExpiryTimes(data.shiftExpiries.size(), 0.0);
529 vector<Real> shiftTermTimes(data.shiftTerms.size(), 0.0);
530
531 DayCounter dc;
532 if(auto s = simMarket_.lock()) {
533 dc = s->swaptionVol(key)->dayCounter();
534 } else {
535 QL_FAIL("Internal error: could not lock simMarket. Contact dev.");
536 }
537
538 // cache original vol data
539 for (Size j = 0; j < n_swvol_exp; ++j) {
540 Date expiry = asof + simMarketData_->swapVolExpiries(key)[j];
541 volExpiryTimes[j] = dc.yearFraction(asof, expiry);
542 }
543 for (Size j = 0; j < n_swvol_term; ++j) {
544 Date term = asof + simMarketData_->swapVolTerms(key)[j];
545 volTermTimes[j] = dc.yearFraction(asof, term);
546 }
547 for (Size j = 0; j < n_swvol_exp; ++j) {
548 for (Size k = 0; k < n_swvol_term; ++k) {
549 Size idx = j * n_swvol_term + k;
550
551 RiskFactorKey rf(RiskFactorKey::KeyType::SwaptionVolatility, key, idx);
552 volData[j][k] = baseScenarioAbsolute_->get(rf);
553 }
554 }
555
556 // cache tenor times
557 for (Size j = 0; j < shiftExpiryTimes.size(); ++j)
558 shiftExpiryTimes[j] = dc.yearFraction(asof, asof + data.shiftExpiries[j]);
559 for (Size j = 0; j < shiftTermTimes.size(); ++j)
560 shiftTermTimes[j] = dc.yearFraction(asof, asof + data.shiftTerms[j]);
561
562 // loop over shift expiries and terms
563 // FIXME: apply same shifts to all strikes when present
564 for (Size j = 0; j < shiftExpiryTimes.size(); ++j) {
565 for (Size k = 0; k < shiftTermTimes.size(); ++k) {
566 // Size strikeBucket = 0; // FIXME
567 Real shift = 0.0;
568 pair<Period, Period> key(data.shiftExpiries[j], data.shiftTerms[k]);
569 if (shifts.size() == 0)
570 shift = data.parallelShiftSize;
571 else {
572 QL_REQUIRE(shifts.find(key) != shifts.end(), "swaption vol shift not found for expiry "
573 << data.shiftExpiries[j] << " and term "
574 << data.shiftTerms[k]);
575 shift = shifts[key];
576 }
577 applyShift(j, k, shift, true, shiftType, shiftExpiryTimes, shiftTermTimes, volExpiryTimes, volTermTimes,
578 volData, shiftedVolData, j == 0 && k == 0);
579 }
580 }
581
582 // add shifted vol data to the scenario
583 for (Size jj = 0; jj < n_swvol_exp; ++jj) {
584 for (Size kk = 0; kk < n_swvol_term; ++kk) {
585 Size idx = jj * n_swvol_term + kk;
586 RiskFactorKey rfkey(RiskFactorKey::KeyType::SwaptionVolatility, key, idx);
587 if (stressData_->useSpreadedTermStructures()) {
588 scenario->add(rfkey, shiftedVolData[jj][kk] - volData[jj][kk]);
589 } else {
590 scenario->add(rfkey, shiftedVolData[jj][kk]);
591 }
592 }
593 }
594 }
595 DLOG("Swaption vol scenarios done");
596}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addCapFloorVolShifts()

void addCapFloorVolShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 598 of file stressscenariogenerator.cpp.

599 {
600 Date asof = baseScenario_->asof();
601
602 for (auto d : std.capVolShifts) {
603 std::string key = d.first;
604 TLOG("Apply stress scenario to cap/floor vol structure " << key);
605
606 vector<Real> volStrikes = simMarketData_->capFloorVolStrikes(key);
607 // Strikes may be empty which indicates that the optionlet structure in the simulation market is an ATM curve
608 if (volStrikes.empty()) {
609 volStrikes = {0.0};
610 }
611 Size n_cfvol_strikes = volStrikes.size();
612
613 Size n_cfvol_exp = simMarketData_->capFloorVolExpiries(key).size();
614 vector<vector<Real>> volData(n_cfvol_exp, vector<Real>(n_cfvol_strikes, 0.0));
615 vector<Real> volExpiryTimes(n_cfvol_exp, 0.0);
616 vector<vector<Real>> shiftedVolData(n_cfvol_exp, vector<Real>(n_cfvol_strikes, 0.0));
617
618 StressTestScenarioData::CapFloorVolShiftData data = d.second;
619
620 ShiftType shiftType = data.shiftType;
621
622 vector<Real> shiftExpiryTimes(data.shiftExpiries.size(), 0.0);
623 vector<Real> shiftStrikes = data.shiftStrikes.empty() ? volStrikes : data.shiftStrikes;
624
625 vector<vector<Real>> shifts;
626 for (size_t i = 0; i < data.shiftExpiries.size(); ++i) {
627 const auto tenor = data.shiftExpiries[i];
628 if (data.shiftStrikes.empty()){
629 const double shift = data.shifts[tenor].front();
630 shifts.push_back(std::vector<Real>(volStrikes.size(), shift));
631 } else{
632 shifts.push_back(data.shifts[tenor]);
633 }
634 }
635
636 // DayCounter dc = parseDayCounter(simMarketData_->capFloorVolDayCounter(key));
637 DayCounter dc;
638 if (auto s = simMarket_.lock()) {
639 dc = s->capFloorVol(key)->dayCounter();
640 } else {
641 QL_FAIL("Internal error: could not lock simMarket. Contact dev.");
642 }
643
644 // cache original vol data
645 for (Size j = 0; j < n_cfvol_exp; ++j) {
646 Date expiry = asof + simMarketData_->capFloorVolExpiries(key)[j];
647 volExpiryTimes[j] = dc.yearFraction(asof, expiry);
648 }
649 for (Size j = 0; j < n_cfvol_exp; ++j) {
650 for (Size k = 0; k < n_cfvol_strikes; ++k) {
651 Size idx = j * n_cfvol_strikes + k;
652 volData[j][k] =
654 }
655 }
656
657 // cache tenor times
658 for (Size j = 0; j < shiftExpiryTimes.size(); ++j)
659 shiftExpiryTimes[j] = dc.yearFraction(asof, asof + data.shiftExpiries[j]);
660
661 // loop over shift expiries, apply same shifts across all strikes
662
663 for (Size j = 0; j < shiftExpiryTimes.size(); ++j) {
664 for (Size k = 0; k < shiftStrikes.size(); ++k) {
665 applyShift(j, k, shifts[j][k], true, shiftType, shiftExpiryTimes, shiftStrikes, volExpiryTimes, volStrikes,
666 volData, shiftedVolData, j == 0 && k == 0);
667 }
668 }
669
670 // add shifted vol data to the scenario
671 for (Size jj = 0; jj < n_cfvol_exp; ++jj) {
672 for (Size kk = 0; kk < n_cfvol_strikes; ++kk) {
673 Size idx = jj * n_cfvol_strikes + kk;
674 RiskFactorKey rfkey(RiskFactorKey::KeyType::OptionletVolatility, key, idx);
675 if (stressData_->useSpreadedTermStructures()) {
676 scenario->add(rfkey, shiftedVolData[jj][kk] - volData[jj][kk]);
677 } else {
678 scenario->add(rfkey, shiftedVolData[jj][kk]);
679 }
680 }
681 }
682 }
683 DLOG("Optionlet vol scenarios done");
684}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addSecuritySpreadShifts()

void addSecuritySpreadShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 686 of file stressscenariogenerator.cpp.

687 {
688 for (auto d : std.securitySpreadShifts) {
689 string bond = d.first;
690 TLOG("Apply stress scenario to security spread " << bond);
691 StressTestScenarioData::SpotShiftData data = d.second;
692 ShiftType type = data.shiftType;
693 bool relShift = (type == ShiftType::Relative);
694 Real size = data.shiftSize;
695
696 RiskFactorKey key(RiskFactorKey::KeyType::SecuritySpread, bond);
697 Real base_spread = baseScenarioAbsolute_->get(key);
698
699 Real newSpread = relShift ? base_spread * (1.0 + size) : (base_spread + size);
700 scenario->add(RiskFactorKey(RiskFactorKey::KeyType::SecuritySpread, bond),
701 stressData_->useSpreadedTermStructures() ? newSpread - base_spread : newSpread);
702 }
703 DLOG("Security spread scenarios done");
704}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addDefaultCurveShifts()

void addDefaultCurveShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

◆ addRecoveryRateShifts()

void addRecoveryRateShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 706 of file stressscenariogenerator.cpp.

707 {
708 for (auto d : std.recoveryRateShifts) {
709 string isin = d.first;
710 TLOG("Apply stress scenario to recovery rate " << isin);
711 StressTestScenarioData::SpotShiftData data = d.second;
712 ShiftType type = data.shiftType;
713 bool relShift = (type == ShiftType::Relative);
714 Real size = data.shiftSize;
715
716 RiskFactorKey key(RiskFactorKey::KeyType::RecoveryRate, isin);
717 Real base_recoveryRate = baseScenarioAbsolute_->get(key);
718 Real new_recoveryRate = relShift ? base_recoveryRate * (1.0 + size) : (base_recoveryRate + size);
719 scenario->add(RiskFactorKey(RiskFactorKey::KeyType::RecoveryRate, isin),
720 stressData_->useSpreadedTermStructures() ? new_recoveryRate - base_recoveryRate
721 : new_recoveryRate);
722 }
723 DLOG("Recovery rate scenarios done");
724}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addSurvivalProbabilityShifts()

void addSurvivalProbabilityShifts ( StressTestScenarioData::StressTestData data,
QuantLib::ext::shared_ptr< Scenario > &  scenario 
)
private

Definition at line 199 of file stressscenariogenerator.cpp.

200 {
201 Date asof = baseScenario_->asof();
202
203 for (auto d : std.survivalProbabilityShifts) {
204 string name = d.first;
205 TLOG("Apply stress scenario to " << name);
206
207 Size n_ten = simMarketData_->defaultTenors(name).size();
208 // original curves' buffer
209 std::vector<Real> zeros(n_ten);
210 std::vector<Real> times(n_ten);
211 // buffer for shifted zero curves
212 std::vector<Real> shiftedZeros(n_ten);
213
214 StressTestScenarioData::CurveShiftData data = d.second;
215 ShiftType shiftType = data.shiftType;
216 //DayCounter dc = parseDayCounter(simMarketData_->defaultCurveDayCounter(name));
217 DayCounter dc;
218 if(auto s = simMarket_.lock()) {
219 dc = s->defaultCurve(name)->curve()->dayCounter();
220 } else {
221 QL_FAIL("Internal error: could not lock simMarket. Contact dev.");
222 }
223
224 for (Size j = 0; j < n_ten; ++j) {
225 Date d = asof + simMarketData_->defaultTenors(name)[j];
226 times[j] = dc.yearFraction(asof, d);
227 RiskFactorKey key(RiskFactorKey::KeyType::SurvivalProbability, name, j);
228 Real quote = baseScenarioAbsolute_->get(key);
229 zeros[j] = -std::log(quote) / times[j];
230 }
231
232 std::vector<Period> shiftTenors = data.shiftTenors;
233 QL_REQUIRE(shiftTenors.size() > 0, "Survival Probability shift tenors not specified");
234 std::vector<Real> shifts = data.shifts;
235 QL_REQUIRE(shiftTenors.size() == shifts.size(), "shift tenor and shift size vectors do not match");
236 std::vector<Time> shiftTimes(shiftTenors.size());
237 for (Size j = 0; j < shiftTenors.size(); ++j)
238 shiftTimes[j] = dc.yearFraction(asof, asof + shiftTenors[j]);
239
240 // apply zero rate shift at tenor point j
241 for (Size j = 0; j < shiftTenors.size(); ++j)
242 applyShift(j, shifts[j], true, shiftType, shiftTimes, zeros, times, shiftedZeros, j == 0 ? true : false);
243
244 // store shifted discount curve in the scenario
245 for (Size k = 0; k < n_ten; ++k) {
246 RiskFactorKey key(RiskFactorKey::KeyType::SurvivalProbability, name, k);
247 Real shiftedSurvivalProbability = exp(-shiftedZeros[k] * times[k]);
248 if (stressData_->useSpreadedTermStructures()) {
249 Real survivalProbability = exp(-zeros[k] * times[k]);
250 scenario->add(key, shiftedSurvivalProbability / survivalProbability);
251 } else {
252 scenario->add(key, shiftedSurvivalProbability);
253 }
254 }
255 }
256 DLOG("Default Curve stress scenarios done");
257}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ stressData_

QuantLib::ext::shared_ptr<StressTestScenarioData> stressData_
private

Definition at line 98 of file stressscenariogenerator.hpp.

◆ stressScenarioFactory_

QuantLib::ext::shared_ptr<ScenarioFactory> stressScenarioFactory_
private

Definition at line 99 of file stressscenariogenerator.hpp.

◆ baseScenarioAbsolute_

QuantLib::ext::shared_ptr<Scenario> baseScenarioAbsolute_
private

Definition at line 100 of file stressscenariogenerator.hpp.