20#include <boost/test/unit_test.hpp>
21#include <boost/test/data/test_case.hpp>
60#include <ql/currencies/america.hpp>
61#include <ql/currencies/europe.hpp>
62#include <ql/indexes/ibor/all.hpp>
63#include <ql/indexes/swap/euriborswap.hpp>
64#include <ql/indexes/swap/usdliborswap.hpp>
65#include <ql/instruments/makeswaption.hpp>
66#include <ql/instruments/makevanillaswap.hpp>
67#include <ql/math/statistics/incrementalstatistics.hpp>
68#include <ql/pricingengines/swap/discountingswapengine.hpp>
69#include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
70#include <ql/quotes/simplequote.hpp>
71#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
72#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
73#include <ql/termstructures/yield/flatforward.hpp>
74#include <ql/time/calendars/jointcalendar.hpp>
75#include <ql/time/calendars/target.hpp>
76#include <ql/time/daycounters/actual360.hpp>
77#include <ql/time/daycounters/thirty360.hpp>
79#include <boost/timer/timer.hpp>
85using namespace boost::unit_test_framework;
91 ObservationMode::instance().setMode(ObservationMode::Mode::None);
95 market = QuantLib::ext::make_shared<testsuite::TestMarket>(referenceDate);
101 vector<string> swaptionExpiries = {
"1Y",
"2Y",
"3Y",
"5Y",
"7Y",
"10Y",
"15Y",
"20Y",
"30Y"};
102 vector<string> swaptionTerms = {
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y"};
103 vector<string> swaptionStrikes(swaptionExpiries.size(),
"ATM");
104 vector<Time> hTimes = {};
105 vector<Time> aTimes = {};
107 std::vector<QuantLib::ext::shared_ptr<IrModelData>> irConfigs;
109 vector<Real> hValues = {0.02};
110 vector<Real> aValues = {0.01};
111 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
112 "EUR", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
113 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
117 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
118 "USD", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
119 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
122 vector<string> optionExpiries = {};
123 vector<string> optionStrikes = {};
124 vector<Time> sigmaTimes = {};
126 std::vector<QuantLib::ext::shared_ptr<FxBsData>> fxConfigs;
127 vector<Real> sigmaValues = {0.15};
128 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>(
"USD",
"EUR", calibrationType,
false, ParamType::Constant,
129 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
132 cmb.
addCorrelation(
"IR:EUR",
"IR:USD", Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.5)));
133 cmb.
addCorrelation(
"IR:EUR",
"FX:USDEUR", Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.6)));
134 cmb.
addCorrelation(
"IR:USD",
"FX:USDEUR", Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.7)));
137 QuantLib::ext::shared_ptr<CrossAssetModelData> config(
138 QuantLib::ext::make_shared<CrossAssetModelData>(irConfigs, fxConfigs, cmb.
correlations()));
142 ccLgm = *modelBuilder.model();
143 lgm_eur = QuantLib::ext::make_shared<QuantExt::LGM>(ccLgm->irlgm1f(0));
144 lgm_usd = QuantLib::ext::make_shared<QuantExt::LGM>(ccLgm->irlgm1f(1));
148 QuantLib::ext::shared_ptr<ore::data::Conventions> conventions_;
149 QuantLib::ext::shared_ptr<CrossAssetModelData> config;
150 QuantLib::ext::shared_ptr<QuantExt::CrossAssetModel> ccLgm;
151 QuantLib::ext::shared_ptr<QuantExt::LGM> lgm_eur, lgm_usd;
152 QuantLib::ext::shared_ptr<ore::data::Market> market;
159 Size gridEvalEachNth;
171 std::vector<std::vector<Real>> cachedResults;
175std::ostream&
operator<<(std::ostream& os,
const TestCase& testCase) {
return os << testCase.label; }
178 {
"Physical Settled Swaption EUR 10y10y",
193 {{0.509357, 0.091875}, {1.00662, 0.0918901}, {1.50411, 0.0918698}, {2.00274, 0.0918969}, {2.50411, 0.0919471},
194 {3, 0.0919541}, {3.50411, 0.0919187}, {4, 0.091858}, {4.50389, 0.0917798}, {5.00116, 0.0918077},
195 {5.50959, 0.0917394}, {6, 0.0917051}, {6.50685, 0.0915082}, {7.00548, 0.0914719}, {7.50411, 0.0916239},
196 {8.00274, 0.0916299}, {8.50389, 0.0915738}, {9.00116, 0.0917204}, {9.50411, 0.0920092}, {10, 0.0918714},
197 {10.5041, 0.0917764}, {11, 0.0844412}, {11.5096, 0.0831162}, {12, 0.0758481}, {12.5066, 0.0743106},
198 {13.0039, 0.0670203}, {13.5041, 0.0661777}, {14, 0.0583992}, {14.5041, 0.0571024}, {15, 0.0494685},
199 {15.5041, 0.0481926}, {16, 0.0403637}, {16.5039, 0.0389221}, {17.0012, 0.0309469}, {17.5068, 0.0294415},
200 {18.0055, 0.0214747}, {18.5041, 0.0199978}, {19.0027, 0.0118743}, {19.5041, 0.0098358}, {20, 0.00239165},
201 {20.5039, 0}, {21.0012, 0}}},
202 {
"Cash Settled Swaption EUR 10y10y",
217 {{0.509357, 0.091875}, {1.00662, 0.0918901},
218 {1.50411, 0.0918698}, {2.00274, 0.0918969},
219 {2.50411, 0.0919471}, {3, 0.0919541},
220 {3.50411, 0.0919187}, {4, 0.091858},
221 {4.50389, 0.0917798}, {5.00116, 0.0918077},
222 {5.50959, 0.0917394}, {6, 0.0917051},
223 {6.50685, 0.0915082}, {7.00548, 0.0914719},
224 {7.50411, 0.0916239}, {8.00274, 0.0916299},
225 {8.50389, 0.0915738}, {9.00116, 0.0917204},
226 {9.50411, 0.0920092}, {10, 0.0918714},
227 {10.5041, 0.0216995}, {11, 0.0216537},
228 {11.5096, 0.0165814}, {12, 0.0165204},
229 {12.5066, 0.0114238}, {13.0039, 0.0112071},
230 {13.5041, 0.00810083}, {14, 0.00810626},
231 {14.5041, 0.00498351}, {15, 0.00494857},
232 {15.5041, 0.00302471}, {16, 0.00300223},
233 {16.5039, 0.00161475}, {17.0012, 0.00150577},
234 {17.5068, 0.000872231}, {18.0055, 0.000691536},
235 {18.5041, 0.000427726}, {19.0027, 0.000259685},
236 {19.5041, 0}, {20, 0},
237 {20.5039, 0}, {21.0012, 0}}},
238 {
"Physical Settled Swaption USD 10y10y",
253 {{0.509357, 0.05351}, {1.00662, 0.0534781}, {1.50411, 0.0533827}, {2.00274, 0.0532503}, {2.50411, 0.0533026},
254 {3, 0.053185}, {3.50411, 0.0530595}, {4, 0.0529746}, {4.50389, 0.0530751}, {5.00116, 0.0532191},
255 {5.50959, 0.0529909}, {6, 0.0530138}, {6.50685, 0.0529023}, {7.00548, 0.0529725}, {7.50411, 0.0530392},
256 {8.00274, 0.0525997}, {8.50389, 0.052524}, {9.00116, 0.052617}, {9.50411, 0.0528042}, {10, 0.0527962},
257 {10.5041, 0.0501823}, {11, 0.043772}, {11.5096, 0.0440506}, {12, 0.0384473}, {12.5066, 0.0392294},
258 {13.0039, 0.0338302}, {13.5041, 0.0339911}, {14, 0.0287289}, {14.5041, 0.0292609}, {15, 0.0235833},
259 {15.5041, 0.0240571}, {16, 0.0184883}, {16.5039, 0.0189846}, {17.0012, 0.0133277}, {17.5068, 0.0134281},
260 {18.0055, 0.00808448}, {18.5041, 0.00806168}, {19.0027, 0.00289948}, {19.5041, 0.00248467}, {20, 1.91824e-06},
261 {20.5039, 0}, {21.0012, 0}}},
300 {
"Physical Settled Swaption EUR 10y50y (Long Term Simulation)",
315 {{0.509357, 0}, {1.00662, 0}, {1.50411, 0}, {2.00274, 0.36692},
316 {2.50411, 0}, {3, 0}, {3.50411, 0}, {4, 0.367243},
317 {4.50389, 0}, {5.00116, 0}, {5.50959, 0}, {6, 0.366503},
318 {6.50685, 0}, {7.00548, 0}, {7.50411, 0}, {8.00274, 0.365889},
319 {8.50389, 0}, {9.00116, 0}, {9.50411, 0}, {10, 0.363011},
320 {10.5041, 0}, {11, 0}, {11.5096, 0}, {12, 0.352021},
321 {12.5066, 0}, {13.0039, 0}, {13.5041, 0}, {14, 0.337706},
322 {14.5041, 0}, {15, 0}, {15.5041, 0}, {16, 0.320619},
323 {16.5039, 0}, {17.0012, 0}, {17.5068, 0}, {18.0055, 0.304939},
324 {18.5041, 0}, {19.0027, 0}, {19.5041, 0}, {20, 0.287801},
325 {20.5039, 0}, {21.0012, 0}, {21.5041, 0}, {22, 0.271108},
326 {22.5096, 0}, {23, 0}, {23.5068, 0}, {24.0055, 0.254674},
327 {24.5039, 0}, {25.0012, 0}, {25.5041, 0}, {26, 0.237545},
328 {26.5041, 0}, {27, 0}, {27.5041, 0}, {28, 0.221542},
329 {28.5094, 0}, {29.0066, 0}, {29.5041, 0}, {30.0027, 0.204903},
330 {30.5041, 0}, {31, 0}, {31.5041, 0}, {32, 0.189248},
331 {32.5039, 0}, {33.0012, 0}, {33.5096, 0}, {34, 0.173405},
332 {34.5068, 0}, {35.0055, 0}, {35.5041, 0}, {36.0027, 0.158597},
333 {36.5039, 0}, {37.0012, 0}, {37.5041, 0}, {38, 0.144585},
334 {38.5041, 0}, {39, 0}, {39.5096, 0}, {40, 0.129709},
335 {40.5066, 0}, {41.0039, 0}, {41.5041, 0}, {42, 0.115654},
336 {42.5041, 0}, {43, 0}, {43.5041, 0}, {44, 0.101223},
337 {44.5039, 0}, {45.0012, 0}, {45.5068, 0}, {46.0055, 0.0882498},
338 {46.5041, 0}, {47.0027, 0}, {47.5041, 0}, {48, 0.0751091},
339 {48.5039, 0}, {49.0012, 0}, {49.5041, 0}, {50, 0.0619377},
340 {50.5096, 0}, {51, 0}, {51.5068, 0}, {52.0055, 0.0496666},
341 {52.5039, 0}, {53.0012, 0}, {53.5041, 0}, {54, 0.0373868},
342 {54.5041, 0}, {55, 0}, {55.5041, 0}, {56, 0.0249966},
343 {56.5094, 0}, {57.0066, 0}, {57.5041, 0}, {58.0027, 0.0131594},
344 {58.5041, 0}, {59, 0}, {59.5041, 0}, {60, 0.00169942},
345 {60.5039, 0}, {61.0012, 0}}},
346 {
"Physical Settled Amortising Swaption EUR 10y10y",
361 {{0.509357, 0.0465975}, {1.00662, 0.046597}, {1.50411, 0.0465705},
362 {2.00274, 0.0465701}, {2.50411, 0.0465922}, {3, 0.0465888},
363 {3.50411, 0.0465547}, {4, 0.0465135}, {4.50389, 0.0464943},
364 {5.00116, 0.0465701}, {5.50959, 0.0464974}, {6, 0.0464543},
365 {6.50685, 0.0463007}, {7.00548, 0.0462769}, {7.50411, 0.0464078},
366 {8.00274, 0.0464715}, {8.50389, 0.0464315}, {9.00116, 0.0464997},
367 {9.50411, 0.0467324}, {10, 0.0466733}, {10.5041, 0.0465448},
368 {11, 0.0389981}, {11.5096, 0.0380827}, {12, 0.0312491},
369 {12.5066, 0.0304138}, {13.0039, 0.0243758}, {13.5041, 0.0237934},
370 {14, 0.0183401}, {14.5041, 0.0177131}, {15, 0.0131241},
371 {15.5041, 0.0125303}, {16, 0.00865102}, {16.5039, 0.00818706},
372 {17.0012, 0.00505281}, {17.5068, 0.00468286}, {18.0055, 0.00240449},
373 {18.5041, 0.00216216}, {19.0027, 0.000691815}, {19.5041, 0.00058673},
374 {20, 1.52066e-05}, {20.5039, 0}, {21.0012, 0}}}};
376BOOST_FIXTURE_TEST_SUITE(OreAmcTestSuite, ore::test::TopLevelFixture)
378BOOST_FIXTURE_TEST_SUITE(AmcBermudanSwaptionTest, TestData)
383 const bool outputResults =
false;
389 const bool useCachedResults =
true;
391 BOOST_TEST_MESSAGE(
"Testing Bermudan swaption exposure profile");
395 std::vector<Period> tenorGrid;
397 if (!testCase.fineGrid) {
399 for (Size i = 0; i < 2 * testCase.simYears; ++i) {
400 tenorGrid.push_back(((i + 1) * 6) * Months);
404 for (Size i = 0; i < 12 * testCase.simYears; ++i) {
405 tenorGrid.push_back(((i + 1)) * Months);
410 if (testCase.inBaseCcy)
413 cal = JointCalendar(UnitedStates(UnitedStates::Settlement), UnitedKingdom());
415 QuantLib::ext::shared_ptr<DateGrid> grid = QuantLib::ext::make_shared<DateGrid>(tenorGrid, cal, ActualActual(ActualActual::ISDA));
418 QuantLib::ext::shared_ptr<QuantExt::CrossAssetModel> model = ccLgm;
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);
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());
435 simMarketConfig->setFxCcyPairs(tmp);
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});
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);
451 auto simMarket = QuantLib::ext::make_shared<ScenarioSimMarket>(market, simMarketConfig);
452 simMarket->scenarioGenerator() = sg;
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,
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) {
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,
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,
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());
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());
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());
516 QuantLib::ext::shared_ptr<PricingEngine> underlyingEngine = QuantLib::ext::make_shared<QuantLib::DiscountingSwapEngine>(
517 testCase.inBaseCcy ? simMarket->discountCurve(
"EUR") : simMarket->discountCurve(
"USD"));
519 underlying->setPricingEngine(underlyingEngine);
521 underlyingNs->setPricingEngine(underlyingEngine);
523 vanillaswap->setPricingEngine(underlyingEngine);
524 vanillaswapshort->setPricingEngine(underlyingEngine);
527 vanillaswapNs->setPricingEngine(underlyingEngine);
528 vanillaswapshortNs->setPricingEngine(underlyingEngine);
532 std::vector<Date> fixingDates;
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());
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());
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());
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());
556 std::vector<Date> exerciseDates;
557 for (Size i = 0; i < testCase.numExercises; ++i) {
558 if (!testCase.fineGrid)
560 exerciseDates.push_back(grid->dates()[19 + 2 * i]);
563 exerciseDates.push_back(grid->dates()[119 + 12 * i]);
566 QuantLib::ext::shared_ptr<QuantLib::Instrument> tmpUnd;
567 if (testCase.isAmortising)
568 tmpUnd = underlyingNs;
571 std::vector<QuantLib::ext::shared_ptr<QuantLib::Instrument>> undInst(exerciseDates.size(), tmpUnd);
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);
581 swaption = QuantLib::ext::make_shared<Swaption>(underlying, exercise, settlementType, settlementMethod);
583 QuantLib::ext::shared_ptr<IrLgm1fParametrization> param;
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);
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);
601 param->shift() = -param->H(testCase.horizonShift);
603 QuantLib::ext::static_pointer_cast<IrLgm1fParametrization>(lgm_eur->parametrization())->shift() =
604 -QuantLib::ext::static_pointer_cast<IrLgm1fParametrization>(lgm_eur->parametrization())->H(testCase.horizonShift);
606 QuantLib::ext::static_pointer_cast<IrLgm1fParametrization>(lgm_usd->parametrization())->shift() =
607 -QuantLib::ext::static_pointer_cast<IrLgm1fParametrization>(lgm_usd->parametrization())->H(testCase.horizonShift);
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);
616 engineGrid = QuantLib::ext::make_shared<NumericLgmSwaptionEngine>(bermmodel, Real(testCase.sx), testCase.nx,
617 Real(testCase.sx), testCase.nx);
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>(
625 testCase.trainingPaths, 0, 4711, 4712, 6, LsmBasisSystem::Monomial, SobolBrownianGenerator::Steps,
626 SobolRsg::JoeKuoD7, Handle<YieldTermStructure>(), grid->dates(), externalModelIndices);
627 swaption->setPricingEngine(engineMc);
629 engineMc = QuantLib::ext::make_shared<McLgmSwaptionEngine>(
631 testCase.trainingPaths, 0, 4711, 4712, 6, LsmBasisSystem::Monomial, SobolBrownianGenerator::Steps,
632 SobolRsg::JoeKuoD7, Handle<YieldTermStructure>(), grid->dates(), externalModelIndices);
633 swaption->setPricingEngine(engineMc);
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());
643 std::vector<Real> swaption_epe_grid(grid->dates().size(), 0.0);
644 std::vector<Real> swaption_epe_amc(grid->dates().size(), 0.0);
647 swaption->setPricingEngine(engineMc);
648 class TestTrade :
public Trade {
650 TestTrade(
const string& tradeType,
const string& curr,
const QuantLib::ext::shared_ptr<InstrumentWrapper>& inst)
655 void build(
const QuantLib::ext::shared_ptr<EngineFactory>&)
override {}
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);
669 Real amcTime = timer.elapsed().wall * 1e-9;
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);
679 if (!testCase.inBaseCcy)
680 fx = simMarket->fxRate(
"USDEUR")->value();
682 Real amcNPV = outputCube->getT0(0, 0) / fx;
685 swaption->setPricingEngine(engineGrid);
686 Real gridNPV = swaption->NPV();
688 Real gridTime0 = timer.elapsed().wall * 1e-9;
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);
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);
701 Real updateTime = 0.0;
703 BOOST_TEST_MESSAGE(
"running " << testCase.samples <<
" samples simulation over " << grid->dates().size()
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) {
709 BOOST_TEST_MESSAGE(
"Sample " << i);
710 Size idx = 0, fixIdx = 0;
711 Size gridCnt = testCase.gridEvalEachNth;
712 for (Date date : grid->dates()) {
715 simMarket->update(date);
717 Real v = index->fixing(date);
718 while (fixIdx < fixingDates.size() && fixingDates[fixIdx] <= date) {
719 index->addFixing(fixingDates[fixIdx], v);
727 underlying->update();
729 underlyingNs->update();
731 vanillaswap->update();
732 vanillaswapshort->update();
735 vanillaswapNs->update();
736 vanillaswapshortNs->update();
739 updateTime += timer.elapsed().wall * 1e-9;
740 Real numeraire = simMarket->numeraire();
742 if (!testCase.inBaseCcy)
743 fx = simMarket->fxRate(
"USDEUR")->value();
745 if (--gridCnt == 0) {
747 swaption_epe_grid[idx] += std::max(wrapperGrid->NPV() * fx, 0.0) / numeraire;
749 gridTime += timer.elapsed().wall * 1e-9;
750 gridCnt = testCase.gridEvalEachNth;
754 wrapperGrid->reset();
755 index->clearFixings();
757 BOOST_TEST_MESSAGE(
"Simulation time, grid " << gridTime <<
", updates " << updateTime);
762 std::clog <<
"time swaption_epe_grid swaption_epe_amc" << std::endl;
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;
771 if (useCachedResults) {
773 std::clog << t <<
" " << swaption_epe_grid[i] <<
" " << swaption_epe_amc[i] <<
" " << std::endl;
776 std::clog <<
"{" << t <<
", " << swaption_epe_grid[i] << std::endl;
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);
787 maxSwaptionErr = std::max(maxSwaptionErr, std::abs(swaption_epe_grid[i] - swaption_epe_amc[i]));
788 gridCnt = testCase.gridEvalEachNth;
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);
797BOOST_AUTO_TEST_SUITE_END()
799BOOST_AUTO_TEST_SUITE_END()
BOOST_DATA_TEST_CASE(testBermudanSwaptionExposure, boost::unit_test::data::make(testCaseData), testCase)
std::ostream & operator<<(std::ostream &os, const TestCase &testCase)
void buildCube(const QuantLib::ext::shared_ptr< ore::data::Portfolio > &portfolio, QuantLib::ext::shared_ptr< ore::analytics::NPVCube > &outputCube)
build cube in single threaded run
Build a ScenarioGenerator.
QuantLib::ext::shared_ptr< ScenarioGenerator > build(QuantLib::ext::shared_ptr< QuantExt::CrossAssetModel > model, QuantLib::ext::shared_ptr< ScenarioFactory > sf, QuantLib::ext::shared_ptr< ScenarioSimMarketParameters > marketConfig, Date asof, QuantLib::ext::shared_ptr< ore::data::Market > initMarket, const std::string &configuration=ore::data::Market::defaultConfiguration, const QuantLib::ext::shared_ptr< PathGeneratorFactory > &pf=QuantLib::ext::make_shared< MultiPathGeneratorFactory >())
Build function.
Scenario Generator description.
ScenarioSimMarket description.
void addCorrelation(const std::string &factor1, const std::string &factor2, QuantLib::Real correlation)
const std::map< CorrelationKey, QuantLib::Handle< QuantLib::Quote > > & correlations()
virtual void build(const QuantLib::ext::shared_ptr< EngineFactory > &)=0
OREAnalytics Top level fixture.
Scenario generation using cross asset model paths.
A cube implementation that stores the cube in memory.
Scenario generation using LGM paths.
MersenneTwisterAntithetic
Size size(const ValueType &v)
Singleton class to hold global Observation Mode.
Fixture that can be used at top level of OREAnalytics test suites.
Build a scenariogenerator.
A Market class that can be updated by Scenarios.
factory classes for simple scenarios