Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
analyticlgmswaptionengine.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>
47#include <qle/models/lgm.hpp>
71
72#include <ql/currencies/europe.hpp>
73#include <ql/indexes/swap/euriborswap.hpp>
74#include <ql/instruments/makeswaption.hpp>
75#include <ql/math/array.hpp>
76#include <ql/math/comparison.hpp>
77#include <ql/models/shortrate/onefactormodels/gsr.hpp>
78#include <ql/pricingengines/swap/discountingswapengine.hpp>
79#include <ql/pricingengines/swaption/fdhullwhiteswaptionengine.hpp>
80#include <ql/pricingengines/swaption/gaussian1dswaptionengine.hpp>
81#include <ql/pricingengines/credit/midpointcdsengine.hpp>
82#include <ql/quotes/simplequote.hpp>
83#include <ql/termstructures/yield/flatforward.hpp>
84#include <ql/time/calendars/nullcalendar.hpp>
85#include <ql/time/calendars/target.hpp>
86
87#include <boost/make_shared.hpp>
88
89using namespace QuantLib;
90using namespace QuantExt;
91
92namespace {
93struct F : public qle::test::TopLevelFixture {
94 F() { Settings::instance().evaluationDate() = Date(20, March, 2019); }
95 ~F() {}
96};
97} // namespace
98
99BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
100
101BOOST_FIXTURE_TEST_SUITE(AnalyticLgmSwaptionEngineTest, F)
102
103BOOST_AUTO_TEST_CASE(testMonoCurve) {
104
105 BOOST_TEST_MESSAGE("Testing analytic LGM swaption engine coupon "
106 "adjustments in mono curve setup...");
107
108 Handle<YieldTermStructure> flatCurve(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.02, Actual365Fixed()));
109
110 const QuantLib::ext::shared_ptr<IrLgm1fConstantParametrization> irlgm1f =
111 QuantLib::ext::make_shared<IrLgm1fConstantParametrization>(EURCurrency(), flatCurve, 0.01, 0.01);
112
113 // no curve attached
114 QuantLib::ext::shared_ptr<SwapIndex> index_nocurves = QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(10 * Years);
115
116 // forward curve attached
117 QuantLib::ext::shared_ptr<SwapIndex> index_monocurve = QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(10 * Years, flatCurve);
118
119 Swaption swaption_nocurves = MakeSwaption(index_nocurves, 10 * Years, 0.02);
120 Swaption swaption_monocurve = MakeSwaption(index_monocurve, 10 * Years, 0.02);
121
122 QuantLib::ext::shared_ptr<PricingEngine> engine_nodisc = QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1f);
123 QuantLib::ext::shared_ptr<PricingEngine> engine_monocurve =
124 QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1f, flatCurve);
125
126 swaption_nocurves.setPricingEngine(engine_nodisc);
127 swaption_nocurves.NPV();
128 std::vector<Real> fixedAmountCorrections1 = swaption_nocurves.result<std::vector<Real> >("fixedAmountCorrections");
129 Real fixedAmountCorrectionSettlement1 = swaption_nocurves.result<Real>("fixedAmountCorrectionSettlement");
130 swaption_nocurves.setPricingEngine(engine_monocurve);
131 swaption_nocurves.NPV();
132 std::vector<Real> fixedAmountCorrections2 = swaption_nocurves.result<std::vector<Real> >("fixedAmountCorrections");
133 Real fixedAmountCorrectionSettlement2 = swaption_nocurves.result<Real>("fixedAmountCorrectionSettlement");
134 swaption_monocurve.setPricingEngine(engine_nodisc);
135 swaption_monocurve.NPV();
136 std::vector<Real> fixedAmountCorrections3 = swaption_nocurves.result<std::vector<Real> >("fixedAmountCorrections");
137 Real fixedAmountCorrectionSettlement3 = swaption_nocurves.result<Real>("fixedAmountCorrectionSettlement");
138 swaption_monocurve.setPricingEngine(engine_monocurve);
139 swaption_monocurve.NPV();
140 std::vector<Real> fixedAmountCorrections4 = swaption_nocurves.result<std::vector<Real> >("fixedAmountCorrections");
141 Real fixedAmountCorrectionSettlement4 = swaption_nocurves.result<Real>("fixedAmountCorrectionSettlement");
142
143 if (fixedAmountCorrections1.size() != 10) {
144 BOOST_ERROR("fixed coupon adjustment vector 1 should have size 10, "
145 "but actually has size "
146 << fixedAmountCorrections1.size());
147 }
148 if (fixedAmountCorrections2.size() != 10) {
149 BOOST_ERROR("fixed coupon adjustment vector 2 should have size 10, "
150 "but actually has size "
151 << fixedAmountCorrections2.size());
152 }
153 if (fixedAmountCorrections3.size() != 10) {
154 BOOST_ERROR("fixed coupon adjustment vector 3 should have size 10, "
155 "but actually has size "
156 << fixedAmountCorrections3.size());
157 }
158 if (fixedAmountCorrections4.size() != 10) {
159 BOOST_ERROR("fixed coupon adjustment vector 4 should have size 10, "
160 "but actually has size "
161 << fixedAmountCorrections4.size());
162 }
163
164 for (Size i = 0; i < 10; ++i) {
165 if (!close_enough(fixedAmountCorrections1[i], 0.0)) {
166 BOOST_ERROR("fixed coupon adjustment (1) should be zero in mono "
167 "curve setup, but component "
168 << i << " is " << fixedAmountCorrections1[i]);
169 }
170 if (!close_enough(fixedAmountCorrections2[i], 0.0)) {
171 BOOST_ERROR("fixed coupon adjustment (2) should be zero in mono "
172 "curve setup, but component "
173 << i << " is " << fixedAmountCorrections2[i]);
174 }
175 if (!close_enough(fixedAmountCorrections3[i], 0.0)) {
176 BOOST_ERROR("fixed coupon adjustment (3) should be zero in mono "
177 "curve setup, but component "
178 << i << " is " << fixedAmountCorrections3[i]);
179 }
180 if (!close_enough(fixedAmountCorrections4[i], 0.0)) {
181 BOOST_ERROR("fixed coupon adjustment (4) should be zero in mono "
182 "curve setup, but component "
183 << i << " is " << fixedAmountCorrections4[i]);
184 }
185 }
186
187 if (!close_enough(fixedAmountCorrectionSettlement1, 0.0)) {
188 BOOST_ERROR("fixed amount correction on settlement (1) should be "
189 "zero in mono curve setup, but is "
190 << fixedAmountCorrectionSettlement1);
191 }
192 if (!close_enough(fixedAmountCorrectionSettlement2, 0.0)) {
193 BOOST_ERROR("fixed amount correction on settlement (2) should be "
194 "zero in mono curve setup, but is "
195 << fixedAmountCorrectionSettlement2);
196 }
197 if (!close_enough(fixedAmountCorrectionSettlement3, 0.0)) {
198 BOOST_ERROR("fixed amount correction on settlement (3) should be "
199 "zero in mono curve setup, but is "
200 << fixedAmountCorrectionSettlement3);
201 }
202 if (!close_enough(fixedAmountCorrectionSettlement4, 0.0)) {
203 BOOST_ERROR("fixed amount correction on settlement (4) should be "
204 "zero in mono curve setup, but is "
205 << fixedAmountCorrectionSettlement4);
206 }
207}
208
209BOOST_AUTO_TEST_CASE(testDualCurve) {
210
211 BOOST_TEST_MESSAGE("Testing analytic LGM swaption engine coupon "
212 "adjustments in dual curve setup...");
213
214 // discounting curve
215 Handle<YieldTermStructure> discCurve(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.02, Actual365Fixed()));
216 // forward (+10bp)
217 Handle<YieldTermStructure> forwardCurve1(
218 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0210, Actual365Fixed()));
219 // forward (-10bp)
220 Handle<YieldTermStructure> forwardCurve2(
221 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.0190, Actual365Fixed()));
222
223 const QuantLib::ext::shared_ptr<IrLgm1fConstantParametrization> irlgm1f =
224 QuantLib::ext::make_shared<IrLgm1fConstantParametrization>(EURCurrency(), discCurve, 0.01, 0.01);
225
226 // forward curve attached
227 QuantLib::ext::shared_ptr<SwapIndex> index1 = QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(10 * Years, forwardCurve1);
228 QuantLib::ext::shared_ptr<SwapIndex> index2 = QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(10 * Years, forwardCurve2);
229
230 Swaption swaption1 = MakeSwaption(index1, 10 * Years, 0.02);
231 Swaption swaption2 = MakeSwaption(index2, 10 * Years, 0.02);
232
233 QuantLib::ext::shared_ptr<PricingEngine> engine_a =
234 QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1f, discCurve, AnalyticLgmSwaptionEngine::nextCoupon);
235
236 QuantLib::ext::shared_ptr<PricingEngine> engine_b =
237 QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1f, discCurve, AnalyticLgmSwaptionEngine::proRata);
238
239 swaption1.setPricingEngine(engine_a);
240 swaption1.NPV();
241 std::vector<Real> fixedAmountCorrections1a = swaption1.result<std::vector<Real> >("fixedAmountCorrections");
242 Real fixedAmountCorrectionSettlement1a = swaption1.result<Real>("fixedAmountCorrectionSettlement");
243 swaption2.setPricingEngine(engine_a);
244 swaption2.NPV();
245 std::vector<Real> fixedAmountCorrections2a = swaption2.result<std::vector<Real> >("fixedAmountCorrections");
246 Real fixedAmountCorrectionSettlement2a = swaption2.result<Real>("fixedAmountCorrectionSettlement");
247 swaption1.setPricingEngine(engine_b);
248 swaption1.NPV();
249 std::vector<Real> fixedAmountCorrections1b = swaption1.result<std::vector<Real> >("fixedAmountCorrections");
250 Real fixedAmountCorrectionSettlement1b = swaption1.result<Real>("fixedAmountCorrectionSettlement");
251 swaption2.setPricingEngine(engine_b);
252 swaption2.NPV();
253 std::vector<Real> fixedAmountCorrections2b = swaption2.result<std::vector<Real> >("fixedAmountCorrections");
254 Real fixedAmountCorrectionSettlement2b = swaption2.result<Real>("fixedAmountCorrectionSettlement");
255
256 // check corrections on settlement for plausibility
257
258 Real tolerance = 0.000025; // 0.25 bp
259
260 if (!close_enough(fixedAmountCorrectionSettlement1a, 0.0)) {
261 BOOST_ERROR("fixed amount correction on settlement (1) should be "
262 "0 for nextCoupon, but is "
263 << fixedAmountCorrectionSettlement1a);
264 }
265 if (!close_enough(fixedAmountCorrectionSettlement2a, 0.0)) {
266 BOOST_ERROR("fixed amount correction on settlement (2) should be "
267 "0 for nextCoupon, but is "
268 << fixedAmountCorrectionSettlement2a);
269 }
270 if (std::abs(fixedAmountCorrectionSettlement1b - 0.00025) > tolerance) {
271 BOOST_ERROR("fixed amount correction on settlement (1) should be "
272 "close to 2.5bp for proRata, but is "
273 << fixedAmountCorrectionSettlement1b);
274 }
275 if (std::abs(fixedAmountCorrectionSettlement2b + 0.00025) > tolerance) {
276 BOOST_ERROR("fixed amount correction on settlement (2) should be "
277 "close to -2.5bp for proRata, but is "
278 << fixedAmountCorrectionSettlement2b);
279 }
280
281 // we can assume that the result vectors have the correct size, this
282 // was tested above
283
284 for (Size i = 0; i < 10; ++i) {
285 // amount correction should be close to +10bp (-10bp)
286 // up to conventions, check this for plausibility
287 if (std::abs(fixedAmountCorrections1a[i] - 0.0010) > tolerance) {
288 BOOST_ERROR("fixed coupon adjustment (1, nextCoupon) should "
289 "be close to 10bp for "
290 "a 10bp curve spread, but is "
291 << fixedAmountCorrections1a[i] << " for component " << i);
292 }
293 if (std::abs(fixedAmountCorrections2a[i] + 0.0010) > tolerance) {
294 BOOST_ERROR("fixed coupon adjustment (2, nextCoupon) should "
295 "be close to -10bp for "
296 "a -10bp curve spread, but is "
297 << fixedAmountCorrections2a[i] << " for component " << i);
298 }
299 if (std::abs(fixedAmountCorrections1b[i] - (i == 9 ? 0.00075 : 0.0010)) > tolerance) {
300 BOOST_ERROR("fixed coupon adjustment (1, proRata) should "
301 "be close to 10bp (7.5bp for component 9) for "
302 "a 10bp curve spread, but is "
303 << fixedAmountCorrections1b[i] << " for component " << i);
304 }
305 if (std::abs(fixedAmountCorrections2b[i] + (i == 9 ? 0.00075 : 0.0010)) > tolerance) {
306 BOOST_ERROR("fixed coupon adjustment (2, proRata) should "
307 "be close to -10bp (-7.5bp for component 9) for "
308 "a -10bp curve spread, but is "
309 << fixedAmountCorrections2b[i] << " for component " << i);
310 }
311 }
312}
313
314BOOST_AUTO_TEST_CASE(testAgainstOtherEngines) {
315
316 BOOST_TEST_MESSAGE("Testing analytic LGM swaption engine against "
317 "G1d adaptor / Gsr integral and Hull White fd engines...");
318
319 Real discountingRateLevel[] = { -0.0050, 0.01, 0.03, 0.10 };
320 Real forwardingRateLevel[] = { -0.0100, 0.01, 0.04, 0.12 };
321
322 // Hull White only allows for positive reversion levels
323 Real kappa[] = { 0.01, 0.00001, 0.01, 0.05 };
324
325 // the model volatilities are meant to be Hull White volatilities
326 // they are fed into the LGM model via the HW adaptor below
327 // the rationale is to have another independent model
328 // (QuantLib::HullWhite) and pricing engine
329 // (QUantLib::FdHullWhiteSwaptionEngine) available for validation
330
331 Real sigma[] = { 0.0001, 0.01, 0.02 };
332
333 Real strikeOffset[] = { -0.05, -0.02, -0.01, 0.0, 0.01, 0.02, 0.05 };
334
335 Size no = 0;
336
337 // tolerance for comparison FD engine vs integral engines
338 Real tol1 = 3.0E-4;
339
340 // tolerance for comparison of integral engines based
341 // on GSR and LGM model
342 Real tol2 = 1.0E-4;
343
344 // tolerance for LGM integral engine and analytical engine
345 // in the case of no basis between discounting and forwarding
346 Real tol3 = 0.6E-4;
347
348 // tolerance for LGM integral engine and analytical engine
349 // in the case of a non zero basis between discounting and
350 // forwarding curve (mapping type a and b)
351 // this scales with sigma, the tolerances here are
352 // for sigma = 0.01
353 Real tol4a = 6.0E-4, tol4b = 4.0E-4;
354
355 for (Size i = 0; i < LENGTH(discountingRateLevel); ++i) {
356 for (Size k = 0; k < LENGTH(kappa); ++k) {
357 for (Size l = 0; l < LENGTH(sigma); ++l) {
358
359 Handle<YieldTermStructure> discountingCurve(
360 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), discountingRateLevel[i], Actual365Fixed()));
361 Handle<YieldTermStructure> forwardingCurve(
362 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), forwardingRateLevel[i], Actual365Fixed()));
363
364 Array times(0);
365 Array sigma_a(1, sigma[l]);
366 Array kappa_a(1, kappa[k]);
367 std::vector<Date> dates(0);
368 std::vector<Real> sigma_v(1, sigma[l]);
369 std::vector<Real> kappa_v(1, kappa[k]);
370
371 const QuantLib::ext::shared_ptr<IrLgm1fPiecewiseConstantHullWhiteAdaptor> irlgm1f =
372 QuantLib::ext::make_shared<IrLgm1fPiecewiseConstantHullWhiteAdaptor>(EURCurrency(), discountingCurve, times,
373 sigma_a, times, kappa_a);
374
375 std::vector<QuantLib::ext::shared_ptr<Parametrization> > params;
376 params.push_back(irlgm1f);
377 Matrix rho(1, 1);
378 rho[0][0] = 1.0;
379 const QuantLib::ext::shared_ptr<CrossAssetModel> crossasset = QuantLib::ext::make_shared<CrossAssetModel>(params, rho);
380
381 const QuantLib::ext::shared_ptr<Gaussian1dModel> g1d =
382 QuantLib::ext::make_shared<Gaussian1dCrossAssetAdaptor>(0, crossasset);
383
384 const QuantLib::ext::shared_ptr<Gsr> gsr = QuantLib::ext::make_shared<Gsr>(discountingCurve, dates, sigma_v, kappa_v);
385
386 const QuantLib::ext::shared_ptr<HullWhite> hw =
387 QuantLib::ext::make_shared<HullWhite>(discountingCurve, kappa[k], sigma[l]);
388
389 QuantLib::ext::shared_ptr<PricingEngine> engine_map_a = QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(
390 irlgm1f, discountingCurve, AnalyticLgmSwaptionEngine::nextCoupon);
391 QuantLib::ext::shared_ptr<PricingEngine> engine_map_b = QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(
392 irlgm1f, discountingCurve, AnalyticLgmSwaptionEngine::proRata);
393
394 QuantLib::ext::shared_ptr<PricingEngine> engine_g1d =
395 QuantLib::ext::make_shared<Gaussian1dSwaptionEngine>(g1d, 128, 7.0, true, false, discountingCurve);
396
397 QuantLib::ext::shared_ptr<PricingEngine> engine_gsr =
398 QuantLib::ext::make_shared<Gaussian1dSwaptionEngine>(gsr, 128, 7.0, true, false, discountingCurve);
399
400 QuantLib::ext::shared_ptr<PricingEngine> engine_fd =
401 QuantLib::ext::make_shared<FdHullWhiteSwaptionEngine>(hw, 400, 400, 0, 1.0E-8);
402
403 QuantLib::ext::shared_ptr<SwapIndex> index =
404 QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(10 * Years, forwardingCurve, discountingCurve);
405 Real atmStrike = index->fixing(TARGET().advance(Settings::instance().evaluationDate(), 5 * Years));
406
407 for (Size s = 0; s < LENGTH(strikeOffset); ++s) {
408
409 // we have to ensure positive effective fixed flows for
410 // the analytic engine (this is checked there, but we
411 // want to avoid exceptions thrown during testing)
412 if (atmStrike + strikeOffset[s] - (forwardingRateLevel[i] - discountingRateLevel[i]) < 0.0001) {
413 continue;
414 }
415
416 Swaption swaption =
417 MakeSwaption(index, 5 * Years, atmStrike + strikeOffset[s])
418 .withUnderlyingType(strikeOffset[s] > 0.0 ? VanillaSwap::Payer : VanillaSwap::Receiver);
419
420 swaption.setPricingEngine(engine_map_a);
421 Real npv_map_a = swaption.NPV();
422 swaption.setPricingEngine(engine_map_b);
423 Real npv_map_b = swaption.NPV();
424 swaption.setPricingEngine(engine_g1d);
425 Real npv_g1d = swaption.NPV();
426 swaption.setPricingEngine(engine_gsr);
427 Real npv_gsr = swaption.NPV();
428 swaption.setPricingEngine(engine_fd);
429 Real npv_fd = swaption.NPV();
430
431 if (std::abs(npv_fd - npv_gsr) > tol1) {
432 BOOST_ERROR("inconsistent swaption npvs (fd="
433 << npv_fd << ", gsr=" << npv_gsr << ") for case #" << no
434 << " with discounting rate=" << discountingRateLevel[i]
435 << ", forwarding rate=" << forwardingRateLevel[i] << ", kappa=" << kappa[k]
436 << ", sigma=" << sigma[l] << ", strike offset=" << strikeOffset[s]);
437 }
438
439 if (std::abs(npv_gsr - npv_g1d) > tol2) {
440 BOOST_ERROR("inconsistent swaption npvs (gsr="
441 << npv_gsr << ", npv_g1d=" << npv_g1d << ") for case #" << no
442 << " with discounting rate=" << discountingRateLevel[i]
443 << ", forwarding rate=" << forwardingRateLevel[i] << ", kappa=" << kappa[k]
444 << ", sigma=" << sigma[l] << ", strike offset=" << strikeOffset[s]);
445 }
446
447 Real tolTmpA = 0.0, tolTmpB = 0.0;
448 if (std::abs(discountingRateLevel[i] - forwardingRateLevel[i]) < 1.0E-6) {
449 tolTmpA = tolTmpB = tol3;
450 } else {
451 tolTmpA = tol4a * std::max(sigma[l], 0.01) / 0.01; // see above
452 tolTmpB = tol4b * std::max(sigma[l], 0.01) / 0.01; // see above
453 }
454
455 if (std::abs(npv_g1d - npv_map_a) > tolTmpA) {
456 BOOST_ERROR("inconsistent swaption npvs (g1d="
457 << npv_g1d << ", map_a=" << npv_map_a << "), tolerance is " << tolTmpA
458 << ", for case #" << no << " with discounting rate=" << discountingRateLevel[i]
459 << ", forwarding rate=" << forwardingRateLevel[i] << ", kappa=" << kappa[k]
460 << ", sigma=" << sigma[l] << ", strike offset=" << strikeOffset[s]);
461 }
462
463 if (std::abs(npv_g1d - npv_map_b) > tolTmpB) {
464 BOOST_ERROR("inconsistent swaption npvs (g1d="
465 << npv_g1d << ", map_b=" << npv_map_b << "), tolerance is " << tolTmpB
466 << ", for case #" << no << " with discounting rate=" << discountingRateLevel[i]
467 << ", forwarding rate=" << forwardingRateLevel[i] << ", kappa=" << kappa[k]
468 << ", sigma=" << sigma[l] << ", strike offset=" << strikeOffset[s]);
469 }
470
471 no++;
472 }
473 }
474 }
475 }
476} // testAgainstOtherEngines
477
478BOOST_AUTO_TEST_CASE(testLgmInvariances) {
479
480 BOOST_TEST_MESSAGE("Testing LGM model invariances in the analytic LGM "
481 "swaption engine...");
482
483 Real shift[] = { -2.0, -1.0, 0.0, 1.0, 2.0 };
484 Real scaling[] = { 5.0, 2.0, 1.0, 0.1, 0.01, -0.01, -0.1, -1.0, -2.0, -5.0 };
485
486 Handle<YieldTermStructure> discountingCurve(
487 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.03, Actual365Fixed()));
488 Handle<YieldTermStructure> forwardingCurve(
489 QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.05, Actual365Fixed()));
490
491 Array times(0);
492 Array sigma_a(1, 0.01);
493 Array alpha_a(1, 0.01);
494 Array kappa_a(1, 0.01);
495
496 QuantLib::ext::shared_ptr<SwapIndex> index =
497 QuantLib::ext::make_shared<EuriborSwapIsdaFixA>(10 * Years, forwardingCurve, discountingCurve);
498 Swaption swaption = MakeSwaption(index, 5 * Years, 0.07); // otm
499
500 for (Size i = 0; i < LENGTH(shift); ++i) {
501 for (Size j = 0; j < LENGTH(scaling); ++j) {
502
503 const QuantLib::ext::shared_ptr<IrLgm1fParametrization> irlgm1f0 =
504 QuantLib::ext::make_shared<IrLgm1fConstantParametrization>(EURCurrency(), discountingCurve, 0.01, 0.01);
505
506 const QuantLib::ext::shared_ptr<IrLgm1fParametrization> irlgm1fa =
507 QuantLib::ext::make_shared<IrLgm1fConstantParametrization>(EURCurrency(), discountingCurve, 0.01, 0.01);
508 irlgm1fa->shift() = shift[i];
509 irlgm1fa->scaling() = scaling[j];
510
511 const QuantLib::ext::shared_ptr<IrLgm1fParametrization> irlgm1fb =
512 QuantLib::ext::make_shared<IrLgm1fPiecewiseConstantParametrization>(EURCurrency(), discountingCurve, times,
513 alpha_a, times, kappa_a);
514 irlgm1fb->shift() = shift[i];
515 irlgm1fb->scaling() = scaling[j];
516
517 const QuantLib::ext::shared_ptr<IrLgm1fParametrization> irlgm1f0c =
518 QuantLib::ext::make_shared<IrLgm1fPiecewiseConstantHullWhiteAdaptor>(EURCurrency(), discountingCurve, times,
519 sigma_a, times, kappa_a);
520
521 const QuantLib::ext::shared_ptr<IrLgm1fParametrization> irlgm1fc =
522 QuantLib::ext::make_shared<IrLgm1fPiecewiseConstantHullWhiteAdaptor>(EURCurrency(), discountingCurve, times,
523 sigma_a, times, kappa_a);
524 irlgm1fc->shift() = shift[i];
525 irlgm1fc->scaling() = scaling[j];
526
527 const QuantLib::ext::shared_ptr<LinearGaussMarkovModel> lgm0 = QuantLib::ext::make_shared<LinearGaussMarkovModel>(irlgm1f0);
528 const QuantLib::ext::shared_ptr<LinearGaussMarkovModel> lgma = QuantLib::ext::make_shared<LinearGaussMarkovModel>(irlgm1fa);
529 const QuantLib::ext::shared_ptr<LinearGaussMarkovModel> lgmb = QuantLib::ext::make_shared<LinearGaussMarkovModel>(irlgm1fb);
530 const QuantLib::ext::shared_ptr<LinearGaussMarkovModel> lgm0c =
531 QuantLib::ext::make_shared<LinearGaussMarkovModel>(irlgm1f0c);
532 const QuantLib::ext::shared_ptr<LinearGaussMarkovModel> lgmc = QuantLib::ext::make_shared<LinearGaussMarkovModel>(irlgm1fc);
533
534 QuantLib::ext::shared_ptr<PricingEngine> engine0 = QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1f0);
535 QuantLib::ext::shared_ptr<PricingEngine> enginea = QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1fa);
536 QuantLib::ext::shared_ptr<PricingEngine> engineb = QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1fb);
537 QuantLib::ext::shared_ptr<PricingEngine> engine0c = QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1f0c);
538 QuantLib::ext::shared_ptr<PricingEngine> enginec = QuantLib::ext::make_shared<AnalyticLgmSwaptionEngine>(irlgm1fc);
539
540 swaption.setPricingEngine(engine0);
541 Real npv0 = swaption.NPV();
542 swaption.setPricingEngine(enginea);
543 Real npva = swaption.NPV();
544 swaption.setPricingEngine(engineb);
545 Real npvb = swaption.NPV();
546 swaption.setPricingEngine(engine0c);
547 Real npv0c = swaption.NPV();
548 swaption.setPricingEngine(enginec);
549 Real npvc = swaption.NPV();
550
551 Real tol = 1.0E-10;
552 if (std::fabs(npva - npv0) > tol) {
553 BOOST_ERROR("price is not invariant under (shift,scaling)=(" << shift[i] << "," << scaling[i]
554 << "), difference is " << (npva - npv0)
555 << " (constant parametrization)");
556 }
557 if (std::fabs(npvb - npv0) > tol) {
558 BOOST_ERROR("price is not invariant under (shift,scaling)=("
559 << shift[i] << "," << scaling[i] << "), difference is " << (npvb - npv0)
560 << " (piecewise constant parametrization)");
561 }
562 if (std::fabs(npvc - npv0c) > tol) {
563 BOOST_ERROR("price is not invariant under (shift,scaling)=("
564 << shift[i] << "," << scaling[i] << "), difference is " << (npvc - npv0c)
565 << " (hull white adaptor parametrization)");
566 }
567 }
568 }
569} // testInvariances
570
571BOOST_AUTO_TEST_SUITE_END()
572
573BOOST_AUTO_TEST_SUITE_END()
analytic cc lgm fx option engine
analytic dk cpi cap floor engine
analytic lgm cds option engine
analytic engine for european swaptions in the LGM model
analytic cross-asset lgm eq option engine
Black credit default swap option engine.
cds option calibration helper
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
Cross currency swap engine.
deposit engine
Engine to value a commodity forward contract.
discounting currency swap engine
Engine to value an Equity Forward contract.
Engine to value an FX Forward off two yield curves.
Swap engine employing assumptions to speed up calculation.
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
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Overnight Indexed Cross Currency Basis Swap Engine.
base class for model parametrizations
Single payment discounting engine.
helper classes for piecewise constant parametrizations
parameter giving access to calibration machinery
BOOST_AUTO_TEST_CASE(testMonoCurve)
Fixture that can be used at top level.
helper macros and methods for tests
#define LENGTH(a)
Definition: utilities.hpp:27