Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions | Variables
amcbermudanswaption.cpp File Reference
#include <boost/test/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include "oreatoplevelfixture.hpp"
#include <orea/cube/inmemorycube.hpp>
#include <orea/engine/observationmode.hpp>
#include <orea/scenario/crossassetmodelscenariogenerator.hpp>
#include <orea/scenario/lgmscenariogenerator.hpp>
#include <orea/scenario/scenariogeneratorbuilder.hpp>
#include <orea/scenario/scenariosimmarket.hpp>
#include <orea/scenario/simplescenario.hpp>
#include <orea/scenario/simplescenariofactory.hpp>
#include <ored/marketdata/market.hpp>
#include <ored/marketdata/marketimpl.hpp>
#include <ored/model/crossassetmodelbuilder.hpp>
#include <ored/model/irlgmdata.hpp>
#include <ored/portfolio/optionwrapper.hpp>
#include <ored/portfolio/trade.hpp>
#include <ored/utilities/log.hpp>
#include <orea/engine/amcvaluationengine.hpp>
#include <qle/instruments/fxforward.hpp>
#include <qle/models/crossassetmodel.hpp>
#include <qle/models/fxbspiecewiseconstantparametrization.hpp>
#include <qle/models/irlgm1fconstantparametrization.hpp>
#include <qle/models/irlgm1fpiecewiseconstanthullwhiteadaptor.hpp>
#include <qle/models/irlgm1fpiecewiseconstantparametrization.hpp>
#include <qle/models/lgm.hpp>
#include <qle/pricingengines/analyticcclgmfxoptionengine.hpp>
#include <qle/pricingengines/analyticlgmswaptionengine.hpp>
#include <qle/pricingengines/discountingfxforwardengine.hpp>
#include <qle/pricingengines/discountingswapenginemulticurve.hpp>
#include <qle/pricingengines/numericlgmmultilegoptionengine.hpp>
#include <qle/pricingengines/mclgmswaptionengine.hpp>
#include <ql/currencies/america.hpp>
#include <ql/currencies/europe.hpp>
#include <ql/indexes/ibor/all.hpp>
#include <ql/indexes/swap/euriborswap.hpp>
#include <ql/indexes/swap/usdliborswap.hpp>
#include <ql/instruments/makeswaption.hpp>
#include <ql/instruments/makevanillaswap.hpp>
#include <ql/math/statistics/incrementalstatistics.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/jointcalendar.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <boost/timer/timer.hpp>
#include "testmarket.hpp"

Go to the source code of this file.

Functions

std::ostream & operator<< (std::ostream &os, const TestCase &testCase)
 
 BOOST_DATA_TEST_CASE (testBermudanSwaptionExposure, boost::unit_test::data::make(testCaseData), testCase)
 

Variables

TestCase testCaseData []
 

Function Documentation

◆ operator<<()

std::ostream & operator<< ( std::ostream &  os,
const TestCase &  testCase 
)

Definition at line 175 of file amcbermudanswaption.cpp.

175{ return os << testCase.label; }

◆ BOOST_DATA_TEST_CASE()

BOOST_DATA_TEST_CASE ( testBermudanSwaptionExposure  ,
boost::unit_test::data::make(testCaseData ,
testCase   
)

Definition at line 380 of file amcbermudanswaption.cpp.

380 {
381
382 // if true, only output results (e.g. for plotting), do no checks
383 const bool outputResults = false;
384
385 // if true, cached results are used for the reference values computed with the grid engine
386 // if false, the grid engine is used for the computation, which is slow
387 // note that the cached results are for sx=4, nx=10 and gridEvalEachNth=1 (except for Long Term Simulation case,
388 // where it is 4) if these parameters change, the cached results should be refreshed
389 const bool useCachedResults = true;
390
391 BOOST_TEST_MESSAGE("Testing Bermudan swaption exposure profile");
392
393 // Simulation date grid
394 Date today = referenceDate;
395 std::vector<Period> tenorGrid;
396
397 if (!testCase.fineGrid) {
398 // coarse grid 6m spacing
399 for (Size i = 0; i < 2 * testCase.simYears; ++i) {
400 tenorGrid.push_back(((i + 1) * 6) * Months);
401 }
402 } else {
403 // fine grid 1m spacing
404 for (Size i = 0; i < 12 * testCase.simYears; ++i) {
405 tenorGrid.push_back(((i + 1)) * Months);
406 }
407 }
408
409 Calendar cal;
410 if (testCase.inBaseCcy)
411 cal = TARGET();
412 else
413 cal = JointCalendar(UnitedStates(UnitedStates::Settlement), UnitedKingdom());
414
415 QuantLib::ext::shared_ptr<DateGrid> grid = QuantLib::ext::make_shared<DateGrid>(tenorGrid, cal, ActualActual(ActualActual::ISDA));
416
417 // Model
418 QuantLib::ext::shared_ptr<QuantExt::CrossAssetModel> model = ccLgm;
419
420 // Simulation market parameters, we just need the yield curve structure here
421 QuantLib::ext::shared_ptr<ScenarioSimMarketParameters> simMarketConfig(new ScenarioSimMarketParameters);
422 simMarketConfig->setYieldCurveTenors("", {3 * Months, 6 * Months, 1 * Years, 2 * Years, 3 * Years, 4 * Years,
423 5 * Years, 7 * Years, 10 * Years, 12 * Years, 15 * Years, 20 * Years,
424 30 * Years, 40 * Years, 50 * Years});
425 simMarketConfig->setSimulateFXVols(false);
426
427 simMarketConfig->baseCcy() = "EUR";
428 simMarketConfig->setDiscountCurveNames({"EUR", "USD"});
429 simMarketConfig->ccys() = {"EUR", "USD"};
430 std::vector<std::string> tmp;
431 for (auto c : simMarketConfig->ccys()) {
432 if (c != simMarketConfig->baseCcy())
433 tmp.push_back(c + simMarketConfig->baseCcy());
434 }
435 simMarketConfig->setFxCcyPairs(tmp);
436
437 simMarketConfig->setIndices({"EUR-EURIBOR-6M", "USD-LIBOR-3M"});
438 simMarketConfig->interpolation() = "LogLinear";
439 simMarketConfig->setSwapVolExpiries("EUR", {6 * Months, 1 * Years, 2 * Years, 3 * Years, 5 * Years, 10 * Years});
440 simMarketConfig->setSwapVolTerms("EUR", {1 * Years, 2 * Years, 3 * Years, 5 * Years, 7 * Years, 10 * Years});
441
442 QuantLib::ext::shared_ptr<ScenarioGeneratorData> sgd(new ScenarioGeneratorData);
443 sgd->sequenceType() = SobolBrownianBridge;
444 sgd->seed() = 42;
445 sgd->setGrid(grid);
446
448 QuantLib::ext::shared_ptr<ScenarioFactory> sf = QuantLib::ext::make_shared<SimpleScenarioFactory>(true);
449 QuantLib::ext::shared_ptr<ScenarioGenerator> sg = sgb.build(model, sf, simMarketConfig, today, market);
450
451 auto simMarket = QuantLib::ext::make_shared<ScenarioSimMarket>(market, simMarketConfig);
452 simMarket->scenarioGenerator() = sg;
453
454 // Bermudan swaption for exposure generation
455 Date startDate = cal.advance(today, 2 * Days);
456 Date fwdStartDate = cal.advance(startDate, 10 * Years);
457 Date endDate = cal.advance(fwdStartDate, testCase.swapLen * Years);
458 Schedule fixedSchedule(fwdStartDate, endDate, 1 * Years, cal, Following, Following, DateGeneration::Forward, false);
459 Schedule floatingSchedule(fwdStartDate, endDate, (testCase.inBaseCcy ? 6 : 3) * Months, cal, Following, Following,
460 DateGeneration::Forward, false);
461 Schedule fixedScheduleSwap(startDate, endDate, 1 * Years, cal, Following, Following, DateGeneration::Forward,
462 false);
463 Schedule floatingScheduleSwap(startDate, endDate, (testCase.inBaseCcy ? 6 : 3) * Months, cal, Following, Following,
464 DateGeneration::Forward, false);
465 Schedule fixedScheduleSwapShort(startDate, fwdStartDate, 1 * Years, cal, Following, Following,
466 DateGeneration::Forward, false);
467 Schedule floatingScheduleSwapShort(startDate, fwdStartDate, (testCase.inBaseCcy ? 6 : 3) * Months, cal, Following,
468 Following, DateGeneration::Forward, false);
469 QuantLib::ext::shared_ptr<VanillaSwap> underlying, vanillaswap, vanillaswapshort;
470 QuantLib::ext::shared_ptr<NonstandardSwap> underlyingNs, vanillaswapNs, vanillaswapshortNs;
471 if (!testCase.isAmortising) {
472 // Standard Vanilla Swap
473 if (testCase.inBaseCcy) {
474 underlying = QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap::Payer, 1.0, fixedSchedule, 0.02, Thirty360(Thirty360::BondBasis),
475 floatingSchedule, *simMarket->iborIndex("EUR-EURIBOR-6M"), 0.0,
476 Actual360());
477 } else {
478 underlying = QuantLib::ext::make_shared<VanillaSwap>(VanillaSwap::Payer, 1.0, fixedSchedule, 0.03, Thirty360(Thirty360::BondBasis),
479 floatingSchedule, *simMarket->iborIndex("USD-LIBOR-3M"), 0.0,
480 Actual360());
481 }
482 } else {
483 // Nonstandard Swap
484 std::vector<Real> fixNotionals(fixedSchedule.size() - 1), floatNotionals(floatingSchedule.size() - 1);
485 std::vector<Real> fixNotionalsSwap(fixedScheduleSwap.size() - 1),
486 floatNotionalsSwap(floatingScheduleSwap.size() - 1);
487 std::vector<Real> fixNotionalsShort(fixedScheduleSwapShort.size() - 1),
488 floatNotionalsShort(floatingScheduleSwapShort.size() - 1);
489 for (Size i = 0; i < fixNotionals.size(); ++i)
490 fixNotionals[i] = 1.0 - static_cast<Real>(i) / static_cast<Real>(fixNotionals.size());
491 for (Size i = 0; i < floatNotionals.size(); ++i)
492 floatNotionals[i] = 1.0 - static_cast<Real>(i) / static_cast<Real>(floatNotionals.size());
493 for (Size i = 0; i < fixNotionalsSwap.size(); ++i)
494 fixNotionalsSwap[i] = 1.0 - static_cast<Real>(i) / static_cast<Real>(fixNotionalsSwap.size());
495 for (Size i = 0; i < floatNotionalsSwap.size(); ++i)
496 floatNotionalsSwap[i] = 1.0 - static_cast<Real>(i) / static_cast<Real>(floatNotionalsSwap.size());
497 for (Size i = 0; i < fixNotionalsShort.size(); ++i)
498 fixNotionalsShort[i] = 1.0 - static_cast<Real>(i) / static_cast<Real>(fixNotionalsShort.size());
499 for (Size i = 0; i < floatNotionalsShort.size(); ++i)
500 floatNotionalsShort[i] = 1.0 - static_cast<Real>(i) / static_cast<Real>(floatNotionalsShort.size());
501
502 if (testCase.inBaseCcy) {
503 underlyingNs = QuantLib::ext::make_shared<NonstandardSwap>(
504 VanillaSwap::Payer, fixNotionals, floatNotionals, fixedSchedule,
505 std::vector<Real>(fixNotionals.size(), 0.02), Thirty360(Thirty360::BondBasis), floatingSchedule,
506 *simMarket->iborIndex("EUR-EURIBOR-6M"), 1.0, 0.0, Actual360());
507 } else {
508 underlyingNs = QuantLib::ext::make_shared<NonstandardSwap>(
509 VanillaSwap::Payer, fixNotionals, floatNotionals, fixedSchedule,
510 std::vector<Real>(fixNotionals.size(), 0.03), Thirty360(Thirty360::BondBasis), floatingSchedule,
511 *simMarket->iborIndex("USD-LIBOR-3M"), 1.0, 0.0, Actual360());
512 }
513 }
514
515 // needed for physical exercise in the option wrapper
516 QuantLib::ext::shared_ptr<PricingEngine> underlyingEngine = QuantLib::ext::make_shared<QuantLib::DiscountingSwapEngine>(
517 testCase.inBaseCcy ? simMarket->discountCurve("EUR") : simMarket->discountCurve("USD"));
518 if (underlying)
519 underlying->setPricingEngine(underlyingEngine);
520 if (underlyingNs)
521 underlyingNs->setPricingEngine(underlyingEngine);
522 if (vanillaswap) {
523 vanillaswap->setPricingEngine(underlyingEngine);
524 vanillaswapshort->setPricingEngine(underlyingEngine);
525 }
526 if (vanillaswapNs) {
527 vanillaswapNs->setPricingEngine(underlyingEngine);
528 vanillaswapshortNs->setPricingEngine(underlyingEngine);
529 }
530
531 // collect fixing dates
532 std::vector<Date> fixingDates;
533 if (vanillaswap) {
534 for (Size i = 0; i < vanillaswap->leg(1).size(); ++i) {
535 QuantLib::ext::shared_ptr<IborCoupon> c = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(vanillaswap->leg(1)[i]);
536 fixingDates.push_back(c->fixingDate());
537 }
538 } else if (vanillaswapNs) {
539 for (Size i = 0; i < vanillaswapNs->leg(1).size(); ++i) {
540 QuantLib::ext::shared_ptr<IborCoupon> c = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(vanillaswapNs->leg(1)[i]);
541 fixingDates.push_back(c->fixingDate());
542 }
543 } else if (underlying) {
544 for (Size i = 0; i < underlying->leg(1).size(); ++i) {
545 QuantLib::ext::shared_ptr<IborCoupon> c = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(underlying->leg(1)[i]);
546 fixingDates.push_back(c->fixingDate());
547 }
548 } else if (underlyingNs) {
549 for (Size i = 0; i < underlyingNs->leg(1).size(); ++i) {
550 QuantLib::ext::shared_ptr<IborCoupon> c = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(underlyingNs->leg(1)[i]);
551 fixingDates.push_back(c->fixingDate());
552 }
553 }
554
555 // exercise dates
556 std::vector<Date> exerciseDates;
557 for (Size i = 0; i < testCase.numExercises; ++i) {
558 if (!testCase.fineGrid)
559 // coarse grid
560 exerciseDates.push_back(grid->dates()[19 + 2 * i]);
561 else
562 // find grid
563 exerciseDates.push_back(grid->dates()[119 + 12 * i]);
564 }
565
566 QuantLib::ext::shared_ptr<QuantLib::Instrument> tmpUnd;
567 if (testCase.isAmortising)
568 tmpUnd = underlyingNs;
569 else
570 tmpUnd = underlying;
571 std::vector<QuantLib::ext::shared_ptr<QuantLib::Instrument>> undInst(exerciseDates.size(), tmpUnd);
572
573 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<BermudanExercise>(exerciseDates);
574 QuantLib::ext::shared_ptr<Instrument> swaption;
575 Settlement::Type settlementType = testCase.isPhysical ? Settlement::Physical : Settlement::Cash;
576 Settlement::Method settlementMethod =
577 testCase.isPhysical ? Settlement::PhysicalOTC : Settlement::CollateralizedCashPrice;
578 if (testCase.isAmortising)
579 swaption = QuantLib::ext::make_shared<NonstandardSwaption>(underlyingNs, exercise, settlementType, settlementMethod);
580 else
581 swaption = QuantLib::ext::make_shared<Swaption>(underlying, exercise, settlementType, settlementMethod);
582
583 QuantLib::ext::shared_ptr<IrLgm1fParametrization> param;
584 // vol and rev must be consistent to CAM's LGM models in TestData
585 Array emptyTimes;
586 Array alphaEur(1), kappaEur(1), alphaUsd(1), kappaUsd(1);
587 alphaEur[0] = lgm_eur->parametrization()->hullWhiteSigma(1.0);
588 kappaEur[0] = lgm_eur->parametrization()->kappa(1.0);
589 alphaUsd[0] = lgm_usd->parametrization()->hullWhiteSigma(1.0);
590 kappaUsd[0] = lgm_usd->parametrization()->kappa(1.0);
591 if (testCase.inBaseCcy)
592 param = QuantLib::ext::make_shared<IrLgm1fPiecewiseConstantHullWhiteAdaptor>(
593 EURCurrency(), simMarket->discountCurve("EUR"), emptyTimes, alphaEur, emptyTimes, kappaEur);
594 else
595 param = QuantLib::ext::make_shared<IrLgm1fPiecewiseConstantHullWhiteAdaptor>(
596 USDCurrency(), simMarket->discountCurve("USD"), emptyTimes, alphaUsd, emptyTimes, kappaUsd);
597 QuantLib::ext::shared_ptr<LinearGaussMarkovModel> bermmodel = QuantLib::ext::make_shared<LinearGaussMarkovModel>(param);
598
599 // apply horizon shift
600 // for grid engine
601 param->shift() = -param->H(testCase.horizonShift);
602 // for CAM and EUR AMC engine
603 QuantLib::ext::static_pointer_cast<IrLgm1fParametrization>(lgm_eur->parametrization())->shift() =
604 -QuantLib::ext::static_pointer_cast<IrLgm1fParametrization>(lgm_eur->parametrization())->H(testCase.horizonShift);
605 // for USD AMC engine (in CAM no effect)
606 QuantLib::ext::static_pointer_cast<IrLgm1fParametrization>(lgm_usd->parametrization())->shift() =
607 -QuantLib::ext::static_pointer_cast<IrLgm1fParametrization>(lgm_usd->parametrization())->H(testCase.horizonShift);
608
609 // grid engine
610
611 QuantLib::ext::shared_ptr<PricingEngine> engineGrid;
612 if (testCase.isAmortising)
613 engineGrid = QuantLib::ext::make_shared<NumericLgmNonstandardSwaptionEngine>(bermmodel, Real(testCase.sx), testCase.nx,
614 Real(testCase.sx), testCase.nx);
615 else
616 engineGrid = QuantLib::ext::make_shared<NumericLgmSwaptionEngine>(bermmodel, Real(testCase.sx), testCase.nx,
617 Real(testCase.sx), testCase.nx);
618
619 // mc engine
620 std::vector<Size> externalModelIndices = testCase.inBaseCcy ? std::vector<Size>{0} : std::vector<Size>{1};
621 QuantLib::ext::shared_ptr<PricingEngine> engineMc;
622 if (testCase.isAmortising) {
623 engineMc = QuantLib::ext::make_shared<McLgmNonstandardSwaptionEngine>(
624 testCase.inBaseCcy ? lgm_eur : lgm_usd, MersenneTwisterAntithetic, SobolBrownianBridge,
625 testCase.trainingPaths, 0, 4711, 4712, 6, LsmBasisSystem::Monomial, SobolBrownianGenerator::Steps,
626 SobolRsg::JoeKuoD7, Handle<YieldTermStructure>(), grid->dates(), externalModelIndices);
627 swaption->setPricingEngine(engineMc);
628 } else {
629 engineMc = QuantLib::ext::make_shared<McLgmSwaptionEngine>(
630 testCase.inBaseCcy ? lgm_eur : lgm_usd, MersenneTwisterAntithetic, SobolBrownianBridge,
631 testCase.trainingPaths, 0, 4711, 4712, 6, LsmBasisSystem::Monomial, SobolBrownianGenerator::Steps,
632 SobolRsg::JoeKuoD7, Handle<YieldTermStructure>(), grid->dates(), externalModelIndices);
633 swaption->setPricingEngine(engineMc);
634 }
635
636 // wrapper (long option)
637
638 QuantLib::ext::shared_ptr<InstrumentWrapper> wrapperGrid = QuantLib::ext::make_shared<BermudanOptionWrapper>(
639 swaption, vanillaswap ? false : true, exerciseDates, testCase.isPhysical, undInst);
640 wrapperGrid->initialise(grid->dates());
641
642 // collect discounted epe
643 std::vector<Real> swaption_epe_grid(grid->dates().size(), 0.0);
644 std::vector<Real> swaption_epe_amc(grid->dates().size(), 0.0);
645
646 // amc valuation
647 swaption->setPricingEngine(engineMc);
648 class TestTrade : public Trade {
649 public:
650 TestTrade(const string& tradeType, const string& curr, const QuantLib::ext::shared_ptr<InstrumentWrapper>& inst)
651 : Trade(tradeType) {
652 instrument_ = inst;
653 npvCurrency_ = curr;
654 }
655 void build(const QuantLib::ext::shared_ptr<EngineFactory>&) override {}
656 };
657 AMCValuationEngine amcValEngine(model, sgd, QuantLib::ext::shared_ptr<Market>(), std::vector<string>(),
658 std::vector<string>(), 0);
659 auto trade = QuantLib::ext::make_shared<TestTrade>("BermudanSwaption", testCase.inBaseCcy ? "EUR" : "USD",
660 QuantLib::ext::make_shared<VanillaInstrument>(swaption));
661 trade->id() = "DummyTradeId";
662 auto portfolio = QuantLib::ext::make_shared<Portfolio>();
663 portfolio->add(trade);
664 QuantLib::ext::shared_ptr<NPVCube> outputCube = QuantLib::ext::make_shared<DoublePrecisionInMemoryCube>(
665 referenceDate, std::set<string>{"DummyTradeId"}, grid->dates(), testCase.samples);
666 boost::timer::cpu_timer timer;
667 amcValEngine.buildCube(portfolio, outputCube);
668 timer.stop();
669 Real amcTime = timer.elapsed().wall * 1e-9;
670
671 // epe computation (this is divided by the number of samples below)
672 for (Size j = 0; j < grid->dates().size(); ++j) {
673 for (Size i = 0; i < testCase.samples; ++i) {
674 swaption_epe_amc[j] += std::max(outputCube->get(0, j, i, 0), 0.0);
675 }
676 }
677
678 Real fx = 1.0;
679 if (!testCase.inBaseCcy)
680 fx = simMarket->fxRate("USDEUR")->value();
681
682 Real amcNPV = outputCube->getT0(0, 0) / fx; // convert back to USD, cube contains base ccy values
683
684 timer.start();
685 swaption->setPricingEngine(engineGrid);
686 Real gridNPV = swaption->NPV();
687 timer.stop();
688 Real gridTime0 = timer.elapsed().wall * 1e-9;
689
690 BOOST_CHECK_MESSAGE((std::abs(gridNPV - amcNPV) <= testCase.tolerance),
691 "Can not verify gridNPV (" << gridNPV << ") and amcNPV (" << amcNPV << ")"
692 << ", difference is " << gridNPV - amcNPV << ", tolerance is "
693 << testCase.tolerance);
694
695 // grid engine simulation (only if not cached, this takes a long time)
696 if (useCachedResults) {
697 for (Size t = 0; t < grid->dates().size(); ++t) {
698 swaption_epe_grid.at(t) = testCase.cachedResults.at(t).at(1) * static_cast<Real>(testCase.samples);
699 }
700 } else {
701 Real updateTime = 0.0;
702 Real gridTime = 0.0;
703 BOOST_TEST_MESSAGE("running " << testCase.samples << " samples simulation over " << grid->dates().size()
704 << " time steps");
705 QuantLib::ext::shared_ptr<IborIndex> index =
706 *(testCase.inBaseCcy ? simMarket->iborIndex("EUR-EURIBOR-6M") : simMarket->iborIndex("USD-LIBOR-3M"));
707 for (Size i = 0; i < testCase.samples; ++i) {
708 if (i % 100 == 0)
709 BOOST_TEST_MESSAGE("Sample " << i);
710 Size idx = 0, fixIdx = 0;
711 Size gridCnt = testCase.gridEvalEachNth;
712 for (Date date : grid->dates()) {
713 timer.start();
714 // if we use cached results, we do not need the sim market
715 simMarket->update(date);
716 // set fixings
717 Real v = index->fixing(date);
718 while (fixIdx < fixingDates.size() && fixingDates[fixIdx] <= date) {
719 index->addFixing(fixingDates[fixIdx], v);
720 ++fixIdx;
721 }
722 // we do not use the valuation engine, so in case updates are disabled we need to
723 // take care of the instrument update ourselves
724 // this is only relevant for the discrete sim market, not the model sim market
725 swaption->update();
726 if (underlying)
727 underlying->update();
728 if (underlyingNs)
729 underlyingNs->update();
730 if (vanillaswap) {
731 vanillaswap->update();
732 vanillaswapshort->update();
733 }
734 if (vanillaswapNs) {
735 vanillaswapNs->update();
736 vanillaswapshortNs->update();
737 }
738 timer.stop();
739 updateTime += timer.elapsed().wall * 1e-9;
740 Real numeraire = simMarket->numeraire();
741 Real fx = 1.0;
742 if (!testCase.inBaseCcy)
743 fx = simMarket->fxRate("USDEUR")->value();
744 // swaption epe accumulation
745 if (--gridCnt == 0) {
746 timer.start();
747 swaption_epe_grid[idx] += std::max(wrapperGrid->NPV() * fx, 0.0) / numeraire;
748 timer.stop();
749 gridTime += timer.elapsed().wall * 1e-9;
750 gridCnt = testCase.gridEvalEachNth;
751 }
752 idx++;
753 }
754 wrapperGrid->reset();
755 index->clearFixings();
756 }
757 BOOST_TEST_MESSAGE("Simulation time, grid " << gridTime << ", updates " << updateTime);
758 }
759
760 // compute summary statistics for swaption and check results
761 if (outputResults) {
762 std::clog << "time swaption_epe_grid swaption_epe_amc" << std::endl;
763 }
764 Size gridCnt = testCase.gridEvalEachNth;
765 Real maxSwaptionErr = 0.0;
766 for (Size i = 0; i < swaption_epe_grid.size(); ++i) {
767 Real t = grid->timeGrid()[i + 1];
768 swaption_epe_grid[i] /= testCase.samples;
769 swaption_epe_amc[i] /= testCase.samples;
770 if (outputResults) {
771 if (useCachedResults) {
772 // output all results
773 std::clog << t << " " << swaption_epe_grid[i] << " " << swaption_epe_amc[i] << " " << std::endl;
774 } else {
775 // output results in a format that makes it easy to insert them as cached results in the code above
776 std::clog << "{" << t << ", " << swaption_epe_grid[i] << std::endl;
777 }
778 }
779 if (--gridCnt == 0) {
780 if (!outputResults) {
781 BOOST_CHECK_MESSAGE((std::abs(swaption_epe_grid[i] - swaption_epe_amc[i]) <= testCase.tolerance),
782 "Can not verify swaption epe at grid point t="
783 << t << ", grid = " << swaption_epe_grid[i] << ", amc = " << swaption_epe_amc[i]
784 << ", difference " << (swaption_epe_grid[i] - swaption_epe_amc[i])
785 << ", tolerance " << testCase.tolerance);
786 }
787 maxSwaptionErr = std::max(maxSwaptionErr, std::abs(swaption_epe_grid[i] - swaption_epe_amc[i]));
788 gridCnt = testCase.gridEvalEachNth;
789 }
790 }
791 BOOST_TEST_MESSAGE("AMC simulation time = " << amcTime << "s, T0 NPV (AMC) = " << amcNPV
792 << ", T0 NPV (Grid) = " << gridNPV << " (" << gridTime0 * 1000.0
793 << " ms), Max Error Swaption = " << maxSwaptionErr);
794
795} // testBermudanSwaptionExposure
virtual void build(const QuantLib::ext::shared_ptr< EngineFactory > &)=0
Date referenceDate
SobolBrownianBridge
Size size(const ValueType &v)
+ Here is the call graph for this function:

Variable Documentation

◆ testCaseData

TestCase testCaseData[]

Definition at line 177 of file amcbermudanswaption.cpp.