47 {
48 if (averaging)
49 BOOST_TEST_MESSAGE("Testing Averaging Commodity Swaption Analytical Approximation vs MC Pricing");
50 else
51 BOOST_TEST_MESSAGE("Testing Non-Averaging Commodity Swaption Analytical Approximation vs MC Pricing");
52
53 SavedSettings backup;
54
55 Date today(5, Feb, 2019);
56 Settings::instance().evaluationDate() = today;
57 Calendar cal = UnitedStates(UnitedStates::Settlement);
58
59
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();
67
68
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));
71
72
73 Handle<QuantLib::BlackVolTermStructure> vol(QuantLib::ext::make_shared<QuantLib::BlackConstantVol>(today, cal, 0.3, dc));
74
75
76 Real beta = 0.0;
77 QuantLib::ext::shared_ptr<PricingEngine> analyticalEngine =
78 QuantLib::ext::make_shared<CommoditySwaptionEngine>(discountCurve, vol, beta);
79
80
81 Size samples = 10000;
82 QuantLib::ext::shared_ptr<PricingEngine> mcEngine =
83 QuantLib::ext::make_shared<CommoditySwaptionMonteCarloEngine>(discountCurve, vol, samples, beta);
84
85 QuantLib::ext::shared_ptr<PricingEngine> swapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(discountCurve);
86
87 Real quantity = 1.0;
88 std::string
name =
"CL";
89 QuantLib::ext::shared_ptr<CommoditySpotIndex> index = QuantLib::ext::make_shared<CommoditySpotIndex>(
name, cal, priceCurve);
90
91
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};
94
95 for (Size k = 0; k <
strikes.size(); ++k) {
96
98
99
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);
105 Leg fixedLeg;
106 for (Size j = 1; j < schedule.size(); ++j)
107 fixedLeg.push_back(QuantLib::ext::make_shared<SimpleCashFlow>(quantity * strikePrice, schedule[j]));
108 Leg floatLeg;
109 if (averaging)
115 else
121
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);
124
125 payerSwap->setPricingEngine(swapEngine);
126 receiverSwap->setPricingEngine(swapEngine);
127 BOOST_TEST_MESSAGE("Testing Swap NPV " << payerSwap->NPV() << " " << receiverSwap->NPV());
128
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);
134
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;
141
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;
148
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;
153
154 BOOST_TEST_MESSAGE("Analytical vs MC, Payer Swaption, "
155 << std::fixed << std::setprecision(2) << "strike " << strikePrice << ", expiry "
156 << startTerm << ": "
157 << "an " << anPayerPrice << " mc " << mcPayerPrice << " diff "
158 << anPayerPrice - mcPayerPrice << " rel " << std::max(payerError1, payerError2) << "% "
159 << " underlying " << payerSwap->NPV() << " (" << anTime << " ms, " << mcTime << " ms)");
160
161 BOOST_TEST_MESSAGE(
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)");
167
168
169
170
171 BOOST_CHECK_SMALL(anPayerPrice - mcPayerPrice, 26.0);
172 BOOST_CHECK_SMALL(anReceiverPrice - mcReceiverPrice, 26.0);
173
174 Real anPutCallPartiy = anPayerPrice - anReceiverPrice - payerSwap->NPV();
175 Real mcPutCallPartiy = mcPayerPrice - mcReceiverPrice - payerSwap->NPV();
176
177 BOOST_TEST_MESSAGE("put/call parity check, "
178 << std::fixed << std::setprecision(2) << strikePrice << " " << startTerm
179 << ": analyticalPayerSwaption - analyticalreceiverSwaption - payerSwap = "
180 << anPutCallPartiy);
181 BOOST_TEST_MESSAGE("put/call parity check, "
182 << std::fixed << std::setprecision(2) << strikePrice << " " << startTerm
183 << ": mcPayerSwaption - mcreceiverSwaption - payerSwap = " << mcPutCallPartiy);
184
185
186 BOOST_CHECK_SMALL(anPutCallPartiy, 0.5);
187 BOOST_CHECK_SMALL(mcPutCallPartiy, 4.0);
188 }
189 }
190}
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)