Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions
commodityswaption.cpp File Reference
#include <oret/toplevelfixture.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/timer/timer.hpp>
#include <iomanip>
#include <ql/cashflows/simplecashflow.hpp>
#include <ql/currencies/america.hpp>
#include <ql/exercise.hpp>
#include <ql/math/interpolations/linearinterpolation.hpp>
#include <ql/pricingengines/swap/discountingswapengine.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/unitedstates.hpp>
#include <ql/time/schedule.hpp>
#include <qle/cashflows/commodityindexedaveragecashflow.hpp>
#include <qle/cashflows/commodityindexedcashflow.hpp>
#include <qle/termstructures/pricecurve.hpp>
#include <qle/instruments/genericswaption.hpp>
#include <qle/pricingengines/commodityswaptionengine.hpp>

Go to the source code of this file.

Functions

void run_test (bool averaging)
 
 BOOST_AUTO_TEST_CASE (testAveragingCommoditySwaption)
 
 BOOST_AUTO_TEST_CASE (testNonAveragingCommoditySwaption)
 

Function Documentation

◆ run_test()

void run_test ( bool  averaging)

Definition at line 47 of file commodityswaption.cpp.

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 // Market - flat price curve
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(
65 QuantLib::ext::make_shared<InterpolatedPriceCurve<Linear>>(today, dates, prices, dc, USDCurrency()));
66 priceCurve->enableExtrapolation();
67
68 // Market - flat discount curve
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 // Market - flat volatility structure
73 Handle<QuantLib::BlackVolTermStructure> vol(QuantLib::ext::make_shared<QuantLib::BlackConstantVol>(today, cal, 0.3, dc));
74
75 // Analytical engine
76 Real beta = 0.0;
77 QuantLib::ext::shared_ptr<PricingEngine> analyticalEngine =
78 QuantLib::ext::make_shared<CommoditySwaptionEngine>(discountCurve, vol, beta);
79
80 // Monte Carlo engine
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 // Swap start times
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
97 Real strikePrice = strikes[k];
98
99 // Vary Swaption start dates, set up underlying Swaps of length one year with 12 monthly calculation periods
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)
110 floatLeg = CommodityIndexedAverageLeg(schedule, index)
111 .withQuantities(quantity)
114 .withSpreads(0.0);
115 else
116 floatLeg = CommodityIndexedLeg(schedule, index)
117 .withQuantities(quantity)
120 .withSpreads(0.0);
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 // Absolute tolerance is generous, and even if the following check is passed:
169 // Relative errors for short expiry options are significant, in particular out of the money.
170 // => The analytical approximation is rough, consider using the MC engine if performance permits.
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 // Put/call partiy check tolerances are tight on both cases
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)
vector< Real > strikes
string name
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ BOOST_AUTO_TEST_CASE() [1/2]

BOOST_AUTO_TEST_CASE ( testAveragingCommoditySwaption  )

Definition at line 192 of file commodityswaption.cpp.

192 {
193 // averaging swaption
194 run_test(true);
195}
void run_test(bool averaging)
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [2/2]

BOOST_AUTO_TEST_CASE ( testNonAveragingCommoditySwaption  )

Definition at line 197 of file commodityswaption.cpp.

197 {
198 // non-averaging swaption
199 run_test(false);
200}
+ Here is the call graph for this function: