Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions
commodityspreadoption.cpp File Reference
#include "toplevelfixture.hpp"
#include <boost/test/unit_test.hpp>
#include <ql/currencies/america.hpp>
#include <ql/math/interpolations/linearinterpolation.hpp>
#include <ql/math/matrix.hpp>
#include <ql/pricingengines/blackformula.hpp>
#include <ql/settings.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/nullcalendar.hpp>
#include <qle/cashflows/commodityindexedcashflow.hpp>
#include <qle/instruments/commodityspreadoption.hpp>
#include <qle/pricingengines/commodityspreadoptionengine.hpp>
#include <qle/termstructures/pricecurve.hpp>
#include <qle/time/futureexpirycalculator.hpp>
#include <qle/termstructures/flatcorrelation.hpp>

Go to the source code of this file.

Functions

 BOOST_AUTO_TEST_CASE (testCrossAssetFutureSpread)
 
 BOOST_AUTO_TEST_CASE (testCalendarSpread)
 
 BOOST_AUTO_TEST_CASE (testCalendarSpread2)
 
 BOOST_AUTO_TEST_CASE (testCalendarSpreadEdgeCase)
 
 BOOST_AUTO_TEST_CASE (testSpotAveragingSpreadOption)
 
 BOOST_AUTO_TEST_CASE (testSeasonedSpotAveragingSpreadOption)
 
 BOOST_AUTO_TEST_CASE (testFutureAveragingSpreadOption)
 

Function Documentation

◆ BOOST_AUTO_TEST_CASE() [1/7]

BOOST_AUTO_TEST_CASE ( testCrossAssetFutureSpread  )

Definition at line 276 of file commodityspreadoption.cpp.

276 {
277 Date today(5, Nov, 2022);
278 Settings::instance().evaluationDate() = today;
279
280 double strike = 1;
281 double volBrentQuote = 0.3;
282 double volWTIQuote = 0.35;
283 double quantity = 1000.;
284 double WTIspot = 100.;
285 double WTINov = 104.;
286 double WTIDec = 105.;
287 double brentSpot = 101;
288 double brentNov = 103;
289 double brentDec = 106;
290
291 Date novExpiry(30, Nov, 2022);
292 Date decExpiry(31, Dec, 2022);
293 Date exerciseDate(31, Dec, 2022);
294
295 std::vector<Date> futureExpiryDates = {today, novExpiry, decExpiry};
296 std::vector<Real> brentQuotes = {brentSpot, brentNov, brentDec};
297 std::vector<Real> wtiQuotes = {WTIspot, WTINov, WTIDec};
298
299 auto brentCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
300 today, futureExpiryDates, brentQuotes, Actual365Fixed(), USDCurrency()));
301 auto wtiCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
302 today, futureExpiryDates, wtiQuotes, Actual365Fixed(), USDCurrency()));
303
304 auto discount = Handle<YieldTermStructure>(
305 QuantLib::ext::make_shared<FlatForward>(today, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.03)), Actual365Fixed()));
306
307 auto brentVol = Handle<BlackVolTermStructure>(
308 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volBrentQuote, Actual365Fixed()));
309 auto wtiVol = Handle<BlackVolTermStructure>(
310 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volWTIQuote, Actual365Fixed()));
311
312 auto index1 = QuantLib::ext::make_shared<CommodityFuturesIndex>("BRENT_USD", decExpiry, NullCalendar(), brentCurve);
313
314 auto index2 = QuantLib::ext::make_shared<CommodityFuturesIndex>("WTI_USD", decExpiry, NullCalendar(), wtiCurve);
315
316 auto flow1 = QuantLib::ext::make_shared<CommodityIndexedCashFlow>(100, decExpiry, decExpiry, index1);
317
318 auto flow2 = QuantLib::ext::make_shared<CommodityIndexedCashFlow>(100, decExpiry, decExpiry, index2);
319
320 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(exerciseDate);
321
322 CommoditySpreadOption spreadOption(flow1, flow2, exercise, quantity, strike, Option::Call);
323
324 for (const auto& rho : {-0.95, -0.5, -0.25, 0., 0.5, 0.75, 0.9, 0.95}) {
325 Handle<CorrelationTermStructure> corr = Handle<CorrelationTermStructure>(ext::make_shared<FlatCorrelation>(0, NullCalendar(), rho, Actual365Fixed()));
326 auto engine = QuantLib::ext::make_shared<CommoditySpreadOptionAnalyticalEngine>(discount, brentVol, wtiVol, corr);
327 spreadOption.setPricingEngine(engine);
328 double npvMC = monteCarloPricing(brentDec, WTIDec, volBrentQuote, volWTIQuote, rho,
329 discount->timeFromReference(exercise->lastDate()),
330 discount->discount(exercise->lastDate()), strike) *
331 quantity;
332 double npvKrik = spreadOption.NPV();
333 BOOST_CHECK_CLOSE(npvKrik, npvMC, 1.);
334 }
335}
Interpolated price curve.
Definition: pricecurve.hpp:50

◆ BOOST_AUTO_TEST_CASE() [2/7]

BOOST_AUTO_TEST_CASE ( testCalendarSpread  )

Definition at line 337 of file commodityspreadoption.cpp.

337 {
338 Date today(5, Nov, 2022);
339 Settings::instance().evaluationDate() = today;
340
341 double strike = 1;
342 double volBrent = 0.3;
343 double rho = 0.9;
344 double quantity = 1000.;
345 double spot = 100.;
346 double futureNov = 104.;
347 Date futureNovExpiry(30, Nov, 2022);
348 double futureDec = 105.;
349 Date futureDecExpiry(31, Dec, 2022);
350 Date exerciseDate(15, Nov, 2022);
351 Date paymentDate(17, Nov, 2022);
352
353 std::vector<Date> futureExpiryDates = {today, futureNovExpiry, futureDecExpiry};
354 std::vector<Real> brentQuotes = {spot, futureNov, futureDec};
355
356 auto brentCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
357 today, futureExpiryDates, brentQuotes, Actual365Fixed(), USDCurrency()));
358
359 auto discount = Handle<YieldTermStructure>(
360 QuantLib::ext::make_shared<FlatForward>(today, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.03)), Actual365Fixed()));
361
362 auto vol1 = Handle<BlackVolTermStructure>(
363 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volBrent, Actual365Fixed()));
364
365 auto index1 =
366 QuantLib::ext::make_shared<CommodityFuturesIndex>("BRENT_DEC_USD", futureDecExpiry, NullCalendar(), brentCurve);
367
368 auto index2 =
369 QuantLib::ext::make_shared<CommodityFuturesIndex>("BRENT_NOV_USD", futureNovExpiry, NullCalendar(), brentCurve);
370
371 auto flow1 = QuantLib::ext::make_shared<CommodityIndexedCashFlow>(100, futureDecExpiry, Date(31, Dec, 2022), index1);
372
373 auto flow2 = QuantLib::ext::make_shared<CommodityIndexedCashFlow>(100, futureNovExpiry, Date(30, Nov, 2022), index2);
374
375 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(exerciseDate);
376
377 CommoditySpreadOption spreadOption(flow1, flow2, exercise, quantity, strike, Option::Call, paymentDate);
378
379 Handle<CorrelationTermStructure> corr =
380 Handle<CorrelationTermStructure>(ext::make_shared<FlatCorrelation>(0, NullCalendar(), rho, Actual365Fixed()));
381
382 auto engine = QuantLib::ext::make_shared<CommoditySpreadOptionAnalyticalEngine>(discount, vol1, vol1, corr);
383
384 spreadOption.setPricingEngine(engine);
385
386 double kirkNpv = spreadOption.NPV();
387 double mcNpv = quantity * monteCarloPricing(futureDec, futureNov, volBrent, volBrent, rho,
388 discount->timeFromReference(exercise->lastDate()),
389 discount->discount(paymentDate), strike);
390
391 BOOST_CHECK_CLOSE(kirkNpv, mcNpv, 1);
392}

◆ BOOST_AUTO_TEST_CASE() [3/7]

BOOST_AUTO_TEST_CASE ( testCalendarSpread2  )

Definition at line 394 of file commodityspreadoption.cpp.

394 {
395 Date today(5, Nov, 2022);
396 Settings::instance().evaluationDate() = today;
397
398 double strike = 1;
399 double volBrent = 0.3;
400 double rho = 0.9;
401 double quantity = 1000.;
402 double spot = 100.;
403 double futureNov = 104.;
404 Date futureNovExpiry(30, Nov, 2022);
405 double futureDec = 105.;
406 Date futureDecExpiry(31, Dec, 2022);
407 Date exerciseDate(31, Dec, 2022);
408 Date paymentDate = exerciseDate;
409 std::vector<Date> futureExpiryDates = {today, futureNovExpiry, futureDecExpiry};
410 std::vector<Real> brentQuotes = {spot, futureNov, futureDec};
411
412 auto brentCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
413 today, futureExpiryDates, brentQuotes, Actual365Fixed(), USDCurrency()));
414
415 auto discount = Handle<YieldTermStructure>(
416 QuantLib::ext::make_shared<FlatForward>(today, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.03)), Actual365Fixed()));
417
418 auto vol1 = Handle<BlackVolTermStructure>(
419 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volBrent, Actual365Fixed()));
420
421 auto index1 =
422 QuantLib::ext::make_shared<CommodityFuturesIndex>("BRENT_DEC_USD", futureDecExpiry, NullCalendar(), brentCurve);
423
424 auto index2 =
425 QuantLib::ext::make_shared<CommodityFuturesIndex>("BRENT_NOV_USD", futureNovExpiry, NullCalendar(), brentCurve);
426
427 auto flow1 = QuantLib::ext::make_shared<CommodityIndexedCashFlow>(100, futureDecExpiry, Date(31, Dec, 2022), index1);
428
429 auto flow2 = QuantLib::ext::make_shared<CommodityIndexedCashFlow>(100, futureNovExpiry, Date(30, Nov, 2022), index2);
430
431 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(exerciseDate);
432
433 CommoditySpreadOption spreadOption(flow1, flow2, exercise, quantity, strike, Option::Call, paymentDate);
434
435 Handle<CorrelationTermStructure> corr =
436 Handle<CorrelationTermStructure>(ext::make_shared<FlatCorrelation>(0, NullCalendar(), rho, Actual365Fixed()));
437
438 auto engine = QuantLib::ext::make_shared<CommoditySpreadOptionAnalyticalEngine>(discount, vol1, vol1, corr);
439
440 spreadOption.setPricingEngine(engine);
441 double kirkNpv = spreadOption.NPV();
442
443 double volScalingFactor = std::min(
444 std::sqrt(discount->timeFromReference(futureNovExpiry) / discount->timeFromReference(exercise->lastDate())),
445 1.0);
446
447 double mcNpv = quantity * monteCarloPricing(futureDec, futureNov, volBrent, volBrent * volScalingFactor, rho,
448 discount->timeFromReference(paymentDate),
449 discount->discount(exercise->lastDate()), strike);
450 BOOST_CHECK_CLOSE(kirkNpv, mcNpv, 1);
451}

◆ BOOST_AUTO_TEST_CASE() [4/7]

BOOST_AUTO_TEST_CASE ( testCalendarSpreadEdgeCase  )

Definition at line 453 of file commodityspreadoption.cpp.

453 {
454 // The short asset price is already fixed
455 Date today(5, Dec, 2022);
456 Settings::instance().evaluationDate() = today;
457
458 double strike = 1;
459 double volBrent = 0.3;
460 double rho = 0.9;
461 double quantity = 1000.;
462 double spot = 100.;
463 double futureNov = 104.;
464 Date futureNovExpiry(30, Nov, 2022);
465 double futureDec = 105.;
466 Date futureDecExpiry(31, Dec, 2022);
467 Date exerciseDate(31, Dec, 2022);
468
469 std::vector<Date> futureExpiryDates = {today, futureDecExpiry};
470 std::vector<Real> brentQuotes = {spot, futureDec};
471
472 auto brentCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
473 today, futureExpiryDates, brentQuotes, Actual365Fixed(), USDCurrency()));
474
475 auto discount = Handle<YieldTermStructure>(
476 QuantLib::ext::make_shared<FlatForward>(today, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.03)), Actual365Fixed()));
477
478 auto vol1 = Handle<BlackVolTermStructure>(
479 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volBrent, Actual365Fixed()));
480
481 auto index1 =
482 QuantLib::ext::make_shared<CommodityFuturesIndex>("BRENT_DEC_USD", futureDecExpiry, NullCalendar(), brentCurve);
483
484 auto index2 =
485 QuantLib::ext::make_shared<CommodityFuturesIndex>("BRENT_NOV_USD", futureNovExpiry, NullCalendar(), brentCurve);
486
487 index2->addFixing(futureNovExpiry, futureNov);
488
489 auto flow1 = QuantLib::ext::make_shared<CommodityIndexedCashFlow>(100, futureDecExpiry, Date(31, Dec, 2022), index1);
490
491 auto flow2 = QuantLib::ext::make_shared<CommodityIndexedCashFlow>(100, futureNovExpiry, Date(30, Nov, 2022), index2);
492
493 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(exerciseDate);
494
495 CommoditySpreadOption spreadOption(flow1, flow2, exercise, quantity, strike, Option::Call, exerciseDate);
496
497 Handle<CorrelationTermStructure> corr =
498 Handle<CorrelationTermStructure>(ext::make_shared<FlatCorrelation>(0, NullCalendar(), rho, Actual365Fixed()));
499
500 auto engine = QuantLib::ext::make_shared<CommoditySpreadOptionAnalyticalEngine>(discount, vol1, vol1, corr);
501
502 spreadOption.setPricingEngine(engine);
503 double kirkNpv = spreadOption.NPV();
504
505 double bsNpv = quantity * blackFormula(QuantLib::Option::Call, strike + futureNov, futureDec,
506 std::sqrt(vol1->blackVariance(futureDecExpiry, strike + futureNov)),
507 discount->discount(exercise->lastDate()));
508
509 BOOST_CHECK_CLOSE(kirkNpv, bsNpv, 1e-8);
510}

◆ BOOST_AUTO_TEST_CASE() [5/7]

BOOST_AUTO_TEST_CASE ( testSpotAveragingSpreadOption  )

Definition at line 512 of file commodityspreadoption.cpp.

512 {
513 Date today(31, Oct, 2022);
514 Settings::instance().evaluationDate() = today;
515
516 double strike = 1;
517 double volBrentQuote = 0.3;
518 double volWTIQuote = 0.35;
519 double quantity = 1000.;
520 double WTIspot = 100.;
521 double WTINov = 104.;
522 double WTIDec = 105.;
523 double brentSpot = 101;
524 double brentNov = 103;
525 double brentDec = 106;
526
527 Date novExpiry(30, Nov, 2022);
528 Date decExpiry(31, Dec, 2022);
529 Date exerciseDate(31, Dec, 2022);
530
531 std::vector<Date> futureExpiryDates = {today, novExpiry, decExpiry};
532 std::vector<Real> brentQuotes = {brentSpot, brentNov, brentDec};
533 std::vector<Real> wtiQuotes = {WTIspot, WTINov, WTIDec};
534
535 auto brentCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
536 today, futureExpiryDates, brentQuotes, Actual365Fixed(), USDCurrency()));
537 auto wtiCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
538 today, futureExpiryDates, wtiQuotes, Actual365Fixed(), USDCurrency()));
539
540 auto discount = Handle<YieldTermStructure>(
541 QuantLib::ext::make_shared<FlatForward>(today, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.03)), Actual365Fixed()));
542
543 auto brentVol = Handle<BlackVolTermStructure>(
544 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volBrentQuote, Actual365Fixed()));
545 auto wtiVol = Handle<BlackVolTermStructure>(
546 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volWTIQuote, Actual365Fixed()));
547
548 auto index1 = QuantLib::ext::make_shared<CommoditySpotIndex>("BRENT_USD", NullCalendar(), brentCurve);
549
550 auto index2 = QuantLib::ext::make_shared<CommoditySpotIndex>("WTI_USD", NullCalendar(), wtiCurve);
551
552 auto flow1 = QuantLib::ext::make_shared<CommodityIndexedAverageCashFlow>(quantity, Date(1, Dec, 2022), Date(31, Dec, 2022),
553 Date(31, Dec, 2022), index1, NullCalendar());
554
555 auto flow2 = QuantLib::ext::make_shared<CommodityIndexedAverageCashFlow>(quantity, Date(1, Dec, 2022), Date(31, Dec, 2022),
556 Date(31, Dec, 2022), index2, NullCalendar());
557
558 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(exerciseDate);
559
560 CommoditySpreadOption spreadOption(flow1, flow2, exercise, quantity, strike, Option::Call);
561
562 Real df = discount->discount(exercise->lastDate());
563
564 for (const auto& rho : {-0.9, -0.75, -0.5, -0.25, 0., 0.25, 0.5, 0.75, 0.9}) {
565
566 Handle<CorrelationTermStructure> corr = Handle<CorrelationTermStructure>(
567 ext::make_shared<FlatCorrelation>(0, NullCalendar(), rho, Actual365Fixed()));
568 auto engine = QuantLib::ext::make_shared<CommoditySpreadOptionAnalyticalEngine>(discount, brentVol, wtiVol, corr);
569 spreadOption.setPricingEngine(engine);
570 double npvMC = quantity * monteCarloPricingSpotAveraging(flow1, *brentCurve, *brentVol, flow2, *wtiCurve,
571 *wtiVol, rho, strike, df);
572 double npvKirk = spreadOption.NPV();
573 BOOST_CHECK_CLOSE(npvKirk, npvMC, 1);
574 }
575}

◆ BOOST_AUTO_TEST_CASE() [6/7]

BOOST_AUTO_TEST_CASE ( testSeasonedSpotAveragingSpreadOption  )

Definition at line 577 of file commodityspreadoption.cpp.

577 {
578 Date today(10, Nov, 2022);
579 Settings::instance().evaluationDate() = today;
580
581 double strike = 1;
582 double volBrentQuote = 0.3;
583 double volWTIQuote = 0.35;
584 double quantity = 1000.;
585 double WTIspot = 100.;
586 double WTINov = 103.;
587 double WTIDec = 105.;
588 double brentSpot = 100;
589 double brentNov = 104;
590 double brentDec = 106;
591
592 Date novExpiry(30, Nov, 2022);
593 Date decExpiry(31, Dec, 2022);
594 Date exerciseDate(30, Nov, 2022);
595
596 std::vector<Date> futureExpiryDates = {today, novExpiry, decExpiry};
597 std::vector<Real> brentQuotes = {brentSpot, brentNov, brentDec};
598 std::vector<Real> wtiQuotes = {WTIspot, WTINov, WTIDec};
599
600 vector<Date> fixingDates;
601
602 vector<Real> fixingValuesBrent;
603 vector<Real> fixingValuesWTI;
604
605 for (int i = 1; i <= 10; ++i) {
606 fixingDates.push_back(Date(i, Nov, 2022));
607 fixingValuesBrent.push_back(100 + i / 10.);
608 fixingValuesWTI.push_back(100 - i / 10.);
609 }
610
611 auto brentCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
612 today, futureExpiryDates, brentQuotes, Actual365Fixed(), USDCurrency()));
613 auto wtiCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
614 today, futureExpiryDates, wtiQuotes, Actual365Fixed(), USDCurrency()));
615
616 auto discount = Handle<YieldTermStructure>(
617 QuantLib::ext::make_shared<FlatForward>(today, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.03)), Actual365Fixed()));
618
619 auto brentVol = Handle<BlackVolTermStructure>(
620 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volBrentQuote, Actual365Fixed()));
621 auto wtiVol = Handle<BlackVolTermStructure>(
622 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volWTIQuote, Actual365Fixed()));
623
624 auto index1 = QuantLib::ext::make_shared<CommoditySpotIndex>("BRENT_USD", NullCalendar(), brentCurve);
625
626 auto index2 = QuantLib::ext::make_shared<CommoditySpotIndex>("WTI_USD", NullCalendar(), wtiCurve);
627
628 index1->addFixings(fixingDates.begin(), fixingDates.end(), fixingValuesBrent.begin());
629 index2->addFixings(fixingDates.begin(), fixingDates.end(), fixingValuesWTI.begin());
630
631 auto flow1 = QuantLib::ext::make_shared<CommodityIndexedAverageCashFlow>(quantity, Date(1, Nov, 2022), Date(30, Nov, 2022),
632 Date(30, Nov, 2022), index1, NullCalendar());
633
634 auto flow2 = QuantLib::ext::make_shared<CommodityIndexedAverageCashFlow>(quantity, Date(1, Nov, 2022), Date(30, Nov, 2022),
635 Date(30, Nov, 2022), index2, NullCalendar());
636
637 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(exerciseDate);
638
639 Real df = discount->discount(exercise->lastDate());
640
641 for (const auto& rho : {-0.9, -0.75, -0.5, -0.25, 0., 0.25, 0.5, 0.75, 0.9}) {
642 CommoditySpreadOption spreadOption(flow1, flow2, exercise, quantity, strike, Option::Call);
643
644 Handle<CorrelationTermStructure> corr = Handle<CorrelationTermStructure>(
645 ext::make_shared<FlatCorrelation>(0, NullCalendar(), rho, Actual365Fixed()));
646 auto engine = QuantLib::ext::make_shared<CommoditySpreadOptionAnalyticalEngine>(discount, brentVol, wtiVol, corr);
647 spreadOption.setPricingEngine(engine);
648 double npvMC = quantity * monteCarloPricingSpotAveraging(flow1, *brentCurve, *brentVol, flow2, *wtiCurve,
649 *wtiVol, rho, strike, df);
650 double npvKirk = spreadOption.NPV();
651 BOOST_CHECK_CLOSE(npvKirk, npvMC, 1);
652
653 }
654
655 for (const auto& rho : {0.85}) {
656 for (const auto& strike : {0.5, 1., 1.5, 2.0, 2.5}) {
657 CommoditySpreadOption spreadOption(flow1, flow2, exercise, quantity, strike, Option::Call);
658
659 Handle<CorrelationTermStructure> corr = Handle<CorrelationTermStructure>(
660 ext::make_shared<FlatCorrelation>(0, NullCalendar(), rho, Actual365Fixed()));
661 auto engine = QuantLib::ext::make_shared<CommoditySpreadOptionAnalyticalEngine>(discount, brentVol, wtiVol, corr);
662 spreadOption.setPricingEngine(engine);
663 double npvMC = quantity * monteCarloPricingSpotAveraging(flow1, *brentCurve, *brentVol, flow2, *wtiCurve,
664 *wtiVol, rho, strike, df);
665 double npvKirk = spreadOption.NPV();
666 BOOST_CHECK_CLOSE(npvKirk, npvMC, 1);
667 }
668 }
669}

◆ BOOST_AUTO_TEST_CASE() [7/7]

BOOST_AUTO_TEST_CASE ( testFutureAveragingSpreadOption  )

Definition at line 671 of file commodityspreadoption.cpp.

671 {
672 Date today(31, Oct, 2022);
673 Settings::instance().evaluationDate() = today;
674
675 double strike = 1;
676 double volBrentQuote = 0.3;
677 double volWTIQuote = 0.35;
678 double quantity = 1000.;
679 double WTIspot = 100.;
680 double WTINov = 104.;
681 double WTIDec = 105.;
682 double brentSpot = 101;
683 double brentNov = 103;
684 double brentDec = 106;
685
686 Date novExpiry(30, Nov, 2022);
687 Date decExpiry(31, Dec, 2022);
688 Date exerciseDate(31, Dec, 2022);
689
690 std::vector<Date> futureExpiryDates = {today, novExpiry, decExpiry};
691 std::vector<Real> brentQuotes = {brentSpot, brentNov, brentDec};
692 std::vector<Real> wtiQuotes = {WTIspot, WTINov, WTIDec};
693
694 auto feCalc = ext::make_shared<MockUpExpiryCalculator>();
695
696 auto brentCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
697 today, futureExpiryDates, brentQuotes, Actual365Fixed(), USDCurrency()));
698 auto wtiCurve = Handle<PriceTermStructure>(QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(
699 today, futureExpiryDates, wtiQuotes, Actual365Fixed(), USDCurrency()));
700
701 auto discount = Handle<YieldTermStructure>(
702 QuantLib::ext::make_shared<FlatForward>(today, Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.03)), Actual365Fixed()));
703
704 auto brentVol = Handle<BlackVolTermStructure>(
705 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volBrentQuote, Actual365Fixed()));
706 auto wtiVol = Handle<BlackVolTermStructure>(
707 QuantLib::ext::make_shared<BlackConstantVol>(today, NullCalendar(), volWTIQuote, Actual365Fixed()));
708
709 auto index1 = QuantLib::ext::make_shared<CommodityFuturesIndex>("BRENT_USD", novExpiry, NullCalendar(), brentCurve);
710
711 auto index2 = QuantLib::ext::make_shared<CommodityFuturesIndex>("WTI_USD", novExpiry, NullCalendar(), wtiCurve);
712
713 auto flow1 = QuantLib::ext::make_shared<CommodityIndexedAverageCashFlow>(quantity, Date(1, Dec, 2022), Date(31, Dec, 2022),
714 Date(31, Dec, 2022), index1, NullCalendar(), 0.0,
715 1.0, true, 0, 0, feCalc);
716
717 auto flow2 = QuantLib::ext::make_shared<CommodityIndexedAverageCashFlow>(quantity, Date(1, Dec, 2022), Date(31, Dec, 2022),
718 Date(31, Dec, 2022), index2, NullCalendar(), 0.0,
719 1.0, true, 0, 0, feCalc);
720
721 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(exerciseDate);
722
723 CommoditySpreadOption spreadOption(flow1, flow2, exercise, quantity, strike, Option::Call);
724
725 Real df = discount->discount(exercise->lastDate());
726
727 for (const auto& rho : {-0.9, -0.75, -0.5, -0.25, 0., 0.25, 0.5, 0.75, 0.9}) {
728
729 Handle<CorrelationTermStructure> corr = Handle<CorrelationTermStructure>(
730 ext::make_shared<FlatCorrelation>(0, NullCalendar(), rho, Actual365Fixed()));
731 auto engine = QuantLib::ext::make_shared<CommoditySpreadOptionAnalyticalEngine>(discount, brentVol, wtiVol, corr);
732 spreadOption.setPricingEngine(engine);
733 double npvMC = quantity * monteCarloPricingFutureAveraging(flow1, *brentCurve, *brentVol, flow2, *wtiCurve,
734 *wtiVol, rho, strike, df);
735 double npvKirk = spreadOption.NPV();
736 BOOST_CHECK_CLOSE(npvKirk, npvMC, 1);
737 }
738}