Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
sensitivityperformance.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
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
19#include "testmarket.hpp"
20#include "testportfolio.hpp"
21#include <boost/test/unit_test.hpp>
22#include <oret/toplevelfixture.hpp>
24
25#include <boost/timer/timer.hpp>
27#include <orea/cube/npvcube.hpp>
54#include <ql/math/randomnumbers/mt19937uniformrng.hpp>
55#include <ql/time/calendars/target.hpp>
56#include <ql/time/date.hpp>
57#include <ql/time/daycounters/actualactual.hpp>
59
60using namespace std;
61using namespace QuantLib;
62using namespace QuantExt;
63using namespace boost::unit_test_framework;
64using namespace ore;
65using namespace ore::data;
66using namespace ore::analytics;
67using boost::timer::cpu_timer;
68using boost::timer::default_places;
69
70namespace {
71
72// Returns an int in the interval [min, max]. Inclusive.
73inline unsigned long randInt(MersenneTwisterUniformRng& rng, Size min, Size max) {
74 return min + (rng.nextInt32() % (max + 1 - min));
75}
76
77inline const string& randString(MersenneTwisterUniformRng& rng, const vector<string>& strs) {
78 return strs[randInt(rng, 0, strs.size() - 1)];
79}
80
81inline bool randBoolean(MersenneTwisterUniformRng& rng) { return randInt(rng, 0, 1) == 1; }
82
83QuantLib::ext::shared_ptr<data::Conventions> conv() {
84 QuantLib::ext::shared_ptr<data::Conventions> conventions(new data::Conventions());
85
86 QuantLib::ext::shared_ptr<data::Convention> swapIndexConv(
87 new data::SwapIndexConvention("EUR-CMS-2Y", "EUR-6M-SWAP-CONVENTIONS"));
88 conventions->add(swapIndexConv);
89
90 // QuantLib::ext::shared_ptr<data::Convention> swapConv(
91 // new data::IRSwapConvention("EUR-6M-SWAP-CONVENTIONS", "TARGET", "Annual", "MF", "30/360", "EUR-EURIBOR-6M"));
92 conventions->add(QuantLib::ext::make_shared<data::IRSwapConvention>("EUR-6M-SWAP-CONVENTIONS", "TARGET", "A", "MF",
93 "30/360", "EUR-EURIBOR-6M"));
94 conventions->add(QuantLib::ext::make_shared<data::IRSwapConvention>("USD-3M-SWAP-CONVENTIONS", "TARGET", "Q", "MF",
95 "30/360", "USD-LIBOR-3M"));
96 conventions->add(QuantLib::ext::make_shared<data::IRSwapConvention>("USD-6M-SWAP-CONVENTIONS", "TARGET", "Q", "MF",
97 "30/360", "USD-LIBOR-6M"));
98 conventions->add(QuantLib::ext::make_shared<data::IRSwapConvention>("GBP-6M-SWAP-CONVENTIONS", "TARGET", "A", "MF",
99 "30/360", "GBP-LIBOR-6M"));
100 conventions->add(QuantLib::ext::make_shared<data::IRSwapConvention>("JPY-6M-SWAP-CONVENTIONS", "TARGET", "A", "MF",
101 "30/360", "JPY-LIBOR-6M"));
102 conventions->add(QuantLib::ext::make_shared<data::IRSwapConvention>("CHF-6M-SWAP-CONVENTIONS", "TARGET", "A", "MF",
103 "30/360", "CHF-LIBOR-6M"));
104
105 conventions->add(QuantLib::ext::make_shared<data::DepositConvention>("EUR-DEP-CONVENTIONS", "EUR-EURIBOR"));
106 conventions->add(QuantLib::ext::make_shared<data::DepositConvention>("USD-DEP-CONVENTIONS", "USD-LIBOR"));
107 conventions->add(QuantLib::ext::make_shared<data::DepositConvention>("GBP-DEP-CONVENTIONS", "GBP-LIBOR"));
108 conventions->add(QuantLib::ext::make_shared<data::DepositConvention>("JPY-DEP-CONVENTIONS", "JPY-LIBOR"));
109 conventions->add(QuantLib::ext::make_shared<data::DepositConvention>("CHF-DEP-CONVENTIONS", "CHF-LIBOR"));
110
111 InstrumentConventions::instance().setConventions(conventions);
112
113 return conventions;
114}
115
116QuantLib::ext::shared_ptr<analytics::ScenarioSimMarketParameters> setupSimMarketData5() {
117 QuantLib::ext::shared_ptr<analytics::ScenarioSimMarketParameters> simMarketData(
119
120 simMarketData->baseCcy() = "EUR";
121 simMarketData->setDiscountCurveNames({"EUR", "GBP", "USD", "CHF", "JPY"});
122 simMarketData->setYieldCurveTenors("", {1 * Months, 6 * Months, 1 * Years, 2 * Years, 3 * Years, 4 * Years,
123 5 * Years, 7 * Years, 10 * Years, 15 * Years, 20 * Years, 30 * Years});
124 simMarketData->setIndices(
125 {"EUR-EURIBOR-6M", "USD-LIBOR-3M", "USD-LIBOR-6M", "GBP-LIBOR-6M", "CHF-LIBOR-6M", "JPY-LIBOR-6M"});
126 simMarketData->interpolation() = "LogLinear";
127
128 simMarketData->setSwapVolTerms("", {1 * Years, 2 * Years, 3 * Years, 5 * Years, 7 * Years, 10 * Years, 20 * Years});
129 simMarketData->setSwapVolExpiries(
130 "", {6 * Months, 1 * Years, 2 * Years, 3 * Years, 5 * Years, 7 * Years, 10 * Years, 20 * Years});
131 simMarketData->setSwapVolKeys({"EUR", "GBP", "USD", "CHF", "JPY"});
132 simMarketData->swapVolDecayMode() = "ForwardVariance";
133 simMarketData->setSimulateSwapVols(true); // false;
134
135 simMarketData->setFxVolExpiries("",
136 vector<Period>{1 * Months, 3 * Months, 6 * Months, 2 * Years, 3 * Years, 4 * Years, 5 * Years});
137 simMarketData->setFxVolDecayMode(string("ConstantVariance"));
138 simMarketData->setSimulateFXVols(true); // false;
139 simMarketData->setFxVolCcyPairs({"EURUSD", "EURGBP", "EURCHF", "EURJPY", "GBPCHF"});
140
141 simMarketData->setFxCcyPairs({"EURUSD", "EURGBP", "EURCHF", "EURJPY"});
142
143 simMarketData->setSimulateCapFloorVols(true);
144 simMarketData->capFloorVolDecayMode() = "ForwardVariance";
145 simMarketData->setCapFloorVolKeys({"EUR", "USD"});
146 simMarketData->setCapFloorVolExpiries(
147 "", {6 * Months, 1 * Years, 2 * Years, 3 * Years, 5 * Years, 7 * Years, 10 * Years, 15 * Years, 20 * Years});
148 simMarketData->setCapFloorVolStrikes("", {0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06});
149
150 return simMarketData;
151}
152
153QuantLib::ext::shared_ptr<analytics::ScenarioSimMarketParameters> setupSimMarketData5Big() {
154 QuantLib::ext::shared_ptr<analytics::ScenarioSimMarketParameters> simMarketData(
156
157 simMarketData->baseCcy() = "EUR";
158 simMarketData->setDiscountCurveNames({"EUR", "GBP", "USD", "CHF", "JPY"});
159 simMarketData->setYieldCurveTenors(
160 "", {1 * Weeks, 2 * Weeks, 1 * Months, 2 * Months, 3 * Months, 4 * Months, 5 * Months, 6 * Months,
161 9 * Months, 10 * Months, 11 * Months, 1 * Years, 13 * Months, 14 * Months, 15 * Months, 16 * Months,
162 17 * Months, 18 * Months, 19 * Months, 20 * Months, 21 * Months, 22 * Months, 23 * Months, 2 * Years,
163 25 * Months, 26 * Months, 27 * Months, 28 * Months, 29 * Months, 30 * Months, 31 * Months, 32 * Months,
164 3 * Years, 40 * Months, 41 * Months, 42 * Months, 43 * Months, 44 * Months, 4 * Years, 52 * Months,
165 53 * Months, 54 * Months, 55 * Months, 56 * Months, 5 * Years, 64 * Months, 65 * Months, 66 * Months,
166 67 * Months, 68 * Months, 6 * Years, 76 * Months, 77 * Months, 78 * Months, 79 * Months, 80 * Months,
167 7 * Years, 88 * Months, 89 * Months, 90 * Months, 91 * Months, 92 * Months, 10 * Years, 15 * Years,
168 20 * Years, 25 * Years, 30 * Years, 50 * Years});
169 simMarketData->setIndices(
170 {"EUR-EURIBOR-6M", "USD-LIBOR-3M", "USD-LIBOR-6M", "GBP-LIBOR-6M", "CHF-LIBOR-6M", "JPY-LIBOR-6M"});
171 simMarketData->interpolation() = "LogLinear";
172
173 simMarketData->setSwapVolTerms(
174 "", {3 * Months, 4 * Months, 5 * Months, 6 * Months, 9 * Months, 10 * Months, 11 * Months, 1 * Years,
175 13 * Months, 14 * Months, 15 * Months, 16 * Months, 17 * Months, 18 * Months, 19 * Months, 20 * Months,
176 21 * Months, 22 * Months, 23 * Months, 2 * Years, 25 * Months, 26 * Months, 27 * Months, 28 * Months,
177 29 * Months, 30 * Months, 31 * Months, 32 * Months, 3 * Years, 40 * Months, 41 * Months, 42 * Months,
178 43 * Months, 44 * Months, 4 * Years, 52 * Months, 53 * Months, 54 * Months, 55 * Months, 56 * Months,
179 5 * Years, 64 * Months, 65 * Months, 66 * Months, 67 * Months, 68 * Months, 6 * Years, 76 * Months,
180 77 * Months, 78 * Months, 79 * Months, 80 * Months, 7 * Years, 88 * Months, 89 * Months, 90 * Months,
181 91 * Months, 92 * Months, 10 * Years, 15 * Years, 20 * Years, 25 * Years, 30 * Years, 50 * Years});
182 simMarketData->setSwapVolExpiries(
183 "", {1 * Weeks, 2 * Weeks, 1 * Months, 2 * Months, 3 * Months, 4 * Months, 5 * Months, 6 * Months,
184 9 * Months, 10 * Months, 11 * Months, 1 * Years, 13 * Months, 14 * Months, 15 * Months, 16 * Months,
185 17 * Months, 18 * Months, 19 * Months, 20 * Months, 21 * Months, 22 * Months, 23 * Months, 2 * Years,
186 25 * Months, 26 * Months, 27 * Months, 28 * Months, 29 * Months, 30 * Months, 31 * Months, 32 * Months,
187 3 * Years, 40 * Months, 41 * Months, 42 * Months, 43 * Months, 44 * Months, 4 * Years, 52 * Months,
188 53 * Months, 54 * Months, 55 * Months, 56 * Months, 5 * Years, 64 * Months, 65 * Months, 66 * Months,
189 67 * Months, 68 * Months, 6 * Years, 76 * Months, 77 * Months, 78 * Months, 79 * Months, 80 * Months,
190 7 * Years, 88 * Months, 89 * Months, 90 * Months, 91 * Months, 92 * Months, 10 * Years, 15 * Years,
191 20 * Years, 25 * Years, 30 * Years, 50 * Years});
192 simMarketData->setSwapVolKeys({"EUR", "GBP", "USD", "CHF", "JPY"});
193 simMarketData->swapVolDecayMode() = "ForwardVariance";
194 simMarketData->setSimulateSwapVols(true); // false;
195
196 vector<Period> tmpFxVolExpiries = {
197 1 * Weeks, 2 * Weeks, 1 * Months, 2 * Months, 3 * Months, 4 * Months, 5 * Months, 6 * Months,
198 9 * Months, 10 * Months, 11 * Months, 1 * Years, 13 * Months, 14 * Months, 15 * Months, 16 * Months,
199 17 * Months, 18 * Months, 19 * Months, 20 * Months, 21 * Months, 22 * Months, 23 * Months, 2 * Years,
200 25 * Months, 26 * Months, 27 * Months, 28 * Months, 29 * Months, 30 * Months, 31 * Months, 32 * Months,
201 3 * Years, 40 * Months, 41 * Months, 42 * Months, 43 * Months, 44 * Months, 4 * Years, 52 * Months,
202 53 * Months, 54 * Months, 55 * Months, 56 * Months, 5 * Years, 64 * Months, 65 * Months, 66 * Months,
203 67 * Months, 68 * Months, 6 * Years, 76 * Months, 77 * Months, 78 * Months, 79 * Months, 80 * Months,
204 7 * Years, 88 * Months, 89 * Months, 90 * Months, 91 * Months, 92 * Months, 10 * Years, 15 * Years,
205 20 * Years, 25 * Years, 30 * Years, 50 * Years};
206
207 simMarketData->setFxVolExpiries("", tmpFxVolExpiries);
208 simMarketData->setFxVolDecayMode(string("ConstantVariance"));
209 simMarketData->setSimulateFXVols(true); // false;
210 simMarketData->setFxVolCcyPairs({"EURUSD", "EURGBP", "EURCHF", "EURJPY", "GBPCHF"});
211
212 simMarketData->setFxCcyPairs({"EURUSD", "EURGBP", "EURCHF", "EURJPY"});
213
214 simMarketData->setSimulateCapFloorVols(true);
215 simMarketData->capFloorVolDecayMode() = "ForwardVariance";
216 simMarketData->setCapFloorVolKeys({"EUR", "USD"});
217 simMarketData->setCapFloorVolExpiries(
218 "", {3 * Months, 4 * Months, 5 * Months, 6 * Months, 9 * Months, 10 * Months, 11 * Months, 1 * Years,
219 13 * Months, 14 * Months, 15 * Months, 16 * Months, 17 * Months, 18 * Months, 19 * Months, 20 * Months,
220 21 * Months, 22 * Months, 23 * Months, 2 * Years, 25 * Months, 26 * Months, 27 * Months, 28 * Months,
221 29 * Months, 30 * Months, 31 * Months, 32 * Months, 3 * Years, 40 * Months, 41 * Months, 42 * Months,
222 43 * Months, 44 * Months, 4 * Years, 52 * Months, 53 * Months, 54 * Months, 55 * Months, 56 * Months,
223 5 * Years, 64 * Months, 65 * Months, 66 * Months, 67 * Months, 68 * Months, 6 * Years, 76 * Months,
224 77 * Months, 78 * Months, 79 * Months, 80 * Months, 7 * Years, 88 * Months, 89 * Months, 90 * Months,
225 91 * Months, 92 * Months, 10 * Years, 15 * Years, 20 * Years, 25 * Years, 30 * Years, 50 * Years});
226 simMarketData->setCapFloorVolStrikes("", {0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06});
227
228 return simMarketData;
229}
230
231QuantLib::ext::shared_ptr<SensitivityScenarioData> setupSensitivityScenarioData5Big() {
232 QuantLib::ext::shared_ptr<SensitivityScenarioData> sensiData = QuantLib::ext::make_shared<SensitivityScenarioData>();
233
235 cvsData.shiftTenors = {
236 1 * Weeks, 2 * Weeks, 1 * Months, 2 * Months, 3 * Months, 4 * Months, 5 * Months, 6 * Months,
237 9 * Months, 10 * Months, 11 * Months, 1 * Years, 13 * Months, 14 * Months, 15 * Months, 16 * Months,
238 17 * Months, 18 * Months, 19 * Months, 20 * Months, 21 * Months, 22 * Months, 23 * Months, 2 * Years,
239 25 * Months, 26 * Months, 27 * Months, 28 * Months, 29 * Months, 30 * Months, 31 * Months, 32 * Months,
240 3 * Years, 40 * Months, 41 * Months, 42 * Months, 43 * Months, 44 * Months, 4 * Years, 52 * Months,
241 53 * Months, 54 * Months, 55 * Months, 56 * Months, 5 * Years, 64 * Months, 65 * Months, 66 * Months,
242 67 * Months, 68 * Months, 6 * Years, 76 * Months, 77 * Months, 78 * Months, 79 * Months, 80 * Months,
243 7 * Years, 88 * Months, 89 * Months, 90 * Months, 91 * Months, 92 * Months, 10 * Years, 15 * Years,
244 20 * Years, 25 * Years, 30 * Years, 50 * Years}; // multiple tenors: triangular shifts
245 cvsData.shiftType = ShiftType::Absolute;
246 cvsData.shiftSize = 0.0001;
247
249 fxsData.shiftType = ShiftType::Relative;
250 fxsData.shiftSize = 0.01;
251
253 fxvsData.shiftType = ShiftType::Relative;
254 fxvsData.shiftSize = 1.0;
255 fxvsData.shiftExpiries = {1 * Weeks, 2 * Weeks, 1 * Months, 2 * Months, 3 * Months, 4 * Months, 5 * Months,
256 6 * Months, 9 * Months, 10 * Months, 11 * Months, 1 * Years, 13 * Months, 14 * Months,
257 15 * Months, 16 * Months, 17 * Months, 18 * Months, 19 * Months, 20 * Months, 21 * Months,
258 22 * Months, 23 * Months, 2 * Years, 25 * Months, 26 * Months, 27 * Months, 28 * Months,
259 29 * Months, 30 * Months, 31 * Months, 32 * Months, 3 * Years, 40 * Months, 41 * Months,
260 42 * Months, 43 * Months, 44 * Months, 4 * Years, 52 * Months, 53 * Months, 54 * Months,
261 55 * Months, 56 * Months, 5 * Years, 64 * Months, 65 * Months, 66 * Months, 67 * Months,
262 68 * Months, 6 * Years, 76 * Months, 77 * Months, 78 * Months, 79 * Months, 80 * Months,
263 7 * Years, 88 * Months, 89 * Months, 90 * Months, 91 * Months, 92 * Months, 10 * Years,
264 15 * Years, 20 * Years, 25 * Years, 30 * Years, 50 * Years};
265
267 cfvsData.shiftType = ShiftType::Absolute;
268 cfvsData.shiftSize = 0.0001;
269 cfvsData.shiftExpiries = {
270 3 * Months, 4 * Months, 5 * Months, 6 * Months, 9 * Months, 10 * Months, 11 * Months, 1 * Years,
271 13 * Months, 14 * Months, 15 * Months, 16 * Months, 17 * Months, 18 * Months, 19 * Months, 20 * Months,
272 21 * Months, 22 * Months, 23 * Months, 2 * Years, 25 * Months, 26 * Months, 27 * Months, 28 * Months,
273 29 * Months, 30 * Months, 31 * Months, 32 * Months, 3 * Years, 40 * Months, 41 * Months, 42 * Months,
274 43 * Months, 44 * Months, 4 * Years, 52 * Months, 53 * Months, 54 * Months, 55 * Months, 56 * Months,
275 5 * Years, 64 * Months, 65 * Months, 66 * Months, 67 * Months, 68 * Months, 6 * Years, 76 * Months,
276 77 * Months, 78 * Months, 79 * Months, 80 * Months, 7 * Years, 88 * Months, 89 * Months, 90 * Months,
277 91 * Months, 92 * Months, 10 * Years, 15 * Years, 20 * Years, 25 * Years, 30 * Years, 50 * Years};
278 cfvsData.shiftStrikes = {0.01, 0.02, 0.03, 0.04, 0.05};
279
281 swvsData.shiftType = ShiftType::Relative;
282 swvsData.shiftSize = 0.01;
283 swvsData.shiftExpiries = {1 * Weeks, 2 * Weeks, 1 * Months, 2 * Months, 3 * Months, 4 * Months, 5 * Months,
284 6 * Months, 9 * Months, 10 * Months, 11 * Months, 1 * Years, 13 * Months, 14 * Months,
285 15 * Months, 16 * Months, 17 * Months, 18 * Months, 19 * Months, 20 * Months, 21 * Months,
286 22 * Months, 23 * Months, 2 * Years, 25 * Months, 26 * Months, 27 * Months, 28 * Months,
287 29 * Months, 30 * Months, 31 * Months, 32 * Months, 3 * Years, 40 * Months, 41 * Months,
288 42 * Months, 43 * Months, 44 * Months, 4 * Years, 52 * Months, 53 * Months, 54 * Months,
289 55 * Months, 56 * Months, 5 * Years, 64 * Months, 65 * Months, 66 * Months, 67 * Months,
290 68 * Months, 6 * Years, 76 * Months, 77 * Months, 78 * Months, 79 * Months, 80 * Months,
291 7 * Years, 88 * Months, 89 * Months, 90 * Months, 91 * Months, 92 * Months, 10 * Years,
292 15 * Years, 20 * Years, 25 * Years, 30 * Years, 50 * Years};
293 swvsData.shiftTerms = {
294 3 * Months, 4 * Months, 5 * Months, 6 * Months, 9 * Months, 10 * Months, 11 * Months, 1 * Years,
295 13 * Months, 14 * Months, 15 * Months, 16 * Months, 17 * Months, 18 * Months, 19 * Months, 20 * Months,
296 21 * Months, 22 * Months, 23 * Months, 2 * Years, 25 * Months, 26 * Months, 27 * Months, 28 * Months,
297 29 * Months, 30 * Months, 31 * Months, 32 * Months, 3 * Years, 40 * Months, 41 * Months, 42 * Months,
298 43 * Months, 44 * Months, 4 * Years, 52 * Months, 53 * Months, 54 * Months, 55 * Months, 56 * Months,
299 5 * Years, 64 * Months, 65 * Months, 66 * Months, 67 * Months, 68 * Months, 6 * Years, 76 * Months,
300 77 * Months, 78 * Months, 79 * Months, 80 * Months, 7 * Years, 88 * Months, 89 * Months, 90 * Months,
301 91 * Months, 92 * Months, 10 * Years, 15 * Years, 20 * Years, 25 * Years, 30 * Years, 50 * Years};
302
303 sensiData->discountCurveShiftData()["EUR"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
304
305 sensiData->discountCurveShiftData()["USD"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
306
307 sensiData->discountCurveShiftData()["GBP"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
308
309 sensiData->discountCurveShiftData()["JPY"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
310
311 sensiData->discountCurveShiftData()["CHF"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
312
313 sensiData->indexCurveShiftData()["EUR-EURIBOR-6M"] =
314 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
315
316 sensiData->indexCurveShiftData()["USD-LIBOR-3M"] =
317 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
318
319 sensiData->indexCurveShiftData()["GBP-LIBOR-6M"] =
320 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
321
322 sensiData->indexCurveShiftData()["JPY-LIBOR-6M"] =
323 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
324
325 sensiData->indexCurveShiftData()["CHF-LIBOR-6M"] =
326 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
327
328 sensiData->fxShiftData()["EURUSD"] = fxsData;
329 sensiData->fxShiftData()["EURGBP"] = fxsData;
330 sensiData->fxShiftData()["EURJPY"] = fxsData;
331 sensiData->fxShiftData()["EURCHF"] = fxsData;
332
333 sensiData->fxVolShiftData()["EURUSD"] = fxvsData;
334 sensiData->fxVolShiftData()["EURGBP"] = fxvsData;
335 sensiData->fxVolShiftData()["EURJPY"] = fxvsData;
336 sensiData->fxVolShiftData()["EURCHF"] = fxvsData;
337 sensiData->fxVolShiftData()["GBPCHF"] = fxvsData;
338
339 sensiData->swaptionVolShiftData()["EUR"] = swvsData;
340 sensiData->swaptionVolShiftData()["GBP"] = swvsData;
341 sensiData->swaptionVolShiftData()["USD"] = swvsData;
342 sensiData->swaptionVolShiftData()["JPY"] = swvsData;
343 sensiData->swaptionVolShiftData()["CHF"] = swvsData;
344
345 sensiData->capFloorVolShiftData()["EUR"] =
346 QuantLib::ext::make_shared<SensitivityScenarioData::CapFloorVolShiftData>(cfvsData);
347 sensiData->capFloorVolShiftData()["EUR"]->indexName = "EUR-EURIBOR-6M";
348 sensiData->capFloorVolShiftData()["USD"] =
349 QuantLib::ext::make_shared<SensitivityScenarioData::CapFloorVolShiftData>(cfvsData);
350 sensiData->capFloorVolShiftData()["USD"]->indexName = "USD-LIBOR-3M";
351
352 return sensiData;
353}
354
355QuantLib::ext::shared_ptr<SensitivityScenarioData> setupSensitivityScenarioData5() {
356 QuantLib::ext::shared_ptr<SensitivityScenarioData> sensiData = QuantLib::ext::make_shared<SensitivityScenarioData>();
357
359 cvsData.shiftTenors = {6 * Months, 1 * Years, 2 * Years, 3 * Years, 5 * Years,
360 7 * Years, 10 * Years, 15 * Years, 20 * Years}; // multiple tenors: triangular shifts
361 cvsData.shiftType = ShiftType::Absolute;
362 cvsData.shiftSize = 0.0001;
363
365 fxsData.shiftType = ShiftType::Relative;
366 fxsData.shiftSize = 0.01;
367
369 fxvsData.shiftType = ShiftType::Relative;
370 fxvsData.shiftSize = 1.0;
371 fxvsData.shiftExpiries = {5 * Years};
372
374 cfvsData.shiftType = ShiftType::Absolute;
375 cfvsData.shiftSize = 0.0001;
376 cfvsData.shiftExpiries = {1 * Years, 2 * Years, 3 * Years, 5 * Years, 10 * Years};
377 cfvsData.shiftStrikes = {0.01, 0.02, 0.03, 0.04, 0.05};
378
380 swvsData.shiftType = ShiftType::Relative;
381 swvsData.shiftSize = 0.01;
382 swvsData.shiftExpiries = {6 * Months, 1 * Years, 3 * Years, 5 * Years, 10 * Years};
383 swvsData.shiftTerms = {1 * Years, 3 * Years, 5 * Years, 10 * Years, 20 * Years};
384
385 sensiData->discountCurveShiftData()["EUR"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
386
387 sensiData->discountCurveShiftData()["USD"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
388
389 sensiData->discountCurveShiftData()["GBP"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
390
391 sensiData->discountCurveShiftData()["JPY"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
392
393 sensiData->discountCurveShiftData()["CHF"] = QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
394
395 sensiData->indexCurveShiftData()["EUR-EURIBOR-6M"] =
396 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
397
398 sensiData->indexCurveShiftData()["USD-LIBOR-3M"] =
399 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
400
401 sensiData->indexCurveShiftData()["GBP-LIBOR-6M"] =
402 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
403
404 sensiData->indexCurveShiftData()["JPY-LIBOR-6M"] =
405 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
406
407 sensiData->indexCurveShiftData()["CHF-LIBOR-6M"] =
408 QuantLib::ext::make_shared<SensitivityScenarioData::CurveShiftData>(cvsData);
409
410 sensiData->fxShiftData()["EURUSD"] = fxsData;
411 sensiData->fxShiftData()["EURGBP"] = fxsData;
412 sensiData->fxShiftData()["EURJPY"] = fxsData;
413 sensiData->fxShiftData()["EURCHF"] = fxsData;
414
415 sensiData->fxVolShiftData()["EURUSD"] = fxvsData;
416 sensiData->fxVolShiftData()["EURGBP"] = fxvsData;
417 sensiData->fxVolShiftData()["EURJPY"] = fxvsData;
418 sensiData->fxVolShiftData()["EURCHF"] = fxvsData;
419 sensiData->fxVolShiftData()["GBPCHF"] = fxvsData;
420
421 sensiData->swaptionVolShiftData()["EUR"] = swvsData;
422 sensiData->swaptionVolShiftData()["GBP"] = swvsData;
423 sensiData->swaptionVolShiftData()["USD"] = swvsData;
424 sensiData->swaptionVolShiftData()["JPY"] = swvsData;
425 sensiData->swaptionVolShiftData()["CHF"] = swvsData;
426
427 sensiData->capFloorVolShiftData()["EUR"] =
428 QuantLib::ext::make_shared<SensitivityScenarioData::CapFloorVolShiftData>(cfvsData);
429 sensiData->capFloorVolShiftData()["EUR"]->indexName = "EUR-EURIBOR-6M";
430 sensiData->capFloorVolShiftData()["USD"] =
431 QuantLib::ext::make_shared<SensitivityScenarioData::CapFloorVolShiftData>(cfvsData);
432 sensiData->capFloorVolShiftData()["USD"]->indexName = "USD-LIBOR-3M";
433
434 return sensiData;
435}
436
437void addCrossGammas(vector<pair<string, string>>& cgFilter) {
438 BOOST_CHECK_EQUAL(cgFilter.size(), 0);
439 cgFilter.push_back(pair<string, string>("DiscountCurve/EUR", "DiscountCurve/EUR"));
440 cgFilter.push_back(pair<string, string>("DiscountCurve/USD", "DiscountCurve/USD"));
441 cgFilter.push_back(pair<string, string>("DiscountCurve/GBP", "DiscountCurve/GBP"));
442 cgFilter.push_back(pair<string, string>("DiscountCurve/CHF", "DiscountCurve/CHF"));
443 cgFilter.push_back(pair<string, string>("DiscountCurve/JPY", "DiscountCurve/JPY"));
444 cgFilter.push_back(pair<string, string>("IndexCurve/EUR", "DiscountCurve/EUR"));
445 cgFilter.push_back(pair<string, string>("IndexCurve/USD", "DiscountCurve/USD"));
446 cgFilter.push_back(pair<string, string>("IndexCurve/GBP", "DiscountCurve/GBP"));
447 cgFilter.push_back(pair<string, string>("IndexCurve/CHF", "DiscountCurve/CHF"));
448 cgFilter.push_back(pair<string, string>("IndexCurve/JPY", "DiscountCurve/JPY"));
449 cgFilter.push_back(pair<string, string>("IndexCurve/EUR", "IndexCurve/EUR"));
450 cgFilter.push_back(pair<string, string>("IndexCurve/USD", "IndexCurve/USD"));
451 cgFilter.push_back(pair<string, string>("IndexCurve/GBP", "IndexCurve/GBP"));
452 cgFilter.push_back(pair<string, string>("IndexCurve/CHF", "IndexCurve/CHF"));
453 cgFilter.push_back(pair<string, string>("IndexCurve/JPY", "IndexCurve/JPY"));
454 cgFilter.push_back(pair<string, string>("SwaptionVolatility/EUR", "SwaptionVolatility/EUR"));
455 cgFilter.push_back(pair<string, string>("SwaptionVolatility/USD", "SwaptionVolatility/USD"));
456 cgFilter.push_back(pair<string, string>("SwaptionVolatility/GBP", "SwaptionVolatility/GBP"));
457 // cgFilter.push_back(pair<string, string>("SwaptionVolatility/CHF", "SwaptionVolatility/CHF"));
458 // cgFilter.push_back(pair<string, string>("SwaptionVolatility/JPY", "SwaptionVolatility/JPY"));
459}
460
461QuantLib::ext::shared_ptr<Portfolio> buildPortfolio(Size portfolioSize, QuantLib::ext::shared_ptr<EngineFactory> factory = {}) {
462
463 QuantLib::ext::shared_ptr<Portfolio> portfolio(new Portfolio());
464
465 vector<string> ccys = {"EUR", "USD", "GBP", "JPY", "CHF"};
466
467 map<string, vector<string>> indices = {{"EUR", {"EUR-EURIBOR-6M"}},
468 {"USD", {"USD-LIBOR-3M"}},
469 {"GBP", {"GBP-LIBOR-6M"}},
470 {"CHF", {"CHF-LIBOR-6M"}},
471 {"JPY", {"JPY-LIBOR-6M"}}};
472
473 vector<string> fixedTenors = {"6M", "1Y"};
474
475 Size minStart = 0;
476 Size maxStart = 5;
477 Size minTerm = 2;
478 Size maxTerm = 30;
479
480 Size minFixedBps = 10;
481 Size maxFixedBps = 400;
482
483 Size seed = 5; // keep this constant to ensure portfolio doesn't change
484 MersenneTwisterUniformRng rng(seed);
485
486 Calendar cal = TARGET();
487 string fixDC = "30/360";
488 string floatDC = "ACT/365";
489
490 Real notional = 1000000;
491 Real spread = 0.0;
492
493 for (Size i = 0; i < portfolioSize; i++) {
494
495 // ccy + index
496 string ccy = portfolioSize == 1 ? "EUR" : randString(rng, ccys);
497 string index = portfolioSize == 1 ? "EUR-EURIBOR-6M" : randString(rng, indices[ccy]);
498 string floatFreq = portfolioSize == 1 ? "6M" : index.substr(index.find('-', 4) + 1);
499
500 // fixed details
501 Real fixedRate = portfolioSize == 1 ? 0.02 : randInt(rng, minFixedBps, maxFixedBps) / 100.0;
502 string fixFreq = portfolioSize == 1 ? "1Y" : randString(rng, fixedTenors);
503
504 bool isPayer = randBoolean(rng);
505
506 // id
507 std::ostringstream oss;
508 oss.clear();
509 oss.str("");
510 oss << "Trade_" << i + 1;
511 string id = oss.str();
512
513 if (i % 2 == 0) {
514 int start = randInt(rng, minTerm, maxTerm);
515 Size term = portfolioSize == 1 ? 20 : randInt(rng, minTerm, maxTerm);
516 string longShort = randBoolean(rng) ? "Long" : "Short";
517 portfolio->add(testsuite::buildEuropeanSwaption(id, longShort, ccy, isPayer, notional, start, term,
518 fixedRate, spread, fixFreq, fixDC, floatFreq, floatDC,
519 index));
520 } else {
521 int start = randInt(rng, minStart, maxStart);
522 Size end = randInt(rng, minTerm, maxTerm);
523 portfolio->add(testsuite::buildSwap(id, ccy, isPayer, notional, start, end, fixedRate, spread, fixFreq,
524 fixDC, floatFreq, floatDC, index));
525 }
526 }
527 if (factory)
528 portfolio->build(factory);
529
530 BOOST_CHECK_MESSAGE(portfolio->size() == portfolioSize,
531 "Failed to build portfolio (got " << portfolio->size() << " expected " << portfolioSize << ")");
532
533 return portfolio;
534}
535
536void test_performance(bool bigPortfolio, bool bigScenario, bool lotsOfSensis, bool crossGammas,
538 cpu_timer t_base;
539 t_base.start();
540 Size portfolioSize = bigPortfolio ? 100 : 1;
541 string om_str = (om == ObservationMode::Mode::None)
542 ? "None"
543 : (om == ObservationMode::Mode::Disable)
544 ? "Disable"
545 : (om == ObservationMode::Mode::Defer)
546 ? "Defer"
547 : (om == ObservationMode::Mode::Unregister) ? "Unregister" : "???";
548 string bigPfolioStr = bigPortfolio ? "big" : "small";
549 string bigScenarioStr = bigScenario ? "big" : "small";
550 string lotsOfSensisStr = lotsOfSensis ? "lots" : "few";
551 string crossGammasStr = crossGammas ? "included" : "excluded";
552
553 BOOST_TEST_MESSAGE("Testing Sensitivity Performance "
554 << "(portfolio=" << bigPfolioStr << ")"
555 << "(scenarioSize=" << bigScenarioStr << ")"
556 << "(numSensis=" << lotsOfSensisStr << ")"
557 << "(crossGammas=" << crossGammasStr << ")"
558 << "(observation=" << om_str << ")...");
559
560 SavedSettings backup;
561 ObservationMode::Mode backupOm = ObservationMode::instance().mode();
562 ObservationMode::instance().setMode(om);
563
564 Date today = Date(14, April, 2016);
565 Settings::instance().evaluationDate() = today;
566
567 // Init market
568 QuantLib::ext::shared_ptr<Market> initMarket = QuantLib::ext::make_shared<testsuite::TestMarket>(today);
569
570 // build scenario sim market parameters
571 QuantLib::ext::shared_ptr<analytics::ScenarioSimMarketParameters> simMarketData = setupSimMarketData5();
572 QuantLib::ext::shared_ptr<SensitivityScenarioData> sensiData = setupSensitivityScenarioData5();
573 if (bigScenario) {
574 simMarketData = setupSimMarketData5Big();
575 }
576 if (lotsOfSensis) {
577 sensiData = setupSensitivityScenarioData5Big();
578 }
579 if (crossGammas) {
580 addCrossGammas(sensiData->crossGammaFilter());
581 }
582
583 // build scenario sim market
584 conv();
585
586 // build portfolio
587 QuantLib::ext::shared_ptr<EngineData> data = QuantLib::ext::make_shared<EngineData>();
588 data->model("Swap") = "DiscountedCashflows";
589 data->engine("Swap") = "DiscountingSwapEngine";
590 data->model("EuropeanSwaption") = "BlackBachelier";
591 data->engine("EuropeanSwaption") = "BlackBachelierSwaptionEngine";
592
593 QuantLib::ext::shared_ptr<Portfolio> portfolio = buildPortfolio(portfolioSize);
594
595 cpu_timer t2;
596 t2.start();
597 QuantLib::ext::shared_ptr<SensitivityAnalysis> sa = QuantLib::ext::make_shared<SensitivityAnalysis>(
598 portfolio, initMarket, Market::defaultConfiguration, data, simMarketData, sensiData, false);
599 sa->generateSensitivities();
600 t2.stop();
601 Real elapsed = t2.elapsed().wall * 1e-9;
602 Size numScenarios = sa->scenarioGenerator()->samples();
603 Size scenarioSize = sa->scenarioGenerator()->scenarios().front()->keys().size();
604 BOOST_TEST_MESSAGE("number of scenarios=" << numScenarios);
605 BOOST_TEST_MESSAGE("Size of scenario = " << scenarioSize << " keys");
606 BOOST_TEST_MESSAGE("time = " << elapsed << " seconds");
607 Real avTime = (elapsed / ((Real)(numScenarios * portfolioSize)));
608 BOOST_TEST_MESSAGE("Average pricing time = " << avTime << " seconds");
609 BOOST_TEST_MESSAGE("Memory usage - " << os::getMemoryUsage());
610
611 ObservationMode::instance().setMode(backupOm);
612 t_base.stop();
613
614 BOOST_TEST_MESSAGE("total time = " << t_base.format(default_places, "%w") << " seconds");
615}
616} // namespace
617
618BOOST_FIXTURE_TEST_SUITE(OREAnalyticsTestSuite, ore::test::OreaTopLevelFixture)
619
620BOOST_AUTO_TEST_SUITE(SensitivityPerformanceTest, *boost::unit_test::disabled())
621
622BOOST_AUTO_TEST_CASE(testSensiPerformanceNoneObs) {
623 test_performance(false, false, false, false, ObservationMode::Mode::None);
624}
625
626BOOST_AUTO_TEST_CASE(testSensiPerformanceDisableObs) {
627 test_performance(false, false, false, false, ObservationMode::Mode::Disable);
628}
629
630BOOST_AUTO_TEST_CASE(testSensiPerformanceDeferObs) {
631 test_performance(false, false, false, false, ObservationMode::Mode::Defer);
632}
633
634BOOST_AUTO_TEST_CASE(testSensiPerformanceUnregisterObs) {
635 test_performance(false, false, false, false, ObservationMode::Mode::Unregister);
636}
637
638BOOST_AUTO_TEST_CASE(testSensiPerformanceCrossGammaNoneObs) {
639 test_performance(false, false, false, true, ObservationMode::Mode::None);
640}
641
642BOOST_AUTO_TEST_CASE(testSensiPerformanceBigScenarioNoneObs) {
643 test_performance(false, true, false, false, ObservationMode::Mode::None);
644}
645
646BOOST_AUTO_TEST_CASE(testSensiPerformanceBigPortfolioNoneObs) {
647 test_performance(true, false, false, false, ObservationMode::Mode::None);
648}
649
650BOOST_AUTO_TEST_CASE(testSensiPerformanceBigPortfolioBigScenarioNoneObs) {
651 test_performance(true, true, false, false, ObservationMode::Mode::None);
652}
653
654BOOST_AUTO_TEST_CASE(testSensiPerformanceBigPortfolioCrossGammaNoneObs) {
655 test_performance(true, false, false, true, ObservationMode::Mode::None);
656}
657
658BOOST_AUTO_TEST_CASE(testSensiPerformanceBigScenarioCrossGammaNoneObs) {
659 test_performance(false, true, false, true, ObservationMode::Mode::None);
660}
661
662BOOST_AUTO_TEST_CASE(testSensiPerformanceBigPortfolioBigScenarioCrossGammaNoneObs) {
663 test_performance(true, true, false, true, ObservationMode::Mode::None);
664}
665
666BOOST_AUTO_TEST_SUITE_END()
667
668BOOST_AUTO_TEST_SUITE_END()
static const string defaultConfiguration
OREAnalytics Top level fixture.
Scenario generation using cross asset model paths.
unsigned long randInt(MersenneTwisterUniformRng &rng, Size min, Size max)
Definition: cube.cpp:255
bool randBoolean(MersenneTwisterUniformRng &rng)
Definition: cube.cpp:262
const string & randString(MersenneTwisterUniformRng &rng, const vector< string > &strs)
Definition: cube.cpp:259
QuantLib::ext::shared_ptr< Portfolio > buildPortfolio(Size portfolioSize, QuantLib::ext::shared_ptr< EngineFactory > &factory)
Definition: cube.cpp:264
Class that wraps a sensitivity stream and filters out negligible records.
string getMemoryUsage()
A cube implementation that stores the cube in memory.
data
RandomVariable max(RandomVariable x, const RandomVariable &y)
RandomVariable min(RandomVariable x, const RandomVariable &y)
QuantLib::ext::shared_ptr< Trade > buildSwap(string id, string ccy, bool isPayer, Real notional, int start, Size term, Real rate, Real spread, string fixedFreq, string fixedDC, string floatFreq, string floatDC, string index, Calendar calendar, Natural spotDays, bool spotStartLag)
QuantLib::ext::shared_ptr< Trade > buildEuropeanSwaption(string id, string longShort, string ccy, bool isPayer, Real notional, int start, Size term, Real rate, Real spread, string fixedFreq, string fixedDC, string floatFreq, string floatDC, string index, string cashPhysical, Real premium, string premiumCcy, string premiumDate)
The base NPV cube class.
Singleton class to hold global Observation Mode.
Fixture that can be used at top level of OREAnalytics test suites.
Perform parametric var calculation for a given portfolio.
risk class and type filter
A Market class that can be updated by Scenarios.
A class to hold Scenario parameters for scenarioSimMarket.
Class for aggregating SensitivityRecords.
Perform sensitivity analysis for a given portfolio.
Class for streaming SensitivityRecords from a SensitivityCube.
Class for streaming SensitivityRecords from file.
Class for streaming SensitivityRecords from in-memory container.
BOOST_AUTO_TEST_CASE(testSensiPerformanceNoneObs)
Struct for holding a sensitivity record.
Base class for sensitivity record streamer.
factory classes for simple scenarios
perform a stress testing analysis for a given portfolio.
void test_performance(Size portfolioSize, ObservationMode::Mode om, double nonZeroPVRatio, vector< Real > &epe_archived, vector< Real > &ene_archived)
QuantLib::ext::shared_ptr< SensitivityScenarioData > setupSensitivityScenarioData5(bool parConversion)
QuantLib::ext::shared_ptr< analytics::ScenarioSimMarketParameters > setupSimMarketData5()
The counterparty cube calculator interface.
The cube valuation core.