Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
scenarioshiftcalculator.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 Quaternion Risk Management Ltd
3 All rights reserved.
4*/
5
6#include <oret/toplevelfixture.hpp>
9
10using namespace boost::unit_test_framework;
11
18using namespace QuantLib;
19
21using CurveShiftData = SensitivityScenarioData::CurveShiftData;
23
24// Tolerance for comparisons below
25Real tol = 1e-10;
26Date asof(14, Jun, 2018);
27
28BOOST_FIXTURE_TEST_SUITE(OREAnalyticsTestSuite, ore::test::TopLevelFixture)
29
30BOOST_AUTO_TEST_SUITE(ScenarioShiftCalculatorTest)
31
32BOOST_AUTO_TEST_CASE(testAbsoluteDiscountShift) {
33
34 BOOST_TEST_MESSAGE("Testing absolute shift in a discount curve");
35
36 // Set up
37 auto ssd = QuantLib::ext::make_shared<SensitivityScenarioData>();
38 auto ssp = QuantLib::ext::make_shared<ScenarioSimMarketParameters>();
39
40 // Discount curve sensitivity set up to have 1bp absolute shift
41 ssd->discountCurveShiftData()["EUR"] = QuantLib::ext::make_shared<CurveShiftData>();
42 ssd->discountCurveShiftData()["EUR"]->shiftSize = 0.0001;
43 ssd->discountCurveShiftData()["EUR"]->shiftType = ShiftType::Absolute;
44
45 ssp->setYieldCurveTenors("EUR", {3 * Months, 6 * Months});
46
47 // Pick out the 6M discount from the scenarios
48 RiskFactorKey rf(RFType::DiscountCurve, "EUR", 1);
49
50 SimpleScenario scen_1(asof);
51 DiscountFactor v_1 = 0.995;
52 scen_1.add(rf, v_1);
53
54 SimpleScenario scen_2(asof);
55 DiscountFactor v_2 = 0.990;
56 scen_2.add(rf, v_2);
57
58 // Set up the calculator
59 ScenarioShiftCalculator ssc(ssd, ssp);
60
61 // Test the result
62 Real cal = ssc.shift(rf, scen_1, scen_2);
63 Real exp = 100.480591307889;
64 BOOST_CHECK_CLOSE(cal, exp, tol);
65
66 // Scale the shift size and the calculated shift multiple should scale
67 Real factor = 2.5;
68 ssd->discountCurveShiftData()["EUR"]->shiftSize *= factor;
69 cal = ssc.shift(rf, scen_1, scen_2);
70 exp /= factor;
71 BOOST_CHECK_CLOSE(cal, exp, tol);
72}
73
74BOOST_AUTO_TEST_CASE(testRelativeDiscountShift) {
75
76 BOOST_TEST_MESSAGE("Testing relative shift in a discount curve");
77
78 // Set up
79 auto ssd = QuantLib::ext::make_shared<SensitivityScenarioData>();
80 auto ssp = QuantLib::ext::make_shared<ScenarioSimMarketParameters>();
81
82 // Discount curve sensitivity set up to have 1% relative shift
83 ssd->discountCurveShiftData()["EUR"] = QuantLib::ext::make_shared<CurveShiftData>();
84 ssd->discountCurveShiftData()["EUR"]->shiftSize = 0.01;
85 ssd->discountCurveShiftData()["EUR"]->shiftType = ShiftType::Relative;
86
87 ssp->setYieldCurveTenors("EUR", {3 * Months, 6 * Months});
88
89 // Pick out the 6M discount from the scenarios
90 RiskFactorKey rf(RFType::DiscountCurve, "EUR", 1);
91
92 SimpleScenario scen_1(asof);
93 DiscountFactor v_1 = 0.995;
94 scen_1.add(rf, v_1);
95
96 SimpleScenario scen_2(asof);
97 DiscountFactor v_2 = 0.990;
98 scen_2.add(rf, v_2);
99
100 // Set up the calculator
101 ScenarioShiftCalculator ssc(ssd, ssp);
102
103 // Test the result
104 Real cal = ssc.shift(rf, scen_1, scen_2);
105 Real exp = 100.503780463123;
106 BOOST_CHECK_CLOSE(cal, exp, tol);
107
108 // Scale the shift size and the calculated shift multiple should scale
109 Real factor = 1.5;
110 ssd->discountCurveShiftData()["EUR"]->shiftSize *= factor;
111 cal = ssc.shift(rf, scen_1, scen_2);
112 exp /= factor;
113 BOOST_CHECK_CLOSE(cal, exp, tol);
114}
115
116BOOST_AUTO_TEST_CASE(testAbsoluteSurvivalShift) {
117
118 BOOST_TEST_MESSAGE("Testing absolute shift in a survival curve");
119
120 // Set up
121 auto ssd = QuantLib::ext::make_shared<SensitivityScenarioData>();
122 auto ssp = QuantLib::ext::make_shared<ScenarioSimMarketParameters>();
123
124 // Credit curve sensitivity set up to have 10bp absolute shift
125 ssd->creditCurveShiftData()["APPLE"] = QuantLib::ext::make_shared<CurveShiftData>();
126 ssd->creditCurveShiftData()["APPLE"]->shiftSize = 0.0010;
127 ssd->creditCurveShiftData()["APPLE"]->shiftType = ShiftType::Absolute;
128
129 ssp->setDefaultTenors("APPLE", {3 * Months, 6 * Months, 1 * Years});
130
131 // Pick out the 1Y default curve point from the scenarios
132 RiskFactorKey rf(RFType::SurvivalProbability, "APPLE", 2);
133
134 SimpleScenario scen_1(asof);
135 Probability v_1 = 0.90;
136 scen_1.add(rf, v_1);
137
138 SimpleScenario scen_2(asof);
139 Probability v_2 = 0.95;
140 scen_2.add(rf, v_2);
141
142 // Set up the calculator
143 // In a realistic case we wil have a ScenarioSimMarket to be passed here as third argument.
144 // In the absence of this the shift calculator will assume A365 term structure daycount for date/time conversion.
145 ScenarioShiftCalculator ssc(ssd, ssp);
146
147 // Test the result
148 Real cal = ssc.shift(rf, scen_1, scen_2);
149 // This is based on A360 default term structure daycount set before in the scenario sim market parameters for default curves
150 // Real exp = -53.3265744035596;
151 // This is based on A365 daycount now assumed by default in the scenarioshiftcalculator.*pp if sim market is not passed in
152 Real exp = -54.067221270275702;
153
154 BOOST_CHECK_CLOSE(cal, exp, tol);
155
156 // Scale the shift size and the calculated shift multiple should scale
157 Real factor = 2.0;
158 ssd->creditCurveShiftData()["APPLE"]->shiftSize *= factor;
159 cal = ssc.shift(rf, scen_1, scen_2);
160 exp /= factor;
161 BOOST_CHECK_CLOSE(cal, exp, tol);
162}
163
164BOOST_AUTO_TEST_CASE(testRelativeSurvivalShift) {
165
166 BOOST_TEST_MESSAGE("Testing relative shift in a survival curve");
167
168 // Set up
169 auto ssd = QuantLib::ext::make_shared<SensitivityScenarioData>();
170 auto ssp = QuantLib::ext::make_shared<ScenarioSimMarketParameters>();
171
172 // Credit curve sensitivity set up to have 10% relative shift
173 ssd->creditCurveShiftData()["APPLE"] = QuantLib::ext::make_shared<CurveShiftData>();
174 ssd->creditCurveShiftData()["APPLE"]->shiftSize = 0.10;
175 ssd->creditCurveShiftData()["APPLE"]->shiftType = ShiftType::Relative;
176
177 ssp->setDefaultTenors("APPLE", {3 * Months, 6 * Months, 1 * Years});
178
179 // Pick out the 1Y default curve point from the scenarios
180 RiskFactorKey rf(RFType::SurvivalProbability, "APPLE", 2);
181
182 SimpleScenario scen_1(asof);
183 Probability v_1 = 0.90;
184 scen_1.add(rf, v_1);
185
186 SimpleScenario scen_2(asof);
187 Probability v_2 = 0.95;
188 scen_2.add(rf, v_2);
189
190 // Set up the calculator
191 ScenarioShiftCalculator ssc(ssd, ssp);
192
193 // Test the result
194 Real cal = ssc.shift(rf, scen_1, scen_2);
195 Real exp = -5.1316397734676;
196 BOOST_CHECK_CLOSE(cal, exp, tol);
197
198 // Scale the shift size and the calculated shift multiple should scale
199 Real factor = 2.0;
200 ssd->creditCurveShiftData()["APPLE"]->shiftSize *= factor;
201 cal = ssc.shift(rf, scen_1, scen_2);
202 exp /= factor;
203 BOOST_CHECK_CLOSE(cal, exp, tol);
204}
205
206BOOST_AUTO_TEST_CASE(testAbsoluteFxShift) {
207
208 BOOST_TEST_MESSAGE("Testing absolute shift in a FX spot rate");
209
210 // Set up
211 auto ssd = QuantLib::ext::make_shared<SensitivityScenarioData>();
212 auto ssp = QuantLib::ext::make_shared<ScenarioSimMarketParameters>();
213
214 Rate shift = 0.0005;
215 Real exp = 3.0;
216
217 // FX spot sensitivity set up to have 5bp absolute shift
218 ssd->fxShiftData()["EURUSD"].shiftSize = shift;
219 ssd->fxShiftData()["EURUSD"].shiftType = ShiftType::Absolute;
220
221 // EURUSD spot scenario
222 RiskFactorKey rf(RFType::FXSpot, "EURUSD", 0);
223
224 SimpleScenario scen_1(asof);
225 Rate v_1 = 1.1637;
226 scen_1.add(rf, v_1);
227
228 SimpleScenario scen_2(asof);
229 Rate v_2 = v_1 + exp * shift;
230 scen_2.add(rf, v_2);
231
232 // Set up the calculator
233 ScenarioShiftCalculator ssc(ssd, ssp);
234
235 // Test the result
236 Real cal = ssc.shift(rf, scen_1, scen_2);
237 BOOST_CHECK_CLOSE(cal, exp, tol);
238
239 // Scale the shift size and the calculated shift multiple should scale
240 Real factor = 1 / 5.0;
241 ssd->fxShiftData()["EURUSD"].shiftSize *= factor;
242 cal = ssc.shift(rf, scen_1, scen_2);
243 exp /= factor;
244 BOOST_CHECK_CLOSE(cal, exp, tol);
245}
246
247BOOST_AUTO_TEST_CASE(testRelativeFxShift) {
248
249 BOOST_TEST_MESSAGE("Testing relative shift in a FX spot rate");
250
251 Rate shift = 0.02;
252 Real exp = 4.5;
253
254 // Set up
255 auto ssd = QuantLib::ext::make_shared<SensitivityScenarioData>();
256 auto ssp = QuantLib::ext::make_shared<ScenarioSimMarketParameters>();
257
258 // FX spot sensitivity set up to have 2% relative shift
259 ssd->fxShiftData()["EURUSD"].shiftSize = shift;
260 ssd->fxShiftData()["EURUSD"].shiftType = ShiftType::Relative;
261
262 // EURUSD spot scenario
263 RiskFactorKey rf(RFType::FXSpot, "EURUSD", 0);
264
265 SimpleScenario scen_1(asof);
266 Rate v_1 = 1.1637;
267 scen_1.add(rf, v_1);
268
269 SimpleScenario scen_2(asof);
270 Rate v_2 = v_1 * (1.0 + exp * shift);
271 scen_2.add(rf, v_2);
272
273 // Set up the calculator
274 ScenarioShiftCalculator ssc(ssd, ssp);
275
276 // Test the result
277 Real cal = ssc.shift(rf, scen_1, scen_2);
278 BOOST_CHECK_CLOSE(cal, exp, tol);
279
280 // Scale the shift size and the calculated shift multiple should scale
281 Real factor = 1 / 2.0;
282 ssd->fxShiftData()["EURUSD"].shiftSize *= factor;
283 cal = ssc.shift(rf, scen_1, scen_2);
284 exp /= factor;
285 BOOST_CHECK_CLOSE(cal, exp, tol);
286}
287
288BOOST_AUTO_TEST_CASE(testAbsoluteSwaptionVolShift) {
289
290 BOOST_TEST_MESSAGE("Testing absolute shift in a swaption volatility");
291
292 // Set up
293 auto ssd = QuantLib::ext::make_shared<SensitivityScenarioData>();
294 auto ssp = QuantLib::ext::make_shared<ScenarioSimMarketParameters>();
295
296 Rate shift = 0.0001;
297 Real exp = 8.45;
298
299 // Swaption volatility sensitivity set up to have 1bp absolute shift
300 ssd->swaptionVolShiftData()["EUR"].shiftSize = shift;
301 ssd->swaptionVolShiftData()["EUR"].shiftType = ShiftType::Absolute;
302
303 // Swaption volatility scenario (index will correspond to some point on
304 // a cube or matrix)
305 RiskFactorKey rf(RFType::SwaptionVolatility, "EUR", 8);
306
307 SimpleScenario scen_1(asof);
308 Rate v_1 = 0.0064;
309 scen_1.add(rf, v_1);
310
311 SimpleScenario scen_2(asof);
312 Rate v_2 = v_1 + exp * shift;
313 scen_2.add(rf, v_2);
314
315 // Set up the calculator
316 ScenarioShiftCalculator ssc(ssd, ssp);
317
318 // Test the result
319 Real cal = ssc.shift(rf, scen_1, scen_2);
320 BOOST_CHECK_CLOSE(cal, exp, tol);
321
322 // Scale the shift size and the calculated shift multiple should scale
323 Real factor = 1 / 2.0;
324 ssd->swaptionVolShiftData()["EUR"].shiftSize *= factor;
325 cal = ssc.shift(rf, scen_1, scen_2);
326 exp /= factor;
327 BOOST_CHECK_CLOSE(cal, exp, tol);
328}
329
330BOOST_AUTO_TEST_CASE(testRelativeSwaptionVolShift) {
331
332 BOOST_TEST_MESSAGE("Testing relative shift in a swaption volatility");
333
334 // Set up
335 auto ssd = QuantLib::ext::make_shared<SensitivityScenarioData>();
336 auto ssp = QuantLib::ext::make_shared<ScenarioSimMarketParameters>();
337
338 Rate shift = 0.01;
339 Real exp = 5.5;
340
341 // Swaption volatility sensitivity set up to have 1% relative shift
342 ssd->swaptionVolShiftData()["EUR"].shiftSize = shift;
343 ssd->swaptionVolShiftData()["EUR"].shiftType = ShiftType::Relative;
344
345 // Swaption volatility scenario (index will correspond to some point on
346 // a cube or matrix)
347 RiskFactorKey rf(RFType::SwaptionVolatility, "EUR", 8);
348
349 SimpleScenario scen_1(asof);
350 Rate v_1 = 0.0064;
351 scen_1.add(rf, v_1);
352
353 SimpleScenario scen_2(asof);
354 Rate v_2 = v_1 * (1 + exp * shift);
355 scen_2.add(rf, v_2);
356
357 // Set up the calculator
358 ScenarioShiftCalculator ssc(ssd, ssp);
359
360 // Test the result
361 Real cal = ssc.shift(rf, scen_1, scen_2);
362 BOOST_CHECK_CLOSE(cal, exp, tol);
363
364 // Scale the shift size and the calculated shift multiple should scale
365 Real factor = 1 / 2.0;
366 ssd->swaptionVolShiftData()["EUR"].shiftSize *= factor;
367 cal = ssc.shift(rf, scen_1, scen_2);
368 exp /= factor;
369 BOOST_CHECK_CLOSE(cal, exp, tol);
370}
371
372BOOST_AUTO_TEST_SUITE_END()
373
374BOOST_AUTO_TEST_SUITE_END()
Data types stored in the scenario class.
Definition: scenario.hpp:48
KeyType
Risk Factor types.
Definition: scenario.hpp:51
QuantLib::Real shift(const ore::analytics::RiskFactorKey &key, const ore::analytics::Scenario &s_1, const ore::analytics::Scenario &s_2) const
Description of sensitivity shift scenarios.
void add(const RiskFactorKey &key, Real value) override
Add an element to the scenario.
RandomVariable exp(RandomVariable x)
Class for calculating the shift multiple between two scenarios for a given key.
Simple scenario class.
SensitivityScenarioData::CurveShiftData CurveShiftData
Date asof(14, Jun, 2018)
SensitivityScenarioData::SpotShiftData SpotShiftData
BOOST_AUTO_TEST_CASE(testAbsoluteDiscountShift)