Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
deltagammavar.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 "toplevelfixture.hpp"
20#include <boost/test/unit_test.hpp>
21
23
25
26#include <boost/make_shared.hpp>
27#include <boost/math/distributions/chi_squared.hpp>
28
29using namespace QuantLib;
30using namespace QuantExt;
31
32using namespace boost::unit_test_framework;
33using std::vector;
34
35namespace {
36void test(const Size dim, const bool nonzeroDelta, const bool nonzeroGamma, const Size seedParam, const Size seedMc,
37 const Size paths) {
38
39 BOOST_TEST_MESSAGE("################ Testing delta gamma VaR, dim=" << dim << ", delta=" << nonzeroDelta
40 << ", gamma=" << nonzeroGamma
41 << ", paths=" << paths << "\n");
42
43 MersenneTwisterUniformRng mt(seedParam);
44
45 // generate random covariance matrix
46
47 BOOST_TEST_MESSAGE("Generate transformation matrix L");
48 Matrix L(dim, dim, 0.0);
49 Real det = 0.0;
50 do {
51 for (Size i = 0; i < dim; ++i) {
52 for (Size j = 0; j < dim; ++j) {
53 L[i][j] = mt.nextReal();
54 }
55 }
56 det = determinant(L);
57 BOOST_TEST_MESSAGE("... done, determinant is " << det);
58 } while (close_enough(det, 0.0));
59
60 Matrix omega = transpose(L) * L;
61
62 // scale entries such that they have order of magnitude 0.1
63 Real num = QuantExt::detail::absMax(omega);
64 omega /= num * 10.0;
65
66 // generate random delta vector
67
68 BOOST_TEST_MESSAGE("Generate delta");
69 Array delta(dim, 0.0);
70 if (nonzeroDelta) {
71 for (Size i = 0; i < dim; ++i) {
72 delta[i] = mt.nextReal() * 1000.0 - 500.0;
73 }
74 }
75
76 // generate random gamma matrix, TODO negative gammas?
77
78 BOOST_TEST_MESSAGE("Generate gamma");
79 Matrix gamma(dim, dim, 0.0), shift(dim, dim, 0.0);
80 if (nonzeroGamma) {
81 for (Size i = 0; i < dim; ++i) {
82 for (Size j = 0; j < i; ++j) {
83 gamma[i][j] = gamma[j][i] = mt.nextReal() * 1000.0; // - 500.0;
84 }
85 gamma[i][i] = mt.nextReal() * 1000.0; // - 500.0;
86 }
87 }
88
89 BOOST_TEST_MESSAGE("delta=" << delta);
90 if (gamma.rows() <= 20) {
91 BOOST_TEST_MESSAGE("\ngamma=\n" << gamma);
92 BOOST_TEST_MESSAGE("omega=\n" << omega);
93 } else {
94 BOOST_TEST_MESSAGE("\ngamma= too big to display (" << gamma.rows() << "x" << gamma.columns() << ")");
95 BOOST_TEST_MESSAGE("omega= too big to display (" << omega.rows() << "x" << omega.columns() << ")\n");
96 }
97
98 // check results against MC simulation
99
100 std::vector<Real> quantiles = {0.9, 0.95, 0.99, 0.999, 0.9999};
101
102 BOOST_TEST_MESSAGE("Run MC simulation...");
103 Matrix nullGamma(dim, dim, 0.0);
104 auto mc1All = deltaGammaVarMc<PseudoRandom>(omega, delta, nullGamma, quantiles, paths, seedMc);
105 auto mc2All = deltaGammaVarMc<PseudoRandom>(omega, delta, gamma, quantiles, paths, seedMc);
106 BOOST_TEST_MESSAGE("MC simulation Done.");
107
108 BOOST_TEST_MESSAGE(" Quantile dVaR(MC) dgVaR(MC) dVaR(Mdl) dgVaR(CF) dgVaR(SD) "
109 "err(CF)% err(SD)%");
110 BOOST_TEST_MESSAGE("==============================================================================================="
111 "=================");
112
113 Size i = 0;
114 for (auto const& q : quantiles) {
115
116 Real mc1 = mc1All[i];
117 Real mc2 = mc2All[i++];
118
119 Real dVar = deltaVar(omega, delta, q);
120 Real dgVarCf = deltaGammaVarCornishFisher(omega, delta, gamma, q);
121 Real dgVarSd = deltaGammaVarSaddlepoint(omega, delta, gamma, q);
122 Real errCf = (dgVarCf - mc2) / mc2 * 100.0;
123 Real errSd = (dgVarSd - mc2) / mc2 * 100.0;
124
125 BOOST_TEST_MESSAGE(std::right << std::setw(14) << q << std::setw(14) << mc1 << std::setw(14) << mc2
126 << std::setw(14) << dVar << std::setw(14) << dgVarCf << std::setw(14) << dgVarSd
127 << std::setw(14) << errCf << std::setw(14) << errSd);
128
129 BOOST_CHECK_CLOSE(dVar, mc1, 5.0);
130 BOOST_CHECK_CLOSE(dgVarCf, mc2, 15.0);
131 BOOST_CHECK_CLOSE(dgVarSd, mc2, 5.0);
132 }
133
134 BOOST_TEST_MESSAGE("==============================================================================================="
135 "===============\n\n");
136
137} // test
138} // anonymous namespace
139
140BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
141
142BOOST_AUTO_TEST_SUITE(DeltaGammaVarTest)
143
144BOOST_AUTO_TEST_CASE(testDeltaGammaVar) {
145
146 // TODO test Daniel's approx. explicitly (khat < 1E-5)
147 // TODO add more test cases (negative gammas, higher dimensions)
148
149 Size n = (Size)400000;
150
151 test(1, true, false, 42, 42, n);
152 test(1, false, true, 42, 42, n);
153 test(1, true, true, 42, 42, n);
154
155 test(2, true, false, 42, 42, n);
156 test(2, false, true, 42, 42, n);
157 test(2, true, true, 42, 42, n);
158
159 test(10, true, false, 42, 42, n);
160 test(10, false, true, 42, 42, n);
161 test(10, true, true, 42, 42, n);
162
163 // fewer paths here
164 test(100, true, false, 42, 42, n);
165 test(100, false, true, 42, 42, n);
166 test(100, true, true, 42, 42, n);
167}
168
169BOOST_AUTO_TEST_CASE(testNegativeGamma) {
170
171 BOOST_TEST_MESSAGE("Testing delta gamma var for pl = -u^2, u standard normal...");
172
173 // choose n=1, gamma=-10k, omega = 1, then the pl is -0.5*u^2 with
174 // u standard normal, in other words -2pl is chi-squared
175 // distributed with one degree of freedom
176
177 boost::math::chi_squared_distribution<Real> chisq(1.0);
178
179 Real gamma = -10000.0;
180
181 Array delta(1, 0.0);
182 Matrix gamma_m(1, 1, gamma);
183 Matrix omega(1, 1, 1.0);
184
185 Real p = 0.99;
186
187 Real var_mc = deltaGammaVarMc<PseudoRandom>(omega, delta, gamma_m, p, 1000000, 142);
188 Real var_cf = deltaGammaVarCornishFisher(omega, delta, gamma_m, p);
189 Real var_sd = deltaGammaVarSaddlepoint(omega, delta, gamma_m, p);
190
191 Real refVal = 0.5 * gamma * boost::math::quantile(chisq, 1.0 - p);
192
193 BOOST_TEST_MESSAGE("mc = " << var_mc);
194 BOOST_TEST_MESSAGE("cf = " << var_cf);
195 BOOST_TEST_MESSAGE("sd = " << var_sd);
196 BOOST_TEST_MESSAGE("ref = " << refVal);
197
198 // the AS269 function in R (pacakge PDQutils) produces this
199 BOOST_CHECK_SMALL(std::abs(-4707.882 - var_cf), 0.001);
200
201 BOOST_CHECK_SMALL(std::abs(refVal - var_sd), 0.5);
202 BOOST_CHECK_SMALL(std::abs(refVal - var_mc), 0.5);
203}
204
206 // fails as of 05-Sep-2017, fixed with commit 71c736873
207 BOOST_TEST_MESSAGE("Running regression test case 001...");
208 std::vector<double> d1{691.043, 8.62406, 9706.97, 0, 0};
209 std::vector<double> d2 = {-13.9605, 0, 0, 0, 0, 0, -0.174223, 0, 0, 0, 0, 0, -196.1,
210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
211 std::vector<double> d3 = {96.3436, -0.828459, -6.59142, 0.583848, -0.0639266, -0.828459, 97.7309,
212 12.4906, -2.03511, -0.504752, -6.59142, 12.4906, 95.12, 0.800706,
213 0.443861, 0.583848, -2.03511, 0.800706, 2.71239, 0.288881, -0.0639266,
214 -0.504752, 0.443861, 0.288881, 1.42701};
215 Array delta(d1.begin(), d1.end());
216 Matrix gamma(5, 5, d2.begin(), d2.end());
217 Matrix omega(5, 5, d3.begin(), d3.end());
218 Real var = deltaGammaVarSaddlepoint(omega, delta, gamma, 0.99);
219 Real var_mc = deltaGammaVarMc<PseudoRandom>(omega, delta, gamma, 0.99, 1000000, 42);
220 BOOST_TEST_MESSAGE("sd = " << var);
221 BOOST_TEST_MESSAGE("mc = " << var_mc);
222 BOOST_CHECK_CLOSE(var, var_mc, 0.5);
223}
224
226 // failed as of 05-Sep-2018
227 BOOST_TEST_MESSAGE("Running regression test case 002...");
228
229 // similar setup to testNegativeGamma(), but with higher variance and positive gamma
230 boost::math::chi_squared_distribution<Real> chisq(1.0);
231
232 Array delta(1, 0.0);
233 Matrix gamma(1, 1, 1.0);
234 Matrix omega(1, 1, 1.0E6);
235 Real p = 0.99;
236
237 Real var_sd = deltaGammaVarSaddlepoint(omega, delta, gamma, p);
238 Real refVal = 0.5 * 1E6 * boost::math::quantile(chisq, p);
239 Real var_mc = deltaGammaVarMc<PseudoRandom>(omega, delta, gamma, p, 1000000, 42);
240
241 BOOST_TEST_MESSAGE("sd = " << var_sd);
242 BOOST_TEST_MESSAGE("mc = " << var_mc);
243 BOOST_TEST_MESSAGE("ref = " << refVal);
244
245 BOOST_CHECK_CLOSE(refVal, var_sd, 1.0);
246}
247
249 // failed in the Q3-BT 2018
250 BOOST_TEST_MESSAGE("Running regression test case 003...");
251
252 // Salvaged covariance matrix
253 vector<Real> data{
254 11.357910440165, 0.301883284121, 1.690565094559, 0.028921366715, 1.445952963717, 2.683104461304,
255 2.975281862097, 0.284778609491, 3.977509941411, 2.700492214606, 3.973616990595, 1.842042909216,
256 4.507630684591, 2.188574976899, 1.839870252197, 1.653581957759, 0.301883284121, 1.545170636908,
257 1.140841711137, 0.011046063984, 0.223680967726, 0.926416050189, 0.637660185458, 1.634591590508,
258 0.328944419108, -0.321306872147, 0.490226761216, -0.228872084003, -0.466954542255, 0.908486575719,
259 1.208420546045, 1.057641385035, 1.690565094559, 1.140841711137, 4.590122578368, 0.016138328046,
260 1.681703229533, 2.722501254257, 2.941664204785, 4.088913570167, 0.753207493946, 0.750845717386,
261 2.327852200648, -0.083383166375, 0.791187240585, 3.432410532424, 4.576488134589, 4.484608491882,
262 0.028921366715, 0.011046063984, 0.016138328046, 0.003321196784, -0.002052702116, 0.015027345216,
263 0.025225956444, 0.009488292952, 0.023036962659, 0.003752073385, 0.025786900243, 0.004902517590,
264 0.017973354395, 0.013380695889, 0.016450708955, 0.015793906816, 1.445952963717, 0.223680967726,
265 1.681703229533, -0.002052702116, 5.051235107717, 1.504449552996, 1.411232675828, -0.066709336186,
266 0.740371793190, 0.922017945905, 1.423545223509, 0.592880234568, 1.318219401490, 1.512119827471,
267 1.709049165903, 1.651695766740, 2.683104461304, 0.926416050189, 2.722501254257, 0.015027345216,
268 1.504449552996, 5.896840384423, 2.736094553275, 2.318419864064, 2.683772279561, 0.869866043995,
269 2.795123680474, 0.233284568353, 1.954971283941, 2.638478800353, 2.962854214006, 2.999498221322,
270 2.975281862097, 0.637660185458, 2.941664204785, 0.025225956444, 1.411232675828, 2.736094553275,
271 3.730376993077, 2.574152890379, 2.332889913708, 1.012628826625, 2.401055859072, 0.425908702537,
272 2.104222769101, 2.846640151863, 3.254007639538, 3.174532782066, 0.284778609491, 1.634591590508,
273 4.088913570167, 0.009488292952, -0.066709336186, 2.318419864064, 2.574152890379, 8.346545067056,
274 0.111146561779, 0.061442388170, 1.440123839301, -0.532880568392, -0.363306461515, 3.164184153356,
275 4.239774387395, 4.222873062980, 3.977509941411, 0.328944419108, 0.753207493946, 0.023036962659,
276 0.740371793190, 2.683772279561, 2.332889913708, 0.111146561779, 7.816500777128, 1.306158501267,
277 1.892772141649, 1.533232314993, 2.966214070512, 1.981467787886, 0.858479274405, 0.688098796909,
278 2.700492214606, -0.321306872147, 0.750845717386, 0.003752073385, 0.922017945905, 0.869866043995,
279 1.012628826625, 0.061442388170, 1.306158501267, 3.255129750500, 1.447265157820, 1.646805443131,
280 2.024131319493, 0.823110422895, 0.661139572160, 0.726470332699, 3.973616990595, 0.490226761216,
281 2.327852200648, 0.025786900243, 1.423545223509, 2.795123680474, 2.401055859072, 1.440123839301,
282 1.892772141649, 1.447265157820, 9.307941714908, 1.003272291798, 2.960270274699, 2.637484069448,
283 2.395034154720, 2.407859255045, 1.842042909216, -0.228872084003, -0.083383166375, 0.004902517590,
284 0.592880234568, 0.233284568353, 0.425908702537, -0.532880568392, 1.533232314993, 1.646805443131,
285 1.003272291798, 2.715163222630, 1.397890009325, 0.370386734188, -0.170205201951, -0.252456813317,
286 4.507630684591, -0.466954542255, 0.791187240585, 0.017973354395, 1.318219401490, 1.954971283941,
287 2.104222769101, -0.363306461515, 2.966214070512, 2.024131319493, 2.960270274699, 1.397890009325,
288 12.145104529503, 1.291504589690, 0.751431588477, 0.731038259921, 2.188574976899, 0.908486575719,
289 3.432410532424, 0.013380695889, 1.512119827471, 2.638478800353, 2.846640151863, 3.164184153356,
290 1.981467787886, 0.823110422895, 2.637484069448, 0.370386734188, 1.291504589690, 3.304040607934,
291 3.654236283615, 3.549318308813, 1.839870252197, 1.208420546045, 4.576488134589, 0.016450708955,
292 1.709049165903, 2.962854214006, 3.254007639538, 4.239774387395, 0.858479274405, 0.661139572160,
293 2.395034154720, -0.170205201951, 0.751431588477, 3.654236283615, 5.109964090288, 4.959183419230,
294 1.653581957759, 1.057641385035, 4.484608491882, 0.015793906816, 1.651695766740, 2.999498221322,
295 3.174532782066, 4.222873062980, 0.688098796909, 0.726470332699, 2.407859255045, -0.252456813317,
296 0.731038259921, 3.549318308813, 4.959183419230, 5.024852085655};
297 Matrix covar(16, 16, data.begin(), data.end());
298
299 // Gamma matrix, all 0 except g[15,15] = -0.000000000262
300 Matrix gamma(16, 16, 0.0);
301 gamma[14][14] = -0.000000000262;
302
303 // Delta array, all 0 except d[15] = -247189.692289613
304 Array delta(16, 0.0);
305 delta[14] = -247189.692289613;
306
307 // Try the saddlepoint VAR
308 Real p = 0.99;
309 Real sdvar = deltaGammaVarSaddlepoint(covar, delta, gamma, p);
310 BOOST_TEST_MESSAGE("sdvar=" << sdvar);
311
312 // Try the monte-carlo VAR
313 Real mcvar = deltaGammaVarMc<PseudoRandom>(covar, delta, gamma, p, 1000000, 42);
314 BOOST_TEST_MESSAGE("mcvar=" << mcvar);
315
316 // Check saddlepoint and monte-carlo results are close
317 BOOST_CHECK_CLOSE(sdvar, mcvar, 1.0);
318}
319
320BOOST_AUTO_TEST_SUITE_END()
321
322BOOST_AUTO_TEST_SUITE_END()
functions to compute delta or delta-gamma VaR numbers
Real absMax(const A &a)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Real deltaGammaVarCornishFisher(const Matrix &omega, const Array &delta, const Matrix &gamma, const Real p, const CovarianceSalvage &sal)
Real deltaVar(const Matrix &omega, const Array &delta, const Real p, const CovarianceSalvage &sal)
function that computes a delta VaR
Real deltaGammaVarSaddlepoint(const Matrix &omega, const Array &delta, const Matrix &gamma, const Real p, const CovarianceSalvage &sal)
BOOST_AUTO_TEST_CASE(testDeltaGammaVar)
Fixture that can be used at top level.