Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
swapperformance.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 <boost/test/unit_test.hpp>
20#include <boost/timer/timer.hpp>
22#include <orea/cube/npvcube.hpp>
49#include <oret/toplevelfixture.hpp>
50#include <ql/math/randomnumbers/mt19937uniformrng.hpp>
51#include <ql/time/calendars/target.hpp>
52#include <ql/time/date.hpp>
53#include <ql/time/daycounters/actualactual.hpp>
56
57#include "testmarket.hpp"
58
59using namespace std;
60using namespace QuantLib;
61using namespace QuantExt;
62using namespace boost::unit_test_framework;
63using namespace ore;
64using namespace ore::data;
65using namespace ore::analytics;
66
68
69BOOST_FIXTURE_TEST_SUITE(OREAnalyticsTestSuite, ore::test::OreaTopLevelFixture)
70
71BOOST_AUTO_TEST_SUITE(SwapPerformaceTest, *boost::unit_test::disabled())
72
73// Returns an int in the interval [min, max]. Inclusive.
74inline unsigned long randInt(MersenneTwisterUniformRng& rng, Size min, Size max) {
75 return min + (rng.nextInt32() % (max + 1 - min));
76}
77
78inline const string& randString(MersenneTwisterUniformRng& rng, const vector<string>& strs) {
79 return strs[randInt(rng, 0, strs.size() - 1)];
80}
81
82inline bool randBoolean(MersenneTwisterUniformRng& rng) { return randInt(rng, 0, 1) == 1; }
83
84QuantLib::ext::shared_ptr<data::Conventions> convs() {
85 QuantLib::ext::shared_ptr<data::Conventions> conventions(new data::Conventions());
86
87 QuantLib::ext::shared_ptr<data::Convention> swapIndexConv(
88 new data::SwapIndexConvention("EUR-CMS-2Y", "EUR-6M-SWAP-CONVENTIONS"));
89 conventions->add(swapIndexConv);
90
91 QuantLib::ext::shared_ptr<data::Convention> swapConv(
92 new data::IRSwapConvention("EUR-6M-SWAP-CONVENTIONS", "TARGET", "Annual", "MF", "30/360", "EUR-EURIBOR-6M"));
93 conventions->add(swapConv);
94
95 InstrumentConventions::instance().setConventions(conventions);
96
97 return conventions;
98}
99
100QuantLib::ext::shared_ptr<Portfolio> buildPortfolio(Size portfolioSize, QuantLib::ext::shared_ptr<EngineFactory>& factory) {
101
102 QuantLib::ext::shared_ptr<Portfolio> portfolio(new Portfolio());
103
104 vector<string> ccys = {"EUR", "USD", "GBP", "JPY", "CHF"};
105
106 map<string, vector<string>> indices = {{"EUR", {"EUR-EURIBOR-6M"}},
107 {"USD", {"USD-LIBOR-3M"}},
108 {"GBP", {"GBP-LIBOR-6M"}},
109 {"CHF", {"CHF-LIBOR-6M"}},
110 {"JPY", {"JPY-LIBOR-6M"}}};
111
112 vector<string> fixedTenors = {"6M", "1Y"};
113
114 Size minTerm = 2;
115 Size maxTerm = 30;
116
117 Size minFixedBps = 10;
118 Size maxFixedBps = 400;
119
120 Size seed = 5; // keep this constant to ensure portfolio doesn't change
121 MersenneTwisterUniformRng rng(seed);
122
123 Date today = Settings::instance().evaluationDate();
124 Calendar cal = TARGET();
125 string calStr = "TARGET";
126 string conv = "MF";
127 string rule = "Forward";
128 Size days = 2;
129 string fixDC = "30/360";
130 string floatDC = "ACT/365";
131
132 vector<double> notional(1, 1000000);
133 vector<double> spread(1, 0);
134
135 for (Size i = 0; i < portfolioSize; i++) {
136 Size term = portfolioSize == 1 ? 20 : randInt(rng, minTerm, maxTerm);
137
138 // Start today +/- 1 Year
139 Date startDate = portfolioSize == 1 ? cal.adjust(today) : cal.adjust(today - 365 + randInt(rng, 0, 730));
140 Date endDate = cal.adjust(startDate + term * Years);
141
142 // date 2 string
143 ostringstream oss;
144 oss << io::iso_date(startDate);
145 string start(oss.str());
146 oss.str("");
147 oss.clear();
148 oss << io::iso_date(endDate);
149 string end(oss.str());
150
151 // ccy + index
152 string ccy = portfolioSize == 1 ? "EUR" : randString(rng, ccys);
153 string index = portfolioSize == 1 ? "EUR-EURIBOR-6M" : randString(rng, indices[ccy]);
154 string floatFreq = portfolioSize == 1 ? "6M" : index.substr(index.find('-', 4) + 1);
155
156 // This variable is not used and only here to ensure that the random numbers generated in
157 // subsequent blocks produce a swap portfolio, which is compatible with the archived values.
158 string fixedTenor = portfolioSize == 1 ? "1Y" : randString(rng, fixedTenors);
159 fixedTenor = fixedTenor + "_";
160
161 // fixed details
162 Real fixedRate = portfolioSize == 1 ? 0.02 : randInt(rng, minFixedBps, maxFixedBps) / 100.0;
163 string fixFreq = portfolioSize == 1 ? "1Y" : randString(rng, fixedTenors);
164
165 // envelope
166 Envelope env("CP");
167
168 // Schedules
169 ScheduleData floatSchedule(ScheduleRules(start, end, floatFreq, calStr, conv, conv, rule));
170 ScheduleData fixedSchedule(ScheduleRules(start, end, fixFreq, calStr, conv, conv, rule));
171
172 bool isPayer = randBoolean(rng);
173
174 // fixed Leg - with dummy rate
175 LegData fixedLeg(QuantLib::ext::make_shared<FixedLegData>(vector<double>(1, fixedRate)), isPayer, ccy, fixedSchedule,
176 fixDC, notional);
177
178 // float Leg
179 vector<double> spreads(1, 0);
180 LegData floatingLeg(QuantLib::ext::make_shared<FloatingLegData>(index, days, false, spread), !isPayer, ccy,
181 floatSchedule, floatDC, notional);
182
183 QuantLib::ext::shared_ptr<Trade> swap(new data::Swap(env, floatingLeg, fixedLeg));
184
185 // id
186 oss.clear();
187 oss.str("");
188 oss << "Trade_" << i + 1;
189 swap->id() = oss.str();
190
191 portfolio->add(swap);
192 }
193 // portfolio->save("port.xml");
194
195 portfolio->build(factory);
196
197 if (portfolio->size() != portfolioSize)
198 BOOST_ERROR("Failed to build portfolio (got " << portfolio->size() << " expected " << portfolioSize << ")");
199
200 // Dump stats about portfolio
201 Time maturity = 0;
202 DayCounter dc = ActualActual(ActualActual::ISDA);
203 map<string, Size> fixedFreqs;
204 map<string, Size> floatFreqs;
205 for (const auto& [tradeId, trade] : portfolio->trades()) {
206 maturity += dc.yearFraction(today, trade->maturity());
207
208 // fixed Freq
209 QuantLib::ext::shared_ptr<data::Swap> swap = QuantLib::ext::dynamic_pointer_cast<data::Swap>(trade);
210 string floatFreq = swap->legData()[0].schedule().rules().front().tenor();
211 string fixFreq = swap->legData()[1].schedule().rules().front().tenor();
212 QL_REQUIRE(swap->legData()[0].legType() == "Floating" && swap->legData()[1].legType() == "Fixed", "Leg mixup");
213 if (fixedFreqs.find(fixFreq) == fixedFreqs.end())
214 fixedFreqs[fixFreq] = 1;
215 else
216 fixedFreqs[fixFreq]++;
217 if (floatFreqs.find(floatFreq) == floatFreqs.end())
218 floatFreqs[floatFreq] = 1;
219 else
220 floatFreqs[floatFreq]++;
221 }
222 maturity /= portfolioSize;
223 BOOST_TEST_MESSAGE("Portfolio Size : " << portfolioSize);
224 BOOST_TEST_MESSAGE("Average Maturity : " << maturity);
225 ostringstream oss;
226 for (Size i = 0; i < ccys.size(); i++)
227 oss << ccys[i] << " ";
228 BOOST_TEST_MESSAGE("Currencies : " << oss.str());
229 // dump % breakdown of tenors
230 map<string, Size>::iterator it;
231 BOOST_TEST_MESSAGE("Fixed Tenors : ");
232 for (it = fixedFreqs.begin(); it != fixedFreqs.end(); ++it) {
233 Real perc = 100 * it->second / (Real)portfolioSize;
234 BOOST_TEST_MESSAGE(" " << it->first << " " << perc << " %");
235 }
236 BOOST_TEST_MESSAGE("Floating Tenors : ");
237 for (it = floatFreqs.begin(); it != floatFreqs.end(); ++it) {
238 Real perc = 100 * it->second / (Real)portfolioSize;
239 BOOST_TEST_MESSAGE(" " << it->first << " " << perc << " %");
240 }
241
242 return portfolio;
243}
244
245void test_performance(Size portfolioSize, ObservationMode::Mode om, double nonZeroPVRatio, vector<Real>& epe_archived,
246 vector<Real>& ene_archived) {
247 BOOST_TEST_MESSAGE("Testing Swap Exposure Performance size=" << portfolioSize << "...");
248
249 SavedSettings backup;
250 ObservationMode::Mode backupOm = ObservationMode::instance().mode();
251 ObservationMode::instance().setMode(om);
252
253 // Log::instance().registerLogger(QuantLib::ext::make_shared<StderrLogger>());
254 // Log::instance().switchOn();
255
256 Date today = Date(14, April, 2016); // Settings::instance().evaluationDate();
257 Settings::instance().evaluationDate() = today;
258
259 BOOST_TEST_MESSAGE("Today is " << today);
260
261 string dateGridStr = "80,3M"; // 20 years
262 QuantLib::ext::shared_ptr<DateGrid> dg = QuantLib::ext::make_shared<DateGrid>(dateGridStr);
263 Size samples = 1000;
264
265 BOOST_TEST_MESSAGE("Date Grid : " << dateGridStr);
266 BOOST_TEST_MESSAGE("Samples : " << samples);
267 BOOST_TEST_MESSAGE("Swaps : " << portfolioSize);
268
269 // build model
270 string baseCcy = "EUR";
271 vector<string> ccys;
272 ccys.push_back(baseCcy);
273 ccys.push_back("GBP");
274 ccys.push_back("CHF");
275 ccys.push_back("USD");
276 ccys.push_back("JPY");
277
278 // Init market
279 QuantLib::ext::shared_ptr<Market> initMarket = QuantLib::ext::make_shared<TestMarket>(today);
280
281 // build scenario sim market parameters
282 QuantLib::ext::shared_ptr<analytics::ScenarioSimMarketParameters> parameters(new analytics::ScenarioSimMarketParameters());
283 parameters->baseCcy() = "EUR";
284 parameters->setDiscountCurveNames({"EUR", "GBP", "USD", "CHF", "JPY"});
285 parameters->setYieldCurveTenors("",
286 {1 * Months, 6 * Months, 1 * Years, 2 * Years, 5 * Years, 10 * Years, 20 * Years});
287 parameters->setIndices({"EUR-EURIBOR-6M", "USD-LIBOR-3M", "GBP-LIBOR-6M", "CHF-LIBOR-6M", "JPY-LIBOR-6M"});
288
289 parameters->interpolation() = "LogLinear";
290
291 parameters->setSimulateSwapVols(false);
292 parameters->setSwapVolTerms("", {6 * Months, 1 * Years});
293 parameters->setSwapVolExpiries("", {1 * Years, 2 * Years});
294 parameters->swapVolKeys() = ccys;
295 parameters->swapVolDecayMode() = "ForwardVariance";
296
297 parameters->setFxVolExpiries("",
298 vector<Period>{1 * Months, 3 * Months, 6 * Months, 2 * Years, 3 * Years, 4 * Years, 5 * Years});
299 parameters->setFxVolDecayMode(string("ConstantVariance"));
300 parameters->setSimulateFXVols(false);
301
302 parameters->setFxVolCcyPairs({"USDEUR", "GBPEUR", "CHFEUR", "JPYEUR"});
303 parameters->setFxCcyPairs({"USDEUR", "GBPEUR", "CHFEUR", "JPYEUR"});
304
305 parameters->setEquityVolExpiries("", {1 * Months, 3 * Months, 6 * Months, 2 * Years, 3 * Years, 4 * Years, 5 * Years});
306 parameters->setEquityVolDecayMode("ConstantVariance");
307 parameters->setSimulateEquityVols(false);
308
309 // Config
310
311 // Build IR configurations
312 CalibrationType calibrationType = CalibrationType::Bootstrap;
313 LgmData::ReversionType revType = LgmData::ReversionType::HullWhite;
314 LgmData::VolatilityType volType = LgmData::VolatilityType::Hagan;
315 vector<string> swaptionExpiries = {"1Y", "2Y", "3Y", "5Y", "7Y", "10Y", "15Y", "20Y", "30Y"};
316 vector<string> swaptionTerms = {"5Y", "5Y", "5Y", "5Y", "5Y", "5Y", "5Y", "5Y", "5Y"};
317 vector<string> swaptionStrikes(swaptionExpiries.size(), "ATM");
318 vector<Time> hTimes = {};
319 vector<Time> aTimes = {};
320
321 std::vector<QuantLib::ext::shared_ptr<IrModelData>> irConfigs;
322
323 vector<Real> hValues = {0.02};
324 vector<Real> aValues = {0.008};
325 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
326 "EUR", calibrationType, revType, volType, false, ParamType::Constant, hTimes, hValues, true,
327 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
328
329 hValues = {0.03};
330 aValues = {0.009};
331 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
332 "USD", calibrationType, revType, volType, false, ParamType::Constant, hTimes, hValues, true,
333 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
334
335 hValues = {0.04};
336 aValues = {0.01};
337 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
338 "GBP", calibrationType, revType, volType, false, ParamType::Constant, hTimes, hValues, true,
339 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
340
341 hValues = {0.04};
342 aValues = {0.01};
343 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
344 "CHF", calibrationType, revType, volType, false, ParamType::Constant, hTimes, hValues, true,
345 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
346
347 hValues = {0.04};
348 aValues = {0.01};
349 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
350 "JPY", calibrationType, revType, volType, false, ParamType::Constant, hTimes, hValues, true,
351 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
352
353 // Compile FX configurations
354 vector<string> optionExpiries = {"1Y", "2Y", "3Y", "5Y", "7Y", "10Y"};
355 vector<string> optionStrikes(optionExpiries.size(), "ATMF");
356 vector<Time> sigmaTimes = {};
357
358 std::vector<QuantLib::ext::shared_ptr<FxBsData>> fxConfigs;
359
360 vector<Real> sigmaValues = {0.15};
361 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>("USD", "EUR", calibrationType, true, ParamType::Piecewise,
362 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
363
364 sigmaValues = {0.20};
365 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>("GBP", "EUR", calibrationType, true, ParamType::Piecewise,
366 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
367
368 sigmaValues = {0.20};
369 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>("CHF", "EUR", calibrationType, true, ParamType::Piecewise,
370 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
371
372 sigmaValues = {0.20};
373 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>("JPY", "EUR", calibrationType, true, ParamType::Piecewise,
374 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
375
376 map<CorrelationKey, Handle<Quote>> corr;
377 CorrelationFactor f_1{ CrossAssetModel::AssetType::IR, "EUR", 0 };
378 CorrelationFactor f_2{ CrossAssetModel::AssetType::IR, "USD", 0 };
379 corr[make_pair(f_1, f_2)] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.6));
380
381 QuantLib::ext::shared_ptr<CrossAssetModelData> config(QuantLib::ext::make_shared<CrossAssetModelData>(irConfigs, fxConfigs, corr));
382
383 // Model Builder & Model
384 // model builder
385 QuantLib::ext::shared_ptr<CrossAssetModelBuilder> modelBuilder(new CrossAssetModelBuilder(initMarket, config));
386 QuantLib::ext::shared_ptr<QuantExt::CrossAssetModel> model = *modelBuilder->model();
387 modelBuilder = NULL;
388
389 // Path generator
390 Size seed = 5;
391 bool antithetic = false;
392 if (auto tmp = QuantLib::ext::dynamic_pointer_cast<CrossAssetStateProcess>(model->stateProcess())) {
393 tmp->resetCache(dg->timeGrid().size() - 1);
394 }
395 QuantLib::ext::shared_ptr<QuantExt::MultiPathGeneratorBase> pathGen =
396 QuantLib::ext::make_shared<MultiPathGeneratorMersenneTwister>(model->stateProcess(), dg->timeGrid(), seed, antithetic);
397
398 // build scenario generator
399 QuantLib::ext::shared_ptr<ScenarioFactory> scenarioFactory = QuantLib::ext::make_shared<SimpleScenarioFactory>(true);
400 QuantLib::ext::shared_ptr<ScenarioGenerator> scenarioGenerator = QuantLib::ext::make_shared<CrossAssetModelScenarioGenerator>(
401 model, pathGen, scenarioFactory, parameters, today, dg, initMarket);
402
403 // build scenario sim market
404 convs();
405 auto simMarket = QuantLib::ext::make_shared<analytics::ScenarioSimMarket>(initMarket, parameters);
406 simMarket->scenarioGenerator() = scenarioGenerator;
407
408 // Build Portfolio
409 QuantLib::ext::shared_ptr<EngineData> data = QuantLib::ext::make_shared<EngineData>();
410 data->model("Swap") = "DiscountedCashflows";
411 data->engine("Swap") = "DiscountingSwapEngine";
412 QuantLib::ext::shared_ptr<EngineFactory> factory = QuantLib::ext::make_shared<EngineFactory>(data, simMarket);
413
414 QuantLib::ext::shared_ptr<Portfolio> portfolio = buildPortfolio(portfolioSize, factory);
415
416 BOOST_TEST_MESSAGE("Portfolio size after build: " << portfolio->size());
417
418 // Now calculate exposure
419 ValuationEngine valEngine(today, dg, simMarket);
420
421 // Calculate Cube
422 boost::timer::cpu_timer t;
423 QuantLib::ext::shared_ptr<NPVCube> cube =
424 QuantLib::ext::make_shared<DoublePrecisionInMemoryCube>(today, portfolio->ids(), dg->dates(), samples);
425 vector<QuantLib::ext::shared_ptr<ValuationCalculator>> calculators;
426 calculators.push_back(QuantLib::ext::make_shared<NPVCalculator>(baseCcy));
427 valEngine.buildCube(portfolio, cube, calculators);
428 t.stop();
429 double elapsed = t.elapsed().wall * 1e-9;
430
431 BOOST_TEST_MESSAGE("Cube generated in " << elapsed << " seconds");
432
433 Size dates = dg->dates().size();
434 Size numNPVs = dates * samples * portfolioSize;
435 BOOST_TEST_MESSAGE("Cube size = " << numNPVs << " elements");
436 BOOST_TEST_MESSAGE("Cube elements theoretical storage " << numNPVs * sizeof(Real) / (1024 * 1024) << " MB");
437 Real pricingTimeMicroSeconds = elapsed * 1000000 / numNPVs;
438 BOOST_TEST_MESSAGE("Avg Pricing time = " << pricingTimeMicroSeconds << " microseconds");
439
440 // Count the number of times we have an empty line, ie. swap expired.
441 // cube is trades/dates/samples
442 Size count = 0;
443 for (Size i = 0; i < portfolioSize; ++i) {
444 for (Size j = 0; j < dates; ++j) {
445 if (cube->get(i, j, 0) == 0 && cube->get(i, j, 1) == 0 && cube->get(i, j, 2) == 0)
446 ++count;
447 }
448 }
449 Real nonZeroPerc = 100 * (1 - (count / ((Real)portfolioSize * dates)));
450 BOOST_TEST_MESSAGE("Percentage of cube that is non-expired : " << nonZeroPerc << " %");
451 BOOST_TEST_MESSAGE("Avg Pricing time (for non-expired trades) = " << pricingTimeMicroSeconds * 100 / nonZeroPerc
452 << " microseconds");
453
454 // BOOST_TEST_MESSAGE(os::getSystemDetails());
455
456 // Compute portfolio EPE and ENE
457 vector<Real> eeVec, eneVec;
458 for (Size i = 0; i < dates; ++i) {
459 Real epe = 0.0, ene = 0.0;
460 for (Size j = 0; j < samples; ++j) {
461 Real npv = 0.0;
462 for (Size k = 0; k < portfolioSize; ++k)
463 npv += cube->get(k, i, j);
464 epe += std::max(npv, 0.0);
465 ene += std::max(-npv, 0.0);
466 }
467 epe /= samples;
468 ene /= samples;
469 // BOOST_TEST_MESSAGE("Exposures, " << i << " " << epe << " " << ene);
470 eeVec.push_back(epe);
471 eneVec.push_back(ene);
472 }
473
474 ObservationMode::instance().setMode(backupOm);
475 IndexManager::instance().clearHistories();
476
477 // check results
478 BOOST_CHECK_CLOSE(nonZeroPVRatio, nonZeroPerc, 0.005);
479
480 for (Size i = 0; i < epe_archived.size(); ++i) {
481 BOOST_CHECK_CLOSE(eeVec[i], epe_archived[i], 0.01);
482 }
483
484 for (Size i = 0; i < ene_archived.size(); ++i) {
485 BOOST_CHECK_CLOSE(eneVec[i], ene_archived[i], 0.01);
486 }
487}
488
489namespace {
490vector<Real> swap_epe_archived = {
491 0, 0, 0, 0, 0, 0, 0, 0, 0,
492 0, 0, 0, 0, 0, 0, 0, 0, 0,
493 0, 0, 0, 0, 0, 0, 0, 0, 0,
494 0, 0, 0, 0, 0, 0, 0, 0, 0,
495 0, 0, 0, 0, 0, 0, 0, 0, 0,
496 0, 0, 212.058, 0, 7323.56, 31533.6, 53382.9, 36210.1, 46908.3,
497 104101, 135755, 125789, 140937, 182967, 194282, 189492, 243649, 322158,
498 399840, 369531, 439146, 551159, 675010, 635516, 683456, 965534, 1.08921e+06,
499 1.12077e+06, 1.21563e+06, 1.74652e+06, 1.91117e+06, 1.93755e+06, 2.01838e+06, 2.74905e+06, 2.98333e+06};
500vector<Real> swap_ene_archived = {
501 3.68479e+08, 3.66947e+08, 3.59697e+08, 3.67679e+08, 3.60306e+08, 3.60215e+08, 3.3379e+08, 3.33075e+08, 3.26284e+08,
502 3.25852e+08, 3.00194e+08, 2.9983e+08, 2.92797e+08, 2.93767e+08, 2.69069e+08, 2.70243e+08, 2.64709e+08, 2.66009e+08,
503 2.46285e+08, 2.45916e+08, 2.40391e+08, 2.40419e+08, 2.2e+08, 2.20437e+08, 2.13037e+08, 2.13986e+08, 1.94195e+08,
504 1.94421e+08, 1.87828e+08, 1.87927e+08, 1.69285e+08, 1.70055e+08, 1.6356e+08, 1.64559e+08, 1.47753e+08, 1.49094e+08,
505 1.4273e+08, 1.44247e+08, 1.32027e+08, 1.37083e+08, 1.30631e+08, 1.30188e+08, 1.17919e+08, 1.2013e+08, 1.13388e+08,
506 1.13037e+08, 1.00704e+08, 1.04901e+08, 9.77921e+07, 9.74493e+07, 8.64101e+07, 9.05223e+07, 8.41554e+07, 8.52514e+07,
507 7.45642e+07, 8.01076e+07, 7.34561e+07, 7.66085e+07, 6.86271e+07, 7.33344e+07, 6.48527e+07, 6.82275e+07, 6.10455e+07,
508 6.35091e+07, 5.59015e+07, 5.9265e+07, 5.24219e+07, 5.57625e+07, 4.78619e+07, 5.11772e+07, 4.44675e+07, 4.7471e+07,
509 3.98948e+07, 4.31879e+07, 3.70144e+07, 4.01379e+07, 3.26652e+07, 3.64379e+07, 3.0582e+07, 3.35157e+07};
510vector<Real> single_swap_epe_archived = {
511 8422.98, 11198.9, 15557.4, 22182, 24516.4, 22732.1, 24476.9, 30633, 32463.9, 28580.7, 29797.8, 34821.8,
512 35793, 31445.1, 31422.2, 35379.4, 36714.7, 32177, 33110.1, 36914.5, 38422.1, 33316.3, 33986.7, 37881,
513 39304, 34202.6, 34476.6, 37839.7, 38556.6, 33053.6, 34179, 37797.4, 38292.6, 33090.8, 33802.5, 37408.1,
514 37883.6, 32242.8, 32895.4, 35663.4, 36200.2, 30599.5, 31125.9, 33598.7, 33774.8, 27908.2, 28321.2, 30594.3,
515 30704.6, 24996.5, 25220.1, 27476.1, 27992.3, 22261.9, 22504.1, 24273.5, 24606.4, 19184.2, 19377.9, 21040.2,
516 21286.6, 15787.3, 15905.9, 17288.6, 17438.9, 11921.9, 12042.2, 13379.9, 13566.2, 8143.05, 8244.83, 9312.29,
517 9336.46, 4025.82, 4011.94, 4742.76, 4713.78, 387.137, 386.445, 0};
518vector<Real> single_swap_ene_archived = {
519 15211, 23792.4, 25714.7, 21833.1, 24449.6, 30276.1, 31685.9, 28404.2, 30148.2, 35386.3, 36348.7, 31486.9,
520 32452.8, 37586.7, 39033.4, 34616.2, 35485, 40388.1, 40796.5, 35500.3, 37113.1, 40726.3, 41758, 36558.1,
521 37032.1, 40501.5, 41314.7, 36470.8, 37160.9, 39548.5, 39862.6, 33665.1, 34444.8, 37206.8, 37686.3, 32158.8,
522 32323.1, 34521.5, 35197.2, 30809.5, 31219.3, 33447.7, 34164.7, 28843.5, 29113.5, 32074.7, 32535.9, 28093.2,
523 27974.4, 30230.9, 30332.1, 25129.8, 25444.3, 27196.1, 27727.5, 22541, 22624.1, 24869.2, 25036.5, 19195.8,
524 19036.7, 21082.3, 21592.8, 15735.4, 15809.9, 17752.2, 17959.4, 12408.9, 12507, 13937.8, 14004.1, 8403.95,
525 8375.73, 10190.9, 10229.5, 4311.76, 4277.57, 6773.51, 6779.33, 0};
526} // namespace
527
528BOOST_AUTO_TEST_CASE(testSwapPerformanceNoneObs) {
529 BOOST_TEST_MESSAGE("Testing Swap Performance (None observation mode)");
530 test_performance(100, ObservationMode::Mode::None, 70.5875, swap_epe_archived, swap_ene_archived);
531}
532
533BOOST_AUTO_TEST_CASE(testSingleSwapPerformanceNoneObs) {
534 BOOST_TEST_MESSAGE("Testing Single Swap Performance (None observation mode)");
535 test_performance(1, ObservationMode::Mode::None, 98.75, single_swap_epe_archived, single_swap_ene_archived);
536}
537
538BOOST_AUTO_TEST_CASE(testSwapPerformanceDisableObs) {
539 BOOST_TEST_MESSAGE("Testing Swap Performance (Disable observation mode)");
540 test_performance(100, ObservationMode::Mode::None, 70.5875, swap_epe_archived, swap_ene_archived);
541}
542
543BOOST_AUTO_TEST_CASE(testSingleSwapPerformanceDisableObs) {
544 BOOST_TEST_MESSAGE("Testing Single Swap Performance (Disable observation mode)");
545 test_performance(1, ObservationMode::Mode::None, 98.75, single_swap_epe_archived, single_swap_ene_archived);
546}
547
548BOOST_AUTO_TEST_CASE(testSwapPerformanceDeferObs) {
549 BOOST_TEST_MESSAGE("Testing Swap Performance (Defer observation mode)");
550 test_performance(100, ObservationMode::Mode::None, 70.5875, swap_epe_archived, swap_ene_archived);
551}
552
553BOOST_AUTO_TEST_CASE(testSingleSwapPerformanceDeferObs) {
554 BOOST_TEST_MESSAGE("Testing Single Swap Performance (Defer observation mode)");
555 test_performance(1, ObservationMode::Mode::None, 98.75, single_swap_epe_archived, single_swap_ene_archived);
556}
557
558BOOST_AUTO_TEST_CASE(testSwapPerformanceUnregisterObs) {
559 BOOST_TEST_MESSAGE("Testing Swap Performance (Unregister observation mode)");
560 test_performance(100, ObservationMode::Mode::None, 70.5875, swap_epe_archived, swap_ene_archived);
561}
562
563BOOST_AUTO_TEST_CASE(testSingleSwapPerformanceUnregisterObs) {
564 BOOST_TEST_MESSAGE("Testing Single Swap Performance (Unregister observation mode)");
565 test_performance(1, ObservationMode::Mode::None, 98.75, single_swap_epe_archived, single_swap_ene_archived);
566}
567
568BOOST_AUTO_TEST_SUITE_END()
569
570BOOST_AUTO_TEST_SUITE_END()
void buildCube(const QuantLib::ext::shared_ptr< data::Portfolio > &portfolio, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCube, std::vector< QuantLib::ext::shared_ptr< ValuationCalculator > > calculators, bool mporStickyDate=true, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCubeNettingSet=nullptr, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCptyCube=nullptr, std::vector< QuantLib::ext::shared_ptr< CounterpartyCalculator > > cptyCalculators={}, bool dryRun=false)
Build NPV cube.
OREAnalytics Top level fixture.
Simple flat market setup to be used in the test suite.
Definition: testmarket.hpp:64
Scenario generation using cross asset model paths.
Class that wraps a sensitivity stream and filters out negligible records.
A cube implementation that stores the cube in memory.
data
Time maturity
RandomVariable max(RandomVariable x, const RandomVariable &y)
RandomVariable min(RandomVariable x, const RandomVariable &y)
CalibrationType
The base NPV cube class.
Singleton class to hold global Observation Mode.
Fixture that can be used at top level of OREAnalytics test suites.
std::size_t count
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.
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.
unsigned long randInt(MersenneTwisterUniformRng &rng, Size min, Size max)
bool randBoolean(MersenneTwisterUniformRng &rng)
BOOST_AUTO_TEST_CASE(testSwapPerformanceNoneObs)
const string & randString(MersenneTwisterUniformRng &rng, const vector< string > &strs)
QuantLib::ext::shared_ptr< Portfolio > buildPortfolio(Size portfolioSize, QuantLib::ext::shared_ptr< EngineFactory > &factory)
void test_performance(Size portfolioSize, ObservationMode::Mode om, double nonZeroPVRatio, vector< Real > &epe_archived, vector< Real > &ene_archived)
QuantLib::ext::shared_ptr< data::Conventions > convs()
The counterparty cube calculator interface.
The cube valuation core.