Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
stoplightbounds.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 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 "toplevelfixture.hpp"
20
21#include <boost/test/unit_test.hpp>
22#include <boost/make_shared.hpp>
23
25
26using namespace QuantLib;
27using namespace QuantExt;
28
29using namespace boost::unit_test_framework;
30using std::vector;
31
32BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
33
34BOOST_AUTO_TEST_SUITE(StopLightBoundsTest)
35
36BOOST_AUTO_TEST_CASE(testSinglePortfolioAgainstReferenceResults) {
37 BOOST_TEST_MESSAGE("Testing single portfolio stoplight bounds against reference results");
38
39 std::vector<Real> psl = {0.95, 0.9999};
40
41 // in general an even higher number of samples may be required to match all the reference results
42 Size samples = 5000000;
43 Size seed = 42;
44 Real p = 0.99;
45 Size days = 10;
46
47 static const std::vector<Size> obs = {200, 300, 500}; // avoid too long running time
48
49 BOOST_TEST_MESSAGE(
50 "Observations MaxExceed Green (computed/expected) MaxExceedences Amber (computed/expected)");
51
52 for (Size i = 0; i < obs.size(); ++i) {
53 auto b = stopLightBounds(psl, obs[i], days, p, 1, Matrix(1, 1, 1.0), samples, seed);
54 auto tab = stopLightBoundsTabulated(psl, obs[i], days, p);
55 BOOST_TEST_MESSAGE(std::right << std::setw(10) << obs[i] << std::setw(28)
56 << (std::to_string(b[0]) + " / " + std::to_string(tab[0])) << std::setw(38)
57 << (std::to_string(b[1]) + " / " + std::to_string(tab[1])));
58 BOOST_CHECK_EQUAL(b[0], tab[0]);
59 BOOST_CHECK_EQUAL(b[1], tab[1]);
60 }
61} // testSinglePortfolioAgainstReferenceResults
62
63BOOST_AUTO_TEST_CASE(testMultiplePortfoliosAgainstReferenceResults) {
64 BOOST_TEST_MESSAGE("Testing multiple portfolios stoplight bounds against reference results");
65
66 // see ISDA SIMM Backtesting Report, 14Feb17, section 15.3
67 static const std::vector<Size> tab = {19, 51};
68
69 std::vector<Real> psl = {0.95, 0.9999};
70
71 Size samples = 1500000;
72 Size seed = 42;
73 Real p = 0.99;
74 Size days = 10;
75 Size portfolios = 3;
76 Matrix correlation(3, 3);
77
78 for (Size i = 0; i < 3; ++i) {
79 for (Size j = 0; j < 3; ++j) {
80 correlation[i][j] = i == j ? 1.0 : 0.5;
81 }
82 }
83
84 static const std::vector<Size> obs = {250};
85
86 BOOST_TEST_MESSAGE(
87 "Observations MaxExceed Green (computed/expected) MaxExceedences Amber (computed/expected)");
88
89 for (Size i = 0; i < obs.size(); ++i) {
90 auto b = stopLightBounds(psl, obs[i], days, p, portfolios, correlation, samples, seed);
91 BOOST_TEST_MESSAGE(std::right << std::setw(10) << obs[i] << std::setw(28)
92 << (std::to_string(b[0]) + " / " + std::to_string(tab[0])) << std::setw(38)
93 << (std::to_string(b[1]) + " / " + std::to_string(tab[1])));
94 BOOST_CHECK_EQUAL(b[0], tab[0]);
95 BOOST_CHECK_EQUAL(b[1], tab[1]);
96 }
97} // testMultiplePortfoliosAgainstReferenceResults
98
99BOOST_AUTO_TEST_CASE(testIidBoundsAgainstReferenceResults) {
100 BOOST_TEST_MESSAGE("Testing iid bounds against reference results");
101 /* see SUPERVISORY FRAMEWORK FOR THE USE OF "BACKTESTING" IN CONJUNCTION WITH THE
102 INTERNAL MODELS APPROACH TO MARKET RISK CAPITAL REQUIREMENTS,
103 Basle Committee on Banking Supervision January 1996
104 http://www.bis.org/publ/bcbs22.pdf */
105 auto bounds = stopLightBounds({0.95, 0.9999}, 250, 0.99);
106 BOOST_CHECK_EQUAL(bounds[0], 4);
107 BOOST_CHECK_EQUAL(bounds[1], 9);
108 Real cumProb = 0.0;
109 std::vector<Real> exp = {0.0811, 0.2858, 0.5432, 0.7581, 0.8922, 0.9588, 0.9863, 0.9960, 0.9989, 0.9997, 0.9999};
110 for (Size i = 0; i <= 10; ++i) {
111 stopLightBounds({0.95, 0.99}, 250, 0.99, i, &cumProb);
112 BOOST_CHECK_SMALL(cumProb - exp[i], 0.0001);
113 }
114} // testIidBoundsAgainstReferenceResults
115
116// this test case runs apprx. 4 min because of the high number of samples used and is therefore disabled by default
117// FIXME the test fails on several tabulated values, both with 5m and 50m samples (see ORE ticket 1383 for details)
118BOOST_AUTO_TEST_CASE(testGenerateStopLightBoundTable, *boost::unit_test::disabled()) {
119 BOOST_TEST_MESSAGE("Testing generating stop light bounds table against reference results");
120
121 std::vector<Size> obs = {
122 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120,
123 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350,
124 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580,
125 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800, 810,
126 820, 830, 840, 850, 860, 870, 880, 890, 900, 910, 920, 930, 940, 950, 960, 970, 980, 990, 1000, 1010, 1020, 1030,
127 1040, 1050, 1060, 1070, 1080, 1090, 1100, 1110, 1120, 1130, 1140, 1150, 1160, 1170, 1180, 1190, 1200, 1210, 1220,
128 1230, 1240, 1250, 1260, 1270, 1280, 1290, 1300, 1310, 1320, 1330, 1340, 1350, 1360, 1370, 1380, 1390, 1400, 1410,
129 1420, 1430, 1440, 1450, 1460, 1470, 1480, 1490, 1500, 1510, 1520, 1530, 1540, 1550, 1560, 1570, 1580, 1590, 1600,
130 1610, 1620, 1630, 1640, 1650, 1660, 1670, 1680, 1690, 1700, 1710, 1720, 1730, 1740, 1750, 1760, 1770, 1780, 1790,
131 1800, 1810, 1820, 1830, 1840, 1850, 1860, 1870, 1880, 1890, 1900, 1910, 1920, 1930, 1940, 1950, 1960, 1970, 1980,
132 1990, 2000, 2010, 2020, 2030, 2040, 2050, 2060, 2070, 2080, 2090, 2100, 2110, 2120, 2130, 2140, 2150, 2160, 2170,
133 2180, 2190, 2200, 2210, 2220, 2230, 2240, 2250, 2260, 2270, 2280, 2290, 2300, 2310, 2320, 2330, 2340, 2350, 2360,
134 2370, 2380, 2390, 2400, 2410, 2420, 2430, 2440, 2450, 2460, 2470, 2480, 2490, 2500, 2510, 2520, 2530, 2540, 2550,
135 2560, 2570, 2580, 2590, 2600, 2610, 2620, 2630, 2640, 2650, 2660, 2670, 2680, 2690, 2700, 2710, 2720, 2730, 2740,
136 2750, 2760, 2770, 2780, 2790, 2800, 2810, 2820, 2830, 2840, 2850, 2860, 2870, 2880, 2890, 2900, 2910, 2920, 2930,
137 2940, 2950, 2960, 2970, 2980, 2990, 3000, 3010, 3020, 3030, 3040, 3050, 3060, 3070, 3080, 3090, 3100, 3110, 3120,
138 3130, 3140, 3150, 3160, 3170, 3180, 3190, 3200, 3210, 3220, 3230, 3240, 3250, 3260, 3270, 3280, 3290, 3300, 3310,
139 3320, 3330, 3340, 3350, 3360, 3370, 3380, 3390, 3400, 3410, 3420, 3430, 3440, 3450, 3460, 3470, 3480, 3490, 3500,
140 3510, 3520, 3530, 3540, 3550, 3560, 3570, 3580, 3590, 3600, 3610, 3620, 3630, 3640, 3650, 3660, 3670, 3680, 3690
141 };
142 std::vector<Real> psl = {0.95, 0.9999};
143 Size samples = 100000000;
144 Size seed = 42;
145 Real p = 0.99;
146 Size days = 10;
147
148 auto table = generateStopLightBoundTable(obs, psl, samples, seed, days, p);
149 BOOST_REQUIRE(table.size() == obs.size());
150
151 BOOST_TEST_MESSAGE(
152 "Observations MaxExceed Green (computed/expected) MaxExceedences Amber (computed/expected)");
153
154 for (Size i = 0; i < obs.size(); ++i) {
155 BOOST_REQUIRE(table[i].first == obs[i]);
156 BOOST_REQUIRE(table[i].second.size() == psl.size());
157 auto tab = stopLightBoundsTabulated(psl, obs[i], days, p);
158 BOOST_TEST_MESSAGE(std::right << std::setw(10) << obs[i] << std::setw(28)
159 << (std::to_string(table[i].second[0]) + " / " + std::to_string(tab[0]))
160 << std::setw(38)
161 << (std::to_string(table[i].second[1]) + " / " + std::to_string(tab[1])));
162 BOOST_CHECK_EQUAL(table[i].second[0], tab[0]);
163 BOOST_CHECK_EQUAL(table[i].second[1], tab[1]);
164 }
165}
166
167BOOST_AUTO_TEST_SUITE_END()
168
169BOOST_AUTO_TEST_SUITE_END()
std::vector< Size > stopLightBoundsTabulated(const std::vector< Real > &stopLightP, const Size observations, const Size numberOfDays, const Real p)
std::vector< std::pair< Size, std::vector< Size > > > generateStopLightBoundTable(const std::vector< Size > &observations, const std::vector< Real > &stopLightP, const Size samples, const Size seed, const Size numberOfDays, const Real p)
CompiledFormula exp(CompiledFormula x)
std::vector< Size > stopLightBounds(const std::vector< Real > &stopLightP, const Size observations, const Size numberOfDays, const Real p, const Size numberOfPortfolios, const Matrix &correlation, const Size samples, const Size seed, const SalvagingAlgorithm::Type salvaging, const Size exceptions, Real *cumProb)
compute stop light bounds for overlapping and correlated PL
BOOST_AUTO_TEST_CASE(testSinglePortfolioAgainstReferenceResults)
Fixture that can be used at top level.