Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crossassetmodelparametrizations.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 "utilities.hpp"
20
21#include "toplevelfixture.hpp"
22#include <boost/test/unit_test.hpp>
23#include <ql/currencies/america.hpp>
24#include <ql/currencies/europe.hpp>
25#include <ql/math/array.hpp>
26#include <ql/math/comparison.hpp>
27#include <ql/quotes/simplequote.hpp>
28#include <ql/termstructures/yield/flatforward.hpp>
29#include <ql/time/calendars/nullcalendar.hpp>
54#include <qle/models/lgm.hpp>
61
62#include <boost/make_shared.hpp>
63
64using namespace QuantLib;
65using namespace QuantExt;
66
67using boost::unit_test_framework::test_suite;
68
69namespace {
70
71// check for expected result up to round off errors
72void check(const std::string& s, const Real x, const Real y, const Real e, const Size n = 42) {
73 if (!close_enough(y, e, n)) {
74 BOOST_ERROR("failed to verify " << s << "(" << x << ") = " << e << " up to round off errors, it is " << y
75 << " instead (difference is " << (y - e) << ", n is " << n << ")");
76 }
77}
78
79// check for expected result up to truncation errors with absolute tolerance
80void check2(const std::string& s, const Real x, const Real y, const Real e, const Real tol) {
81 if (std::abs(y - e) > tol) {
82 BOOST_ERROR("failed to verify " << s << "(" << x << ") = " << e << ", it is " << y << " instead (difference is "
83 << (y - e) << ", abs tol=" << tol << ")");
84 }
85}
86
87} // anonymous namespace
88
89BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
90BOOST_AUTO_TEST_SUITE(CrossAssetModelParametrizationsTest)
91
92BOOST_AUTO_TEST_CASE(testParametrizationBaseClasses) {
93
94 BOOST_TEST_MESSAGE("Testing CrossAssetModel parametrizations (base classes)...");
95
96 // base class
97
98 Parametrization p1((EURCurrency()));
99
100 if (p1.parameterTimes(42) != Array()) {
101 BOOST_ERROR("empty parametrization should have empty times "
102 "array, it has size "
103 << p1.parameterTimes(42).size() << " though");
104 }
105
106 if (p1.parameterValues(42) != Array()) {
107 BOOST_ERROR("empty parametrization should have empty values "
108 "array, it has size "
109 << p1.parameterValues(42).size() << " though");
110 }
111
112 if (p1.parameter(42)->params().size() != 0) {
113 BOOST_ERROR("empty parametrization should have empty parameter "
114 "array, it has size "
115 << p1.parameter(42)->params().size() << " though");
116 }
117
118 // piecewise constant helpers
119
120 // the helpers expect raw values in the sense of parameter transformation
121 // which we generate here hard coded (kind of white box testing, since
122 // the helper classes are never used directly in client code)
123 Array noTimes;
124 PiecewiseConstantHelper1 helper11(noTimes);
125 helper11.p()->setParam(0, std::sqrt(3.0));
126 check("helper11.y", 0.0, helper11.y(0.0), 3.0);
127 check("helper11.y", 1.0, helper11.y(1.0), 3.0);
128 check("helper11.y", 3.0, helper11.y(3.0), 3.0);
129 check("helper11.int_y_sqr", 0.0, helper11.int_y_sqr(0.0), 0.0);
130 check("helper11.int_y_sqr", 1.0, helper11.int_y_sqr(1.0), 9.0);
131 check("helper11.int_y_sqr", 3.0, helper11.int_y_sqr(3.0), 27.0);
132
133 PiecewiseConstantHelper2 helper21(noTimes);
134 helper21.p()->setParam(0, 3.0);
135 check("helper21.y", 0.0, helper21.y(0.0), 3.0);
136 check("helper21.y", 1.0, helper21.y(1.0), 3.0);
137 check("helper21.y", 3.0, helper21.y(3.0), 3.0);
138 check("helper21.exp_m_int_y", 0.0, helper21.exp_m_int_y(0.0), 1.0);
139 check("helper21.exp_m_int_y", 1.0, helper21.exp_m_int_y(1.0), std::exp(-3.0));
140 check("helper21.exp_m_int_y", 3.0, helper21.exp_m_int_y(3.0), std::exp(-9.0));
141 check("helper21.int_exp_m_int_y", 0.0, helper21.int_exp_m_int_y(0.0), 0.0);
142 check("helper21.int_exp_m_int_y", 1.0, helper21.int_exp_m_int_y(1.0), (1.0 - std::exp(-3.0)) / 3.0);
143 check("helper21.int_exp_m_int_y", 3.0, helper21.int_exp_m_int_y(3.0), (1.0 - std::exp(-9.0)) / 3.0);
144
145 // the helper type 3 is close to type 2, so we only do the easiest
146 // tests here, in the irlgm1f Hull White adaptor tests below the
147 // other tests will be implicit though
148 PiecewiseConstantHelper3 helper31(noTimes, noTimes);
149 helper31.p1()->setParam(0, std::sqrt(3.0));
150 helper31.p2()->setParam(0, 2.0);
151 // helper 3 requires an update()
152 helper31.update();
153 check("helper31.y1", 0.0, helper31.y1(0.0), 3.0);
154 check("helper31.y1", 1.0, helper31.y1(1.0), 3.0);
155 check("helper31.y1", 3.0, helper31.y1(3.0), 3.0);
156 check("helper31.y2", 0.0, helper31.y2(0.0), 2.0);
157 check("helper31.y2", 1.0, helper31.y2(1.0), 2.0);
158 check("helper31.y2", 3.0, helper31.y2(3.0), 2.0);
159 check("helper31.int_y1_sqr_int_exp_2_int_y2", 0.0, helper31.int_y1_sqr_exp_2_int_y2(0.0), 0.0);
160 check("helper31.int_y1_sqr_int_exp_2_int_y2", 1.0, helper31.int_y1_sqr_exp_2_int_y2(1.0),
161 9.0 / 4.0 * (std::exp(2.0 * 2.0 * 1.0) - 1.0));
162 check("helper31.int_y1_sqr_int_exp_2_int_y2", 3.0, helper31.int_y1_sqr_exp_2_int_y2(3.0),
163 9.0 / 4.0 * (std::exp(2.0 * 2.0 * 3.0) - 1.0));
164
165 // test union set of times
166 Array times1(2);
167 Array times2(3);
168 times1[0] = 0.1;
169 times1[1] = 0.5;
170 times2[0] = 0.2;
171 times2[1] = 0.5;
172 times2[2] = 1.0;
173 PiecewiseConstantHelper3 helper32(times1, times2);
174 helper32.p1()->setParam(0, 0.0);
175 helper32.p1()->setParam(1, 0.0);
176 helper32.p1()->setParam(2, 0.0);
177 helper32.p2()->setParam(0, 0.0);
178 helper32.p2()->setParam(1, 0.0);
179 helper32.p2()->setParam(2, 0.0);
180 helper32.p2()->setParam(3, 0.0);
181 helper32.update();
182 Array exTu(4);
183 exTu[0] = 0.1;
184 exTu[1] = 0.2;
185 exTu[2] = 0.5;
186 exTu[3] = 1.0;
187 if (helper32.tUnion() != exTu)
188 BOOST_ERROR("helper32 expected tUnion array " << exTu << ", but is " << helper32.tUnion());
189
190 PiecewiseConstantHelper2 helper22(noTimes);
191 helper22.p()->setParam(0, 0.0);
192 check("helper22.y", 0.0, helper22.y(0.0), 0.0);
193 check("helper22.y", 1.0, helper22.y(1.0), 0.0);
194 check("helper22.y", 3.0, helper22.y(3.0), 0.0);
195 check("helper22.exp_m_int_y", 0.0, helper22.exp_m_int_y(0.0), 1.0);
196 check("helper22.exp_m_int_y", 1.0, helper22.exp_m_int_y(1.0), 1.0);
197 check("helper22.exp_m_int_y", 3.0, helper22.exp_m_int_y(3.0), 1.0);
198 check("helper22.int_exp_m_int_y", 0.0, helper22.int_exp_m_int_y(0.0), 0.0);
199 check("helper22.int_exp_m_int_y", 1.0, helper22.int_exp_m_int_y(1.0), 1.0);
200 check("helper22.int_exp_m_int_y", 3.0, helper22.int_exp_m_int_y(3.0), 3.0);
201
202 Array times(3), values(4), sqrt_values(4);
203 times[0] = 1.0;
204 times[1] = 2.0;
205 times[2] = 3.0;
206 values[0] = 1.0;
207 values[1] = 2.0;
208 values[2] = 0.0;
209 values[3] = 3.0;
210 sqrt_values[0] = std::sqrt(1.0);
211 sqrt_values[1] = std::sqrt(2.0);
212 sqrt_values[2] = std::sqrt(0.0);
213 sqrt_values[3] = std::sqrt(3.0);
214 PiecewiseConstantHelper1 helper12(times);
215 helper12.p()->setParam(0, sqrt_values[0]);
216 helper12.p()->setParam(1, sqrt_values[1]);
217 helper12.p()->setParam(2, sqrt_values[2]);
218 helper12.p()->setParam(3, sqrt_values[3]);
219 helper12.update();
220 check("helper12.y", 0.0, helper12.y(0.0), 1.0);
221 check("helper12.y", 0.5, helper12.y(0.5), 1.0);
222 check("helper12.y", 1.0, helper12.y(1.0), 2.0);
223 check("helper12.y", 2.2, helper12.y(2.2), 0.0);
224 check("helper12.y", 3.0 - 1.0E-8, helper12.y(3.0 - 1.0E-8), 0.0);
225 check("helper12.y", 3.0, helper12.y(3.0), 3.0);
226 check("helper12.y", 5.0, helper12.y(5.0), 3.0);
227 check("helper12.int_y_sqr", 0.0, helper12.int_y_sqr(0.0), 0.0);
228 check("helper12.int_y_sqr", 0.5, helper12.int_y_sqr(0.5), 0.5);
229 check("helper12.int_y_sqr", 1.0, helper12.int_y_sqr(1.0), 1.0);
230 check("helper12.int_y_sqr", 1.2, helper12.int_y_sqr(1.2), 1.0 + 4.0 * 0.2);
231 check("helper12.int_y_sqr", 2.0, helper12.int_y_sqr(2.0), 1.0 + 4.0);
232 check("helper12.int_y_sqr", 2.1, helper12.int_y_sqr(2.1), 1.0 + 4.0);
233 check("helper12.int_y_sqr", 2.5, helper12.int_y_sqr(2.5), 1.0 + 4.0);
234 check("helper12.int_y_sqr", 2.9, helper12.int_y_sqr(2.9), 1.0 + 4.0);
235 check("helper12.int_y_sqr", 3.0, helper12.int_y_sqr(3.0), 1.0 + 4.0);
236 check("helper12.int_y_sqr", 5.0, helper12.int_y_sqr(5.0), 1.0 + 4.0 + 9.0 * 2.0);
237
238 PiecewiseConstantHelper2 helper23(times);
239 helper23.p()->setParam(0, values[0]);
240 helper23.p()->setParam(1, values[1]);
241 helper23.p()->setParam(2, values[2]);
242 helper23.p()->setParam(3, values[3]);
243 helper23.update();
244 check("helper23.y", 0.0, helper23.y(0.0), 1.0);
245 check("helper23.y", 0.5, helper23.y(0.5), 1.0);
246 check("helper23.y", 1.0, helper23.y(1.0), 2.0);
247 check("helper23.y", 2.2, helper23.y(2.2), 0.0);
248 check("helper23.y", 3.0 - 1.0E-8, helper23.y(3.0 - 1.0E-8), 0.0);
249 check("helper23.y", 3.0, helper23.y(3.0), 3.0);
250 check("helper23.y", 5.0, helper23.y(5.0), 3.0);
251 check("helper23.exp_m_int_y", 0.0, helper23.exp_m_int_y(0.0), 1.0);
252 check("helper23.exp_m_int_y", 0.5, helper23.exp_m_int_y(0.5), std::exp(-0.5));
253 check("helper23.exp_m_int_y", 1.0, helper23.exp_m_int_y(1.0), std::exp(-1.0));
254 check("helper23.exp_m_int_y", 1.5, helper23.exp_m_int_y(1.5), std::exp(-2.0));
255 check("helper23.exp_m_int_y", 2.0, helper23.exp_m_int_y(2.0), std::exp(-3.0));
256 check("helper23.exp_m_int_y", 2.1, helper23.exp_m_int_y(2.1), std::exp(-3.0));
257 check("helper23.exp_m_int_y", 2.5, helper23.exp_m_int_y(2.5), std::exp(-3.0));
258 check("helper23.exp_m_int_y", 2.9, helper23.exp_m_int_y(2.9), std::exp(-3.0));
259 check("helper23.exp_m_int_y", 3.0, helper23.exp_m_int_y(3.0), std::exp(-3.0));
260 check("helper23.exp_m_int_y", 5.0, helper23.exp_m_int_y(5.0), std::exp(-3.0 - 6.0));
261
262 check("helper23.int_exp_m_int_y", 0.0, helper23.int_exp_m_int_y(0.0), 0.0);
263 Real h = 1.0E-5, x0 = 0.0, sum = 0.0;
264 while (x0 < 5.0) {
265 sum += h * helper23.exp_m_int_y(x0 + h / 2.0);
266 x0 += h;
267 check2("helper23.int_exp_m_int_y2", x0, helper23.int_exp_m_int_y(x0), sum, 1.0E-10);
268 }
269
270 // check update after value change
271
272 helper12.p()->setParam(0, std::sqrt(0.5));
273 helper12.p()->setParam(1, std::sqrt(1.0));
274 helper23.p()->setParam(0, 0.5);
275 helper23.p()->setParam(1, 1.0);
276 helper12.update();
277 helper23.update();
278 check("update helper12.y", 1.0, helper12.y(1.0), 1.0);
279 check("update helper12.int_y_sqr", 2.0, helper12.int_y_sqr(2.0), 0.5 * 0.5 + 1.0 * 1.0);
280 check("update helper23.y", 1.0, helper23.y(1.0), 1.0);
281 check("update helper23.exp_m_int_y", 2.0, helper23.exp_m_int_y(2.0), std::exp(-0.5 - 1.0));
282
283 // check dates based constructor
284
285 Handle<YieldTermStructure> yts(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0, Actual365Fixed()));
286 std::vector<Date> dates;
287 dates.push_back(yts->referenceDate() + 100);
288 dates.push_back(yts->referenceDate() + 200);
289 dates.push_back(yts->referenceDate() + 250);
290 dates.push_back(yts->referenceDate() + 2385);
291 PiecewiseConstantHelper1 helper1x(dates, yts);
292
293 check("time from date helper1x", 0.0, helper1x.t()[0], yts->timeFromReference(dates[0]));
294 check("time from date helper1x", 0.0, helper1x.t()[1], yts->timeFromReference(dates[1]));
295 check("time from date helper1x", 0.0, helper1x.t()[2], yts->timeFromReference(dates[2]));
296 check("time from date helper1x", 0.0, helper1x.t()[3], yts->timeFromReference(dates[3]));
297}
298
299BOOST_AUTO_TEST_CASE(testIrLgm1fParametrizations) {
300
301 BOOST_TEST_MESSAGE("Testing CrossAssetModel parametrizations (irlgm1f)...");
302
303 // test generic inspectors of irlgm1f parametrization
304
305 class IrLgm1fTmpParametrization : public IrLgm1fParametrization {
306 public:
307 IrLgm1fTmpParametrization(const Currency& currency, const Handle<YieldTermStructure>& termStructure)
308 : IrLgm1fParametrization(currency, termStructure) {}
309 Handle<YieldTermStructure> termStructure() const { return Handle<YieldTermStructure>(); }
310 // do not use this parametrization at home
311 Real zeta(const Time t) const override { return sin(t); }
312 Real H(const Time t) const override { return t * t * t; }
313 } irlgm1f_1((EURCurrency()), Handle<YieldTermStructure>());
314
315 // check numerical differentiation scheme (in particular near zero)
316 // of the irlgm1f parametrization
317
318 Real h = 1.0E-6, h2 = 1.0E-4;
319
320 check("irlgm1f_1.alpha", 0.0, irlgm1f_1.alpha(0.0), std::sqrt((irlgm1f_1.zeta(h) - irlgm1f_1.zeta(0.0)) / h));
321 check("irlgm1f_1.alpha", 0.3E-8, irlgm1f_1.alpha(0.3E-8), std::sqrt((irlgm1f_1.zeta(h) - irlgm1f_1.zeta(0.0)) / h));
322 check("irlgm1f_1.alpha", 1.0, irlgm1f_1.alpha(1.0),
323 std::sqrt((irlgm1f_1.zeta(1.0 + h / 2.0) - irlgm1f_1.zeta(1.0 - h / 2.0)) / h));
324
325 check("irlgm1f_1.Hprime", 0.0, irlgm1f_1.Hprime(0.0), (irlgm1f_1.H(h) - irlgm1f_1.H(0.0)) / h);
326 check("irlgm1f_1.Hprime", 0.3E-8, irlgm1f_1.Hprime(0.3E-8), (irlgm1f_1.H(h) - irlgm1f_1.H(0.0)) / h);
327 check("irlgm1f_1.Hprime", 1.0, irlgm1f_1.Hprime(1.0),
328 (irlgm1f_1.H(1.0 + h / 2.0) - irlgm1f_1.H(1.0 - h / 2.0)) / h);
329
330 check("irlgm1f_1.Hprime2", 0.0, irlgm1f_1.Hprime2(0.0),
331 (irlgm1f_1.H(2.0 * h2) - 2.0 * irlgm1f_1.H(h2) + irlgm1f_1.H(0.0)) / (h2 * h2));
332 check("irlgm1f_1.Hprime2", 0.3E-4, irlgm1f_1.Hprime2(0.3E-4),
333 (irlgm1f_1.H(2.0 * h2) - 2.0 * irlgm1f_1.H(h2) + irlgm1f_1.H(0.0)) / (h2 * h2));
334 check("irlgm1f_1.Hprime2", 1.0, irlgm1f_1.Hprime2(1.0),
335 (irlgm1f_1.H(1.0 + h2) - 2.0 * irlgm1f_1.H(1.0) + irlgm1f_1.H(1.0 - h2)) / (h2 * h2));
336
337 check("irlgm1f_1.hullWhiteSigma", 1.5, irlgm1f_1.hullWhiteSigma(1.5), irlgm1f_1.Hprime(1.5) * irlgm1f_1.alpha(1.5));
338 check("irlgm1f_1.kappa", 1.5, irlgm1f_1.kappa(1.5), -irlgm1f_1.Hprime2(1.5) / irlgm1f_1.Hprime(1.5));
339
340 // check the irlgm1f parametrizations
341
342 Handle<YieldTermStructure> flatYts(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.02, Actual365Fixed()));
343
344 IrLgm1fConstantParametrization irlgm1f_2(EURCurrency(), flatYts, 0.01, 0.01);
345 IrLgm1fConstantParametrization irlgm1f_3(EURCurrency(), flatYts, 0.01, 0.00);
346
347 Array alphaTimes(99), kappaTimes(99), alpha(100), kappa(100), sigma(100);
348 for (Size i = 0; i < 100; ++i) {
349 if (i < 99) {
350 alphaTimes[i] = static_cast<Real>(i + 1);
351 kappaTimes[i] = alphaTimes[i];
352 }
353 // 0.0000 to 0.099
354 alpha[i] = sigma[i] = static_cast<Real>(i) * 0.0010;
355 // -0.05 to 0.049
356 kappa[i] = (static_cast<Real>(i) - 50.0) * 0.001;
357 }
358
359 IrLgm1fPiecewiseConstantParametrization irlgm1f_4(EURCurrency(), flatYts, alphaTimes, alpha, kappaTimes, kappa);
360
361 // alpha and kappa times are identical
362 IrLgm1fPiecewiseConstantHullWhiteAdaptor irlgm1f_5(EURCurrency(), flatYts, alphaTimes, sigma, alphaTimes, kappa);
363
364 Real t = 0.0, step = 1.0E-3;
365 while (t < 100.0) {
366
367 // check irlgm1f parametrization (piecewise constant and constant)
368 // for consistency with sqrt(zeta') = alpha and -H'' / H' = kappa
369
370 // as well, check the Hull White adaptor by checking
371 // sqrt(zeta') H' = sigma, -H'' / H' = kappa
372
373 Real zetaPrime2, zetaPrime3, zetaPrime4, zetaPrime5;
374 Real Hprime2, Hprime3, Hprime4, Hprime5;
375 Real Hprimeprime2, Hprimeprime3, Hprimeprime4, Hprimeprime5;
376 if (t < h / 2.0) {
377 zetaPrime2 = (irlgm1f_2.zeta(t + h) - irlgm1f_2.zeta(t)) / h;
378 zetaPrime3 = (irlgm1f_3.zeta(t + h) - irlgm1f_3.zeta(t)) / h;
379 zetaPrime4 = (irlgm1f_4.zeta(t + h) - irlgm1f_4.zeta(t)) / h;
380 zetaPrime5 = (irlgm1f_5.zeta(t + h) - irlgm1f_5.zeta(t)) / h;
381 Hprime2 = (irlgm1f_2.H(t + h) - irlgm1f_2.H(t)) / h;
382 Hprime3 = (irlgm1f_3.H(t + h) - irlgm1f_3.H(t)) / h;
383 Hprime4 = (irlgm1f_4.H(t + h) - irlgm1f_4.H(t)) / h;
384 Hprime5 = (irlgm1f_5.H(t + h) - irlgm1f_5.H(t)) / h;
385 } else {
386 zetaPrime2 = (irlgm1f_2.zeta(t + h / 2.0) - irlgm1f_2.zeta(t - h / 2.0)) / h;
387 zetaPrime3 = (irlgm1f_3.zeta(t + h / 2.0) - irlgm1f_3.zeta(t - h / 2.0)) / h;
388 zetaPrime4 = (irlgm1f_4.zeta(t + h / 2.0) - irlgm1f_4.zeta(t - h / 2.0)) / h;
389 zetaPrime5 = (irlgm1f_5.zeta(t + h / 2.0) - irlgm1f_5.zeta(t - h / 2.0)) / h;
390 Hprime2 = (irlgm1f_2.H(t + h / 2.0) - irlgm1f_2.H(t - h / 2.0)) / h;
391 Hprime3 = (irlgm1f_3.H(t + h / 2.0) - irlgm1f_3.H(t - h / 2.0)) / h;
392 Hprime4 = (irlgm1f_4.H(t + h / 2.0) - irlgm1f_4.H(t - h / 2.0)) / h;
393 Hprime5 = (irlgm1f_5.H(t + h / 2.0) - irlgm1f_5.H(t - h / 2.0)) / h;
394 }
395 if (t < h2) {
396 Hprimeprime2 = (irlgm1f_2.H(2.0 * h2) - 2.0 * irlgm1f_2.H(h2) + irlgm1f_2.H(0.0)) / (h2 * h2);
397 Hprimeprime3 = (irlgm1f_3.H(2.0 * h2) - 2.0 * irlgm1f_3.H(h2) + irlgm1f_3.H(0.0)) / (h2 * h2);
398 Hprimeprime4 = (irlgm1f_4.H(2.0 * h2) - 2.0 * irlgm1f_4.H(h2) + irlgm1f_4.H(0.0)) / (h2 * h2);
399 Hprimeprime5 = (irlgm1f_5.H(2.0 * h2) - 2.0 * irlgm1f_5.H(h2) + irlgm1f_5.H(0.0)) / (h2 * h2);
400 } else {
401 Hprimeprime2 = (irlgm1f_2.H(t + h2) - 2.0 * irlgm1f_2.H(t) + irlgm1f_2.H(t - h2)) / (h2 * h2);
402 Hprimeprime3 = (irlgm1f_3.H(t + h2) - 2.0 * irlgm1f_3.H(t) + irlgm1f_3.H(t - h2)) / (h2 * h2);
403 Hprimeprime4 = (irlgm1f_4.H(t + h2) - 2.0 * irlgm1f_4.H(t) + irlgm1f_4.H(t - h2)) / (h2 * h2);
404 Hprimeprime5 = (irlgm1f_5.H(t + h2) - 2.0 * irlgm1f_5.H(t) + irlgm1f_5.H(t - h2)) / (h2 * h2);
405 }
406 check2("sqrt(d/dt irlgm1f_2.zeta)", t, sqrt(zetaPrime2), 0.01, 1.0E-7);
407 check2("sqrt(d/dt irlgm1f_3.zeta)", t, sqrt(zetaPrime3), 0.01, 1.0E-7);
408 if (std::fabs(t - static_cast<int>(t + 0.5)) > h) {
409 // we can not expect this test to work when the numerical
410 // differentiation is going over a grid point where
411 // alpha (or sigma) jumps
412 check2("sqrt(d/dt irlgm1f_4.zeta)", t, sqrt(zetaPrime4), QL_PIECEWISE_FUNCTION(alphaTimes, alpha, t),
413 1.0E-7);
414 check2("sqrt(d/dt irlgm1f_5.zeta)*H'", t, sqrt(zetaPrime5) * Hprime5,
415 QL_PIECEWISE_FUNCTION(alphaTimes, sigma, t), 1.0E-6);
416 }
417 check2("irlgm1f_2.(-H''/H')", t, -Hprimeprime2 / Hprime2, 0.01, 2.0E-5);
418 check2("irlgm1f_3.(-H''/H')", t, -Hprimeprime3 / Hprime3, 0.00, 2.0E-5);
419 if (std::fabs(t - static_cast<int>(t + 0.5)) > h2) {
420 // same as above, we avoid to test the grid points
421 check2("irlgm1f_4.(-H''/H')", t, -Hprimeprime4 / Hprime4, QL_PIECEWISE_FUNCTION(kappaTimes, kappa, t),
422 5.0E-5);
423 check2("irlgm1f_5.(-H''/H')", t, -Hprimeprime5 / Hprime5, QL_PIECEWISE_FUNCTION(alphaTimes, kappa, t),
424 5.0E-5);
425 }
426
427 // check the remaining inspectors
428
429 check("irlgm1f_2.alpha", t, irlgm1f_2.alpha(t), 0.01);
430 check("irlgm1f_3.alpha", t, irlgm1f_3.alpha(t), 0.01);
431 check("irlgm1f_4.alpha", t, irlgm1f_4.alpha(t), QL_PIECEWISE_FUNCTION(alphaTimes, alpha, t));
432 check("irlgm1f_5.hullWhiteSigma", t, irlgm1f_5.hullWhiteSigma(t), QL_PIECEWISE_FUNCTION(alphaTimes, sigma, t));
433
434 check("irlgm1f_2.kappa", t, irlgm1f_2.kappa(t), 0.01);
435 check("irlgm1f_3.kappa", t, irlgm1f_3.kappa(t), 0.00);
436 check("irlgm1f_4.kappa", t, irlgm1f_4.kappa(t), QL_PIECEWISE_FUNCTION(kappaTimes, kappa, t));
437 check("irlgm1f_5.kappa", t, irlgm1f_5.kappa(t), QL_PIECEWISE_FUNCTION(alphaTimes, kappa, t));
438
439 check2("irlgm1f_2.Hprime", t, irlgm1f_2.Hprime(t), Hprime2, 1.0E-6);
440 check2("irlgm1f_3.Hprime", t, irlgm1f_3.Hprime(t), Hprime3, 1.0E-6);
441 if (std::fabs(t - static_cast<int>(t + 0.5)) > h) {
442 // same as above, we avoid to test the grid points
443 check2("irlgm1f_4.Hprime", t, irlgm1f_4.Hprime(t), Hprime4, 1.0E-6);
444 check2("irlgm1f_5.Hprime", t, irlgm1f_5.Hprime(t), Hprime5, 1.0E-6);
445 check2("irlgm1f_5.alpha", t, irlgm1f_5.alpha(t),
446 QL_PIECEWISE_FUNCTION(alphaTimes, sigma, t) / irlgm1f_5.Hprime(t), 1.0E-6);
447 }
448
449 check2("irlgm1f_2.Hprime2", t, irlgm1f_2.Hprime2(t), Hprimeprime2, 2.0E-5);
450 check2("irlgm1f_3.Hprime2", t, irlgm1f_3.Hprime2(t), Hprimeprime3, 2.0E-5);
451 if (std::fabs(t - static_cast<int>(t + 0.5)) > h) {
452 // same as above, we avoid to test the grid points
453 check2("irlgm1f_4.Hprime2", t, irlgm1f_4.Hprime2(t), Hprimeprime4, 2.0E-3);
454 check2("irlgm1f_5.Hprime2", t, irlgm1f_5.Hprime2(t), Hprimeprime5, 2.0E-3);
455 }
456
457 check2("irlgm1f_2.hullWhiteSigma", t, irlgm1f_2.hullWhiteSigma(t), 0.01 * Hprime2, 1.0E-7);
458 check2("irlgm1f_3.hullWhiteSigma", t, irlgm1f_3.hullWhiteSigma(t), 0.01 * Hprime3, 1.0E-7);
459 check2("irlgm1f_4.hullWhiteSigma", t, irlgm1f_4.hullWhiteSigma(t),
460 QL_PIECEWISE_FUNCTION(alphaTimes, alpha, t) * Hprime4, 1.0E-7);
461 // irlgm1f_5.alpha check is above if you should have wondered ...
462
463 t += step;
464 }
465}
466
467BOOST_AUTO_TEST_CASE(testFxBsParametrizations) {
468
469 BOOST_TEST_MESSAGE("Testing CrossAssetModel parametrizations (fxbs)...");
470
471 FxBsConstantParametrization fxbs_0(USDCurrency(), Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.10)), 0.10);
472
473 check("fxbs_0.variance", 0.0, fxbs_0.variance(0.0), 0.0);
474 check("fxbs_0.variance", 1.0, fxbs_0.variance(1.0), 0.01 * 1.0);
475 check("fxbs_0.variance", 2.0, fxbs_0.variance(2.0), 0.01 * 2.0);
476 check("fxbs_0.variance", 3.0, fxbs_0.variance(3.0), 0.01 * 3.0);
477 check("fxbs_0.stdDeviation", 0.0, fxbs_0.stdDeviation(0.0), 0.0);
478 check("fxbs_0.stdDeviation", 1.0, fxbs_0.stdDeviation(1.0), std::sqrt(0.01 * 1.0));
479 check("fxbs_0.stdDeviation", 2.0, fxbs_0.stdDeviation(2.0), std::sqrt(0.01 * 2.0));
480 check("fxbs_0.stdDeviation", 3.0, fxbs_0.stdDeviation(3.0), std::sqrt(0.01 * 3.0));
481 check("fxbs_0.sigma", 0.0, fxbs_0.sigma(0.0), 0.10);
482 check("fxbs_0.sigma", 1.0, fxbs_0.sigma(1.0), 0.10);
483 check("fxbs_0.sigma", 2.0, fxbs_0.sigma(2.0), 0.10);
484 check("fxbs_0.sigma", 3.0, fxbs_0.sigma(3.0), 0.10);
485
486 Array times(3), sigma(4);
487 times[0] = 1.0;
488 times[1] = 2.0;
489 times[2] = 3.0;
490 sigma[0] = 0.10;
491 sigma[1] = 0.20;
492 sigma[2] = 0.0;
493 sigma[3] = 0.15;
494
495 FxBsPiecewiseConstantParametrization fxbs_1(USDCurrency(), Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.10)),
496 times, sigma);
497
498 check("fxbs_1.variance", 0.0, fxbs_1.variance(0.0), 0.0);
499 check("fxbs_1.variance", 0.5, fxbs_1.variance(0.5), 0.10 * 0.10 * 0.5);
500 check("fxbs_1.variance", 1.0, fxbs_1.variance(1.0), 0.10 * 0.10);
501 check("fxbs_1.variance", 1.5, fxbs_1.variance(1.5), 0.10 * 0.10 + 0.20 * 0.20 * 0.5);
502 check("fxbs_1.variance", 2.0, fxbs_1.variance(2.0), 0.10 * 0.10 + 0.20 * 0.20);
503 check("fxbs_1.variance", 2.2, fxbs_1.variance(2.2), 0.10 * 0.10 + 0.20 * 0.20);
504 check("fxbs_1.variance", 3.0, fxbs_1.variance(3.0), 0.10 * 0.10 + 0.20 * 0.20);
505 check("fxbs_1.variance", 5.0, fxbs_1.variance(5.0), 0.10 * 0.10 + 0.20 * 0.20 + 2 * 0.15 * 0.15);
506
507 check("fxbs_1.stdDeviation", 0.0, fxbs_1.stdDeviation(0.0), std::sqrt(0.0));
508 check("fxbs_1.stdDeviation", 0.5, fxbs_1.stdDeviation(0.5), std::sqrt(0.10 * 0.10 * 0.5));
509 check("fxbs_1.stdDeviation", 1.0, fxbs_1.stdDeviation(1.0), std::sqrt(0.10 * 0.10));
510 check("fxbs_1.stdDeviation", 1.5, fxbs_1.stdDeviation(1.5), std::sqrt(0.10 * 0.10 + 0.20 * 0.20 * 0.5));
511 check("fxbs_1.stdDeviation", 2.0, fxbs_1.stdDeviation(2.0), std::sqrt(0.10 * 0.10 + 0.20 * 0.20));
512 check("fxbs_1.stdDeviation", 2.2, fxbs_1.stdDeviation(2.2), std::sqrt(0.10 * 0.10 + 0.20 * 0.20));
513 check("fxbs_1.stdDeviation", 3.0, fxbs_1.stdDeviation(3.0), std::sqrt(0.10 * 0.10 + 0.20 * 0.20));
514 check("fxbs_1.stdDeviation", 5.0, fxbs_1.stdDeviation(5.0), std::sqrt(0.10 * 0.10 + 0.20 * 0.20 + 2 * 0.15 * 0.15));
515
516 check("fxb2_1.sigma", 0.0, fxbs_1.sigma(0.0), 0.10);
517 check("fxb2_1.sigma", 0.5, fxbs_1.sigma(0.5), 0.10);
518 check("fxb2_1.sigma", 1.0, fxbs_1.sigma(1.0), 0.20);
519 check("fxb2_1.sigma", 2.0, fxbs_1.sigma(2.0), 0.00);
520 check("fxb2_1.sigma", 3.0, fxbs_1.sigma(3.0), 0.15);
521 check("fxb2_1.sigma", 5.0, fxbs_1.sigma(5.0), 0.15);
522}
523
524BOOST_AUTO_TEST_SUITE_END()
525
526BOOST_AUTO_TEST_SUITE_END()
cds option calibration helper
Real variance(const Time t) const override
virtual Real stdDeviation(const Time t) const
virtual Real H(const Time t) const =0
const Handle< TS > termStructure() const
virtual Real hullWhiteSigma(const Time t) const
virtual Real zeta(const Time t) const =0
virtual const Array & parameterTimes(const Size) const
virtual const QuantLib::ext::shared_ptr< Parameter > parameter(const Size) const
virtual Array parameterValues(const Size) const
const QuantLib::ext::shared_ptr< Parameter > p() const
Real int_y_sqr(const Time t) const
int_0^t y^2(s) ds
Real exp_m_int_y(const Time t) const
exp(int_0^t -y(s)) ds
Real int_exp_m_int_y(const Time t) const
int_0^t exp(int_0^s -y(u) du) ds
const QuantLib::ext::shared_ptr< Parameter > p() const
Real int_y1_sqr_exp_2_int_y2(const Time t) const
int_0^t y1^2(s) exp(2*int_0^s y2(u) du) ds
const QuantLib::ext::shared_ptr< Parameter > p2() const
const QuantLib::ext::shared_ptr< Parameter > p1() const
CPI Cap Floor calibration helper.
Credit Linear Gaussian Markov 1 factor parametrization.
analytics for the cross asset model
basic functions for analytics in the cross asset model
cross asset model
dynamic black volatility term structure
dynamic black volatility term structure
BOOST_AUTO_TEST_CASE(testParametrizationBaseClasses)
year on year inflation term structure implied by a Dodgson Kainth (DK) model
zero inflation term structure implied by a Dodgson Kainth (DK) model
Constant equity model parametrization.
EQ Black Scholes parametrization.
piecewise constant model parametrization
Constant FX model parametrization.
FX Black Scholes parametrization.
piecewise constant model parametrization
calibration helper for Black-Scholes options
adaptor class that extracts one irlgm1f component
Inflation Dodgson Kainth parametrization.
constant model parametrization
Interest Rate Linear Gaussian Markov 1 factor parametrization.
adaptor to emulate piecewise constant Hull White parameters
piecewise constant model parametrization
piecewise linear model parametrization
lgm model class
default probability structure implied by a LGM model
yield term structure implied by a LGM model
calibrated model class with linkable parameters
RandomVariable sqrt(RandomVariable x)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
RandomVariable sin(RandomVariable x)
Lgm1fParametrization< YieldTermStructure > IrLgm1fParametrization
Real sum(const Cash &c, const Cash &d)
Definition: bondbasket.cpp:107
base class for model parametrizations
helper classes for piecewise constant parametrizations
parameter giving access to calibration machinery
Fixture that can be used at top level.
helper macros and methods for tests