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
612 today, futureExpiryDates, brentQuotes, Actual365Fixed(), USDCurrency()));
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}) {
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}) {
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}