19#include <oret/toplevelfixture.hpp>
20#include <boost/test/unit_test.hpp>
21#include <boost/timer/timer.hpp>
23#include <ql/cashflows/simplecashflow.hpp>
24#include <ql/currencies/america.hpp>
25#include <ql/exercise.hpp>
26#include <ql/math/interpolations/linearinterpolation.hpp>
27#include <ql/pricingengines/swap/discountingswapengine.hpp>
28#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
29#include <ql/termstructures/yield/flatforward.hpp>
30#include <ql/time/calendars/unitedstates.hpp>
31#include <ql/time/schedule.hpp>
41using boost::unit_test_framework::test_suite;
43BOOST_FIXTURE_TEST_SUITE(OREPlusCommodityTestSuite, ore::test::TopLevelFixture)
45BOOST_AUTO_TEST_SUITE(CommoditySwaptionTest)
49 BOOST_TEST_MESSAGE(
"Testing Averaging Commodity Swaption Analytical Approximation vs MC Pricing");
51 BOOST_TEST_MESSAGE(
"Testing Non-Averaging Commodity Swaption Analytical Approximation vs MC Pricing");
55 Date today(5, Feb, 2019);
56 Settings::instance().evaluationDate() = today;
57 Calendar cal = UnitedStates(UnitedStates::Settlement);
60 std::vector<Date> dates = {today + 1 * Years, today + 2 * Years, today + 3 * Years, today + 4 * Years,
61 today + 5 * Years, today + 7 * Years, today + 10 * Years};
62 std::vector<Real> prices = {100.0, 105.0, 110.0, 115.0, 120.0, 130.0, 150.0};
63 DayCounter dc = Actual365Fixed();
64 Handle<QuantExt::PriceTermStructure> priceCurve(
66 priceCurve->enableExtrapolation();
69 Handle<Quote> rateQuote(QuantLib::ext::make_shared<SimpleQuote>(0.01));
70 Handle<YieldTermStructure> discountCurve(QuantLib::ext::make_shared<FlatForward>(today, rateQuote, dc, Compounded, Annual));
73 Handle<QuantLib::BlackVolTermStructure> vol(QuantLib::ext::make_shared<QuantLib::BlackConstantVol>(today, cal, 0.3, dc));
77 QuantLib::ext::shared_ptr<PricingEngine> analyticalEngine =
78 QuantLib::ext::make_shared<CommoditySwaptionEngine>(discountCurve, vol, beta);
82 QuantLib::ext::shared_ptr<PricingEngine> mcEngine =
83 QuantLib::ext::make_shared<CommoditySwaptionMonteCarloEngine>(discountCurve, vol, samples, beta);
85 QuantLib::ext::shared_ptr<PricingEngine> swapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(discountCurve);
88 std::string
name =
"CL";
89 QuantLib::ext::shared_ptr<CommoditySpotIndex> index = QuantLib::ext::make_shared<CommoditySpotIndex>(
name, cal, priceCurve);
92 std::vector<Size> startTimes = {0, 1, 2, 3, 4, 5, 7, 10};
93 std::vector<Real>
strikes = {10.0, 60.0, 80.0, 100.0, 120.0, 140.0};
95 for (Size k = 0; k <
strikes.size(); ++k) {
100 for (Size i = 0; i < startTimes.size(); ++i) {
101 Period startTerm = (i == 0 ? 6 * Months : startTimes[i] * Years);
102 Date start = today + startTerm;
103 Date end = start + 1 * Years;
104 Schedule schedule = MakeSchedule().from(start).to(end).withTenor(1 * Months);
106 for (Size j = 1; j < schedule.size(); ++j)
107 fixedLeg.push_back(QuantLib::ext::make_shared<SimpleCashFlow>(quantity * strikePrice, schedule[j]));
122 QuantLib::ext::shared_ptr<QuantLib::Swap> payerSwap = QuantLib::ext::make_shared<QuantLib::Swap>(fixedLeg, floatLeg);
123 QuantLib::ext::shared_ptr<QuantLib::Swap> receiverSwap = QuantLib::ext::make_shared<QuantLib::Swap>(floatLeg, fixedLeg);
125 payerSwap->setPricingEngine(swapEngine);
126 receiverSwap->setPricingEngine(swapEngine);
127 BOOST_TEST_MESSAGE(
"Testing Swap NPV " << payerSwap->NPV() <<
" " << receiverSwap->NPV());
129 QuantLib::ext::shared_ptr<EuropeanExercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(start);
130 QuantLib::ext::shared_ptr<QuantExt::GenericSwaption> payerSwaption =
131 QuantLib::ext::make_shared<QuantExt::GenericSwaption>(payerSwap, exercise);
132 QuantLib::ext::shared_ptr<QuantExt::GenericSwaption> receiverSwaption =
133 QuantLib::ext::make_shared<QuantExt::GenericSwaption>(receiverSwap, exercise);
135 boost::timer::cpu_timer tan;
136 payerSwaption->setPricingEngine(analyticalEngine);
137 receiverSwaption->setPricingEngine(analyticalEngine);
138 Real anPayerPrice = payerSwaption->NPV();
139 Real anReceiverPrice = receiverSwaption->NPV();
140 Real anTime = tan.elapsed().wall * 1e-6;
142 boost::timer::cpu_timer tmc;
143 payerSwaption->setPricingEngine(mcEngine);
144 receiverSwaption->setPricingEngine(mcEngine);
145 Real mcPayerPrice = payerSwaption->NPV();
146 Real mcReceiverPrice = receiverSwaption->NPV();
147 Real mcTime = tmc.elapsed().wall * 1e-6;
149 Real payerError1 = 100.0 * fabs(mcPayerPrice - anPayerPrice) / mcPayerPrice;
150 Real payerError2 = 100.0 * fabs(mcPayerPrice - anPayerPrice) / anPayerPrice;
151 Real receiverError1 = 100.0 * fabs(mcReceiverPrice - anReceiverPrice) / mcReceiverPrice;
152 Real receiverError2 = 100.0 * fabs(mcReceiverPrice - anReceiverPrice) / anReceiverPrice;
154 BOOST_TEST_MESSAGE(
"Analytical vs MC, Payer Swaption, "
155 << std::fixed << std::setprecision(2) <<
"strike " << strikePrice <<
", expiry "
157 <<
"an " << anPayerPrice <<
" mc " << mcPayerPrice <<
" diff "
158 << anPayerPrice - mcPayerPrice <<
" rel " << std::max(payerError1, payerError2) <<
"% "
159 <<
" underlying " << payerSwap->NPV() <<
" (" << anTime <<
" ms, " << mcTime <<
" ms)");
162 "Analytical vs MC, Receiver Swaption, "
163 << std::fixed << std::setprecision(2) <<
"strike " << strikePrice <<
", expiry " << startTerm <<
": "
164 <<
"an " << anReceiverPrice <<
" mc " << mcReceiverPrice <<
" diff "
165 << anReceiverPrice - mcReceiverPrice <<
" rel " << std::max(receiverError1, receiverError2) <<
"% "
166 <<
" underlying " << receiverSwap->NPV() <<
" (" << anTime <<
" ms, " << mcTime <<
" ms)");
171 BOOST_CHECK_SMALL(anPayerPrice - mcPayerPrice, 26.0);
172 BOOST_CHECK_SMALL(anReceiverPrice - mcReceiverPrice, 26.0);
174 Real anPutCallPartiy = anPayerPrice - anReceiverPrice - payerSwap->NPV();
175 Real mcPutCallPartiy = mcPayerPrice - mcReceiverPrice - payerSwap->NPV();
177 BOOST_TEST_MESSAGE(
"put/call parity check, "
178 << std::fixed << std::setprecision(2) << strikePrice <<
" " << startTerm
179 <<
": analyticalPayerSwaption - analyticalreceiverSwaption - payerSwap = "
181 BOOST_TEST_MESSAGE(
"put/call parity check, "
182 << std::fixed << std::setprecision(2) << strikePrice <<
" " << startTerm
183 <<
": mcPayerSwaption - mcreceiverSwaption - payerSwap = " << mcPutCallPartiy);
186 BOOST_CHECK_SMALL(anPutCallPartiy, 0.5);
187 BOOST_CHECK_SMALL(mcPutCallPartiy, 4.0);
202BOOST_AUTO_TEST_SUITE_END()
203BOOST_AUTO_TEST_SUITE_END()
CommodityIndexedAverageLeg & withQuantities(QuantLib::Real quantity)
CommodityIndexedAverageLeg & withPaymentCalendar(const QuantLib::Calendar &paymentCalendar)
CommodityIndexedAverageLeg & withPricingCalendar(const QuantLib::Calendar &pricingCalendar)
CommodityIndexedAverageLeg & withSpreads(QuantLib::Real spread)
CommodityIndexedLeg & withPricingLagCalendar(const QuantLib::Calendar &pricingLagCalendar)
CommodityIndexedLeg & withQuantities(QuantLib::Real quantity)
CommodityIndexedLeg & withPaymentCalendar(const QuantLib::Calendar &paymentCalendar)
CommodityIndexedLeg & withSpreads(QuantLib::Real spread)
void run_test(bool averaging)
BOOST_AUTO_TEST_CASE(testAveragingCommoditySwaption)