Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions
analyticlgmswaptionengine.cpp File Reference
#include "utilities.hpp"
#include "toplevelfixture.hpp"
#include <boost/test/unit_test.hpp>
#include <qle/models/cdsoptionhelper.hpp>
#include <qle/models/cpicapfloorhelper.hpp>
#include <qle/models/crlgm1fparametrization.hpp>
#include <qle/models/crossassetanalytics.hpp>
#include <qle/models/crossassetanalyticsbase.hpp>
#include <qle/models/crossassetmodel.hpp>
#include <qle/models/crossassetmodelimpliedeqvoltermstructure.hpp>
#include <qle/models/crossassetmodelimpliedfxvoltermstructure.hpp>
#include <qle/models/dkimpliedyoyinflationtermstructure.hpp>
#include <qle/models/dkimpliedzeroinflationtermstructure.hpp>
#include <qle/models/eqbsconstantparametrization.hpp>
#include <qle/models/eqbsparametrization.hpp>
#include <qle/models/eqbspiecewiseconstantparametrization.hpp>
#include <qle/models/fxbsconstantparametrization.hpp>
#include <qle/models/fxbsparametrization.hpp>
#include <qle/models/fxbspiecewiseconstantparametrization.hpp>
#include <qle/models/fxeqoptionhelper.hpp>
#include <qle/models/gaussian1dcrossassetadaptor.hpp>
#include <qle/models/infdkparametrization.hpp>
#include <qle/models/irlgm1fconstantparametrization.hpp>
#include <qle/models/irlgm1fparametrization.hpp>
#include <qle/models/irlgm1fpiecewiseconstanthullwhiteadaptor.hpp>
#include <qle/models/irlgm1fpiecewiseconstantparametrization.hpp>
#include <qle/models/irlgm1fpiecewiselinearparametrization.hpp>
#include <qle/models/lgm.hpp>
#include <qle/models/lgmimplieddefaulttermstructure.hpp>
#include <qle/models/lgmimpliedyieldtermstructure.hpp>
#include <qle/models/linkablecalibratedmodel.hpp>
#include <qle/models/parametrization.hpp>
#include <qle/models/piecewiseconstanthelper.hpp>
#include <qle/models/pseudoparameter.hpp>
#include <qle/pricingengines/analyticcclgmfxoptionengine.hpp>
#include <qle/pricingengines/analyticdkcpicapfloorengine.hpp>
#include <qle/pricingengines/analyticlgmcdsoptionengine.hpp>
#include <qle/pricingengines/analyticlgmswaptionengine.hpp>
#include <qle/pricingengines/analyticxassetlgmeqoptionengine.hpp>
#include <qle/pricingengines/blackcdsoptionengine.hpp>
#include <qle/pricingengines/crossccyswapengine.hpp>
#include <qle/pricingengines/depositengine.hpp>
#include <qle/pricingengines/discountingcommodityforwardengine.hpp>
#include <qle/pricingengines/discountingcurrencyswapengine.hpp>
#include <qle/pricingengines/discountingequityforwardengine.hpp>
#include <qle/pricingengines/discountingfxforwardengine.hpp>
#include <qle/pricingengines/discountingriskybondengine.hpp>
#include <qle/pricingengines/discountingswapenginemulticurve.hpp>
#include <qle/pricingengines/numericlgmmultilegoptionengine.hpp>
#include <qle/pricingengines/oiccbasisswapengine.hpp>
#include <qle/pricingengines/paymentdiscountingengine.hpp>
#include <ql/currencies/europe.hpp>
#include <ql/indexes/swap/euriborswap.hpp>
#include <ql/instruments/makeswaption.hpp>
#include <ql/math/array.hpp>
#include <ql/math/comparison.hpp>
#include <ql/models/shortrate/onefactormodels/gsr.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
#include <ql/pricingengines/swaption/fdhullwhiteswaptionengine.hpp>
#include <ql/pricingengines/swaption/gaussian1dswaptionengine.hpp>
#include <ql/pricingengines/credit/midpointcdsengine.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/nullcalendar.hpp>
#include <ql/time/calendars/target.hpp>
#include <boost/make_shared.hpp>

Go to the source code of this file.

Functions

 BOOST_AUTO_TEST_CASE (testMonoCurve)
 
 BOOST_AUTO_TEST_CASE (testDualCurve)
 
 BOOST_AUTO_TEST_CASE (testAgainstOtherEngines)
 
 BOOST_AUTO_TEST_CASE (testLgmInvariances)
 

Function Documentation

◆ BOOST_AUTO_TEST_CASE() [1/4]

BOOST_AUTO_TEST_CASE ( testMonoCurve  )

Definition at line 103 of file analyticlgmswaptionengine.cpp.

103 {
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}
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [2/4]

BOOST_AUTO_TEST_CASE ( testDualCurve  )

Definition at line 209 of file analyticlgmswaptionengine.cpp.

209 {
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}
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [3/4]

BOOST_AUTO_TEST_CASE ( testAgainstOtherEngines  )

Definition at line 314 of file analyticlgmswaptionengine.cpp.

314 {
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
#define LENGTH(a)
Definition: utilities.hpp:27

◆ BOOST_AUTO_TEST_CASE() [4/4]

BOOST_AUTO_TEST_CASE ( testLgmInvariances  )

Definition at line 478 of file analyticlgmswaptionengine.cpp.

478 {
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