241 {
242 BOOST_TEST_MESSAGE("Testing CMS Digital CMS Spread coupon...");
243
244
245 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>();
246 Settings::instance().evaluationDate() = market->asofDate();
247 CommonVars vars;
248
249
250 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
251 engineData->model("CMS") = "LinearTSR";
252 engineData->engine("CMS") = "LinearTSRPricer";
253
254 map<string, string> engineparams1;
255 engineparams1["MeanReversion"] = "0.0";
256 engineparams1["Policy"] = "RateBound";
257 engineparams1["LowerRateBoundLogNormal"] = "0.0001";
258 engineparams1["UpperRateBoundLogNormal"] = "2";
259 engineparams1["LowerRateBoundNormal"] = "-2";
260 engineparams1["UpperRateBoundNormal"] = "2";
261 engineparams1["VegaRatio"] = "0.01";
262 engineparams1["PriceThreshold"] = "0.0000001";
263 engineparams1["BsStdDev"] = "3";
264 engineData->engineParameters("CMS") = engineparams1;
265
266 engineData->model("CMSSpread") = "BrigoMercurio";
267 engineData->engine("CMSSpread") = "Analytic";
268 map<string, string> engineparams2;
269 engineparams2["IntegrationPoints"] = "16";
270 engineData->engineParameters("CMSSpread") = engineparams2;
271 engineData->model("Swap") = "DiscountedCashflows";
272 engineData->engine("Swap") = "DiscountingSwapEngineOptimised";
273
274 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
275
276
277
278
279
280 {
281 double strike = 1.0;
282 double pay = 0.0001;
283 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapCall =
284 vars.makeDigitalCmsSpreadOption(true, vector<double>(1, strike), vector<double>(1, pay));
285 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapPut =
286 vars.makeDigitalCmsSpreadOption(false, vector<double>(1, strike), vector<double>(1, pay));
287 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadOption(vector<double>(1, pay));
288 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadOption(vector<double>(1, 0.0));
289 cmsDigitalSwapCall->build(engineFactory);
290 cmsDigitalSwapPut->build(engineFactory);
291 cmsSwap1->build(engineFactory);
292 cmsSwap2->build(engineFactory);
293
294 BOOST_TEST_MESSAGE("digital call coupons");
295 outputCoupons(cmsDigitalSwapCall);
296 BOOST_TEST_MESSAGE("digital put coupons");
297 outputCoupons(cmsDigitalSwapPut);
298 BOOST_TEST_MESSAGE("coupon 1");
299 outputCoupons(cmsSwap1);
300 BOOST_TEST_MESSAGE("coupon 2");
301 outputCoupons(cmsSwap2);
302
303 BOOST_TEST_MESSAGE("NPV Call = " << cmsDigitalSwapCall->instrument()->NPV());
304 BOOST_TEST_MESSAGE("NPV Put = " << cmsDigitalSwapPut->instrument()->NPV());
305 BOOST_TEST_MESSAGE("NPV1 = " << cmsSwap1->instrument()->NPV());
306 BOOST_TEST_MESSAGE("NPV2 = " << cmsSwap2->instrument()->NPV());
307
308 BOOST_CHECK_CLOSE(cmsDigitalSwapCall->instrument()->NPV(), cmsSwap2->instrument()->NPV(), 0.1);
309 BOOST_CHECK_CLOSE(cmsDigitalSwapPut->instrument()->NPV(), cmsSwap1->instrument()->NPV(), 0.1);
310 }
311
312
313 {
314 double strike = 0.0001;
315 double pay = 0.0001;
316 double eps = 1e-4;
317 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapPut =
318 vars.makeDigitalCmsSpreadOption(false, vector<double>(1, strike), vector<double>(1, pay));
319 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadFloor(vector<double>(1, strike + eps / 2));
320 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadFloor(vector<double>(1, strike - eps / 2));
321 cmsDigitalSwapPut->build(engineFactory);
322 cmsSwap1->build(engineFactory);
323 cmsSwap2->build(engineFactory);
324
325 Leg leg = cmsDigitalSwapPut->legs().at(0);
326 Leg leg1 = cmsSwap1->legs().at(0);
327 Leg leg2 = cmsSwap2->legs().at(0);
328
329 for (Size i = 0; i < leg.size(); i++) {
330 QuantLib::ext::shared_ptr<DigitalCoupon> dc = QuantLib::ext::dynamic_pointer_cast<DigitalCoupon>(leg[i]);
331 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc1 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1[i]);
332 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc2 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2[i]);
333
334 double r = pay * (frc1->rate() - frc2->rate()) / eps;
335
336 BOOST_CHECK_CLOSE(r, dc->putOptionRate(), 0.1);
337 }
338 }
339
340
341 {
342 double strike = 0.0001;
343 double pay = 0.0001;
344 double eps = 1e-4;
345 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapCall =
346 vars.makeDigitalCmsSpreadOption(true, vector<double>(1, strike), vector<double>(1, pay));
347 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadCap(vector<double>(1, strike + eps / 2));
348 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadCap(vector<double>(1, strike - eps / 2));
349 cmsDigitalSwapCall->build(engineFactory);
350 cmsSwap1->build(engineFactory);
351 cmsSwap2->build(engineFactory);
352
353 Leg leg = cmsDigitalSwapCall->legs().at(0);
354 Leg leg1 = cmsSwap1->legs().at(0);
355 Leg leg2 = cmsSwap2->legs().at(0);
356
357 for (Size i = 0; i < leg.size(); i++) {
358 QuantLib::ext::shared_ptr<DigitalCoupon> dc = QuantLib::ext::dynamic_pointer_cast<DigitalCoupon>(leg[i]);
359 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc1 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1[i]);
360 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc2 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2[i]);
361
362 double r = pay * (frc1->rate() - frc2->rate()) / eps;
363
364 BOOST_CHECK_CLOSE(r, dc->callOptionRate(), 0.1);
365 }
366 }
367
368 {
369 double strike = 0.0001;
370 double eps = 1e-4;
371 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapPut =
372 vars.makeDigitalCmsSpreadOption(false, vector<double>(1, strike), vector<double>());
373 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadFloor(vector<double>(1, strike + eps / 2));
374 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadFloor(vector<double>(1, strike - eps / 2));
375 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap3 = vars.makeCmsSpreadFloor(vector<double>(1, strike));
376 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap4 = vars.makeCmsSpreadFloor(vector<double>());
377 cmsDigitalSwapPut->build(engineFactory);
378 cmsSwap1->build(engineFactory);
379 cmsSwap2->build(engineFactory);
380 cmsSwap3->build(engineFactory);
381 cmsSwap4->build(engineFactory);
382
383 Leg leg = cmsDigitalSwapPut->legs().at(0);
384 Leg leg1 = cmsSwap1->legs().at(0);
385 Leg leg2 = cmsSwap2->legs().at(0);
386 Leg leg3 = cmsSwap3->legs().at(0);
387 Leg leg4 = cmsSwap4->legs().at(0);
388
389 for (Size i = 0; i < leg.size(); i++) {
390 QuantLib::ext::shared_ptr<DigitalCoupon> dc = QuantLib::ext::dynamic_pointer_cast<DigitalCoupon>(leg[i]);
391 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc1 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1[i]);
392 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc2 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2[i]);
393 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc3 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg3[i]);
394 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc4 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg4[i]);
395
396 double r = strike * (frc1->rate() - frc2->rate()) / eps;
397 double put = -frc4->rate() + frc3->rate();
398 BOOST_TEST_MESSAGE(frc4->rate() << " " << frc3->rate() << " " << r << " " << put);
399
400 BOOST_CHECK_CLOSE(r - put, dc->putOptionRate(), 0.1);
401 }
402 }
403
404
405 {
406 double strike = 0.0001;
407 double eps = 1e-4;
408 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapCall =
409 vars.makeDigitalCmsSpreadOption(true, vector<double>(1, strike), vector<double>());
410 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadCap(vector<double>(1, strike + eps / 2));
411 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadCap(vector<double>(1, strike - eps / 2));
412 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap3 = vars.makeCmsSpreadCap(vector<double>(1, strike));
413 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap4 = vars.makeCmsSpreadCap(vector<double>());
414 cmsDigitalSwapCall->build(engineFactory);
415 cmsSwap1->build(engineFactory);
416 cmsSwap2->build(engineFactory);
417 cmsSwap3->build(engineFactory);
418 cmsSwap4->build(engineFactory);
419
420 Leg leg = cmsDigitalSwapCall->legs().at(0);
421 Leg leg1 = cmsSwap1->legs().at(0);
422 Leg leg2 = cmsSwap2->legs().at(0);
423 Leg leg3 = cmsSwap3->legs().at(0);
424 Leg leg4 = cmsSwap4->legs().at(0);
425
426 for (Size i = 0; i < leg.size(); i++) {
427 QuantLib::ext::shared_ptr<DigitalCoupon> dc = QuantLib::ext::dynamic_pointer_cast<DigitalCoupon>(leg[i]);
428 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc1 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1[i]);
429 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc2 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2[i]);
430 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc3 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg3[i]);
431 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc4 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg4[i]);
432
433 double r = strike * (frc1->rate() - frc2->rate()) / eps;
434 double call = frc4->rate() - frc3->rate();
435
436 BOOST_CHECK_CLOSE(r + call, dc->callOptionRate(), 0.1);
437 }
438 }
439}