354 {
355 BOOST_TEST_MESSAGE("Testing CMS CapFloor price...");
356
357
358 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>();
359 Settings::instance().evaluationDate() = market->asofDate();
360
361 CommonVars vars;
362 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
363 engineData->model("CMS") = "Hagan";
364 engineData->engine("CMS") = "Analytic";
365 map<string, string> engineparams;
366 engineparams["YieldCurveModel"] = "Standard";
367 engineparams["MeanReversion"] = "0.0";
368 engineData->engineParameters("CMS") = engineparams;
369
370 engineData->model("Swap") = "DiscountedCashflows";
371 engineData->engine("Swap") = "DiscountingSwapEngineOptimised";
372
373 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
374
375 BOOST_TEST_MESSAGE(
376 "Comparing CMS Cap price to replication by a Single Legged CMS Swap and a Single Leg Capped CMS Swap...");
377 vector<double> capRate(1, 0.021);
378 QuantLib::ext::shared_ptr<ore::data::Swap> cmsLegSwap = vars.makeCmsLegSwap();
379 QuantLib::ext::shared_ptr<ore::data::Swap> cappedCmsLegSwap = vars.makeCappedCmsLegSwap(capRate);
380 QuantLib::ext::shared_ptr<ore::data::CapFloor> cap = vars.makeCap(capRate);
381
382 cmsLegSwap->build(engineFactory);
383 cappedCmsLegSwap->build(engineFactory);
384 cap->build(engineFactory);
385
386 Real cmsLegNpv = cmsLegSwap->instrument()->NPV();
387 Real cappedCmsLegNpv = cappedCmsLegSwap->instrument()->NPV();
388 Real capNpv = cap->instrument()->NPV();
389
390 Real capBySwaps = cmsLegNpv - cappedCmsLegNpv;
391
392 BOOST_TEST_MESSAGE("CMS Leg swap NPV is " << cmsLegNpv);
393 BOOST_TEST_MESSAGE("CMS Capped Leg swap NPV is " << cappedCmsLegNpv);
394 BOOST_TEST_MESSAGE("CMS Cap NPV is " << capNpv);
395 BOOST_TEST_MESSAGE("CMS Cap NPV from Swap replication is " << capBySwaps);
396 BOOST_CHECK_CLOSE(capNpv, capBySwaps, 1.0);
397
398 BOOST_TEST_MESSAGE("Checking CMS Cap with high Cap is zero...");
399 vector<double> capHigh(1, 1.0);
400
401 cap = vars.makeCap(capHigh);
402 cap->build(engineFactory);
403 capNpv = cap->instrument()->NPV();
404 BOOST_TEST_MESSAGE("CMS Cap (Cap of 100%) NPV is " << capNpv);
405 BOOST_CHECK_SMALL(capNpv, 0.01);
406
407 BOOST_TEST_MESSAGE("Checking CMS Cap with low Cap is equal to single leg swap...");
408 vector<double> capLow(1, -1.0);
409
410 cap = vars.makeCap(capLow);
411 cap->build(engineFactory);
412 capNpv = cap->instrument()->NPV();
413 BOOST_TEST_MESSAGE("CMS Cap (Cap of -100%) NPV is " << capNpv);
414 BOOST_CHECK_CLOSE(capNpv, cmsLegNpv, 1.0);
415
416 BOOST_TEST_MESSAGE("Checking CMS Floor with low Cap is equal to zero...");
417 vector<double> floorLow(1, -1.0);
418
419 QuantLib::ext::shared_ptr<ore::data::CapFloor> floor = vars.makeFloor(floorLow);
420 floor->build(engineFactory);
421 Real floorNpv = floor->instrument()->NPV();
422 BOOST_TEST_MESSAGE("CMS Floor (Floor of -100%) NPV is " << floorNpv);
423 BOOST_CHECK_SMALL(floorNpv, 0.01);
424
425 BOOST_TEST_MESSAGE("Checking CMS Cap + CMS Floor = Swap...");
426 vector<double> floorRate(1, 0.021);
427
428 cap = vars.makeCap(capRate);
429 floor = vars.makeFloor(floorRate);
430 QuantLib::ext::shared_ptr<ore::data::Swap> swap = vars.makeSwap(0.021, "6M");
431 cap->build(engineFactory);
432 floor->build(engineFactory);
433 swap->build(engineFactory);
434 capNpv = cap->instrument()->NPV();
435 floorNpv = floor->instrument()->NPV();
436 Real swapNpv = swap->instrument()->NPV();
437 Real capFloorNpv = capNpv - floorNpv;
438 BOOST_TEST_MESSAGE("CMS Cap NPV is " << capNpv);
439 BOOST_TEST_MESSAGE("CMS Floor NPV is " << floorNpv);
440 BOOST_TEST_MESSAGE("CMS Cap + Floor NPV is " << capFloorNpv);
441 BOOST_TEST_MESSAGE("CMS Swap NPV is " << swapNpv);
442 BOOST_CHECK_CLOSE(capFloorNpv, swapNpv, 1.0);
443}