20#include <boost/test/unit_test.hpp>
22#include <ql/cashflows/cashflows.hpp>
23#include <ql/cashflows/fixedratecoupon.hpp>
24#include <ql/instruments/bonds/fixedratebond.hpp>
25#include <ql/quotes/simplequote.hpp>
26#include <ql/termstructures/credit/flathazardrate.hpp>
27#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
28#include <ql/termstructures/yield/flatforward.hpp>
29#include <ql/time/calendars/weekendsonly.hpp>
30#include <ql/time/schedule.hpp>
33#include <boost/make_shared.hpp>
40using boost::unit_test_framework::test_suite;
44BOOST_AUTO_TEST_SUITE(BondOptionTest)
48 BOOST_TEST_MESSAGE(
"Testing QuantExt Bond Option pricing.");
52 Settings::instance().evaluationDate() = Date(5, Feb, 2016);
53 Date issueDate = Date(3, Nov, 2015);
54 Date today = Settings::instance().evaluationDate();
55 Settings::instance().includeReferenceDateEvents() =
true;
58 Handle<Quote> rateQuote(QuantLib::ext::make_shared<SimpleQuote>(0.1));
59 Handle<Quote> issuerSpreadQuote(QuantLib::ext::make_shared<SimpleQuote>(0.0));
60 DayCounter dc = Actual365Fixed();
61 Handle<YieldTermStructure> yts(QuantLib::ext::make_shared<FlatForward>(today, rateQuote, dc, Compounded, Semiannual));
62 Handle<DefaultProbabilityTermStructure> dpts(QuantLib::ext::make_shared<FlatHazardRate>(today, issuerSpreadQuote, dc));
63 Handle<Quote> bondSpecificSpread(QuantLib::ext::make_shared<SimpleQuote>(0.0));
66 Date startDate = today;
67 Date endDate = startDate + Period(2, Years);
68 Period tenor = 6 * Months;
69 Calendar calendar = WeekendsOnly();
70 BusinessDayConvention bdc = Following;
71 BusinessDayConvention bdcEnd = bdc;
72 DateGeneration::Rule rule = DateGeneration::Forward;
73 bool endOfMonth =
false;
74 Date firstDate, lastDate;
75 Schedule schedule(startDate, endDate, tenor, calendar, bdc, bdcEnd, rule, endOfMonth, firstDate, lastDate);
77 Real redemption = 100.0;
79 Real couponRate = 0.1;
83 Handle<Quote> discountQuote(QuantLib::ext::make_shared<SimpleQuote>(0.1));
84 Handle<YieldTermStructure> discountTS(
85 QuantLib::ext::make_shared<FlatForward>(today, discountQuote, dc, Compounded, Semiannual));
88 QuantLib::ext::shared_ptr<QuantLib::SwaptionVolatilityStructure> svs(
89 new QuantLib::ConstantSwaptionVolatility(Settings::instance().evaluationDate(), NullCalendar(),
90 ModifiedFollowing, 0.5, Actual365Fixed(), ShiftedLognormal, 0.0));
94 discountTS, Handle<QuantLib::SwaptionVolatilityStructure>(svs), discountTS));
97 Real strikePrice = notional;
98 Real faceAmount = notional;
99 Natural settlementDays = 2;
100 std::vector<Rate> rates = std::vector<Rate>(1, couponRate);
101 QuantLib::Bond::Price callabilityPrice = QuantLib::Bond::Price(strikePrice, QuantLib::Bond::Price::Dirty);
102 Callability::Type callabilityType = Callability::Call;
103 Date exerciseDate = Date(5, Dec, 2016);
104 QuantLib::ext::shared_ptr<Callability> callability(
new Callability(callabilityPrice, callabilityType, exerciseDate));
105 CallabilitySchedule callabilitySchedule = std::vector<QuantLib::ext::shared_ptr<Callability>>(1, callability);
107 QuantLib::ext::shared_ptr<QuantLib::Bond> bond(
108 new QuantLib::FixedRateBond(settlementDays, faceAmount, schedule, rates, dc, bdc, redemption, issueDate));
109 QuantLib::ext::shared_ptr<QuantExt::BondOption> bondOption(
new QuantExt::BondOption(bond, callabilitySchedule));
110 bondOption->setPricingEngine(bondOptionEngine);
113 Real otmStrikePrice = notional * 2;
114 QuantLib::Bond::Price otmCallabilityPrice = QuantLib::Bond::Price(otmStrikePrice, QuantLib::Bond::Price::Dirty);
115 QuantLib::ext::shared_ptr<Callability> otmCallability(
new Callability(otmCallabilityPrice, callabilityType, exerciseDate));
116 CallabilitySchedule otmCallabilitySchedule = std::vector<QuantLib::ext::shared_ptr<Callability>>(1, otmCallability);
118 QuantLib::ext::shared_ptr<QuantExt::BondOption> otmBondOption(
new QuantExt::BondOption(bond, otmCallabilitySchedule));
119 otmBondOption->setPricingEngine(bondOptionEngine);
122 Real itmStrikePrice = notional / 2;
123 QuantLib::Bond::Price itmCallabilityPrice = QuantLib::Bond::Price(itmStrikePrice, QuantLib::Bond::Price::Dirty);
124 QuantLib::ext::shared_ptr<Callability> itmCallability(
new Callability(itmCallabilityPrice, callabilityType, exerciseDate));
125 CallabilitySchedule itmCallabilitySchedule = std::vector<QuantLib::ext::shared_ptr<Callability>>(1, itmCallability);
127 QuantLib::ext::shared_ptr<QuantExt::BondOption> itmBondOption(
new QuantExt::BondOption(bond, itmCallabilitySchedule));
128 itmBondOption->setPricingEngine(bondOptionEngine);
131 QuantLib::ext::shared_ptr<QuantLib::Bond> zerobond(
new QuantLib::FixedRateBond(
132 settlementDays, faceAmount,
133 Schedule(startDate, endDate, Period(Once), calendar, bdc, bdcEnd, DateGeneration::Backward,
false),
134 std::vector<Rate>(1, 0.0), dc, bdc, redemption, issueDate));
135 QuantLib::ext::shared_ptr<QuantExt::BondOption> zeroBondOption(
new QuantExt::BondOption(zerobond, callabilitySchedule));
136 zeroBondOption->setPricingEngine(bondOptionEngine);
138 BOOST_TEST_MESSAGE(
"normal bond option price = " << bondOption->NPV());
139 BOOST_CHECK_CLOSE(bondOption->NPV(), 36.807084355035521, 0.000001);
141 BOOST_TEST_MESSAGE(
"tief otm bond option price = " << otmBondOption->NPV());
142 BOOST_CHECK_CLOSE(otmBondOption->NPV(), 3.2657301416105546e-45, 0.000001);
144 BOOST_TEST_MESSAGE(
"tief itm bond option price = " << itmBondOption->NPV());
145 BOOST_CHECK_CLOSE(itmBondOption->NPV(), 491.52718033161705, 0.000001);
147 BOOST_TEST_MESSAGE(
"zero bond option price = " << zeroBondOption->NPV());
148 BOOST_CHECK_CLOSE(zeroBondOption->NPV(), 0.15813277744399326, 0.000001);
151 Real putCallStrikePrice = 1000;
152 QuantLib::Bond::Price putCallCallabilityPrice =
153 QuantLib::Bond::Price(putCallStrikePrice, QuantLib::Bond::Price::Dirty);
155 QuantLib::ext::shared_ptr<Callability> callCallability(
156 new Callability(putCallCallabilityPrice, Callability::Call, exerciseDate));
157 CallabilitySchedule callCallabilitySchedule = std::vector<QuantLib::ext::shared_ptr<Callability>>(1, callCallability);
158 QuantLib::ext::shared_ptr<QuantExt::BondOption> bondCallOption(
new QuantExt::BondOption(bond, callCallabilitySchedule));
159 bondCallOption->setPricingEngine(bondOptionEngine);
161 QuantLib::ext::shared_ptr<Callability> putCallability(
162 new Callability(putCallCallabilityPrice, Callability::Put, exerciseDate));
163 CallabilitySchedule putCallabilitySchedule = std::vector<QuantLib::ext::shared_ptr<Callability>>(1, putCallability);
164 QuantLib::ext::shared_ptr<QuantExt::BondOption> bondPutOption(
new QuantExt::BondOption(bond, putCallabilitySchedule));
165 bondPutOption->setPricingEngine(bondOptionEngine);
167 Real discount = discountTS->discount(exerciseDate);
169 Real fwdbond = bondCallOption->result<Real>(
"FwdCashPrice");
170 BOOST_TEST_MESSAGE(
"bond forward price = " << fwdbond);
172 BOOST_TEST_MESSAGE(
"bond call option price = " << bondCallOption->NPV());
173 BOOST_TEST_MESSAGE(
"bond put option price = " << bondPutOption->NPV());
175 Real right = bondCallOption->NPV() + putCallStrikePrice * discount;
176 Real left = bondPutOption->NPV() + fwdbond * discount;
178 BOOST_TEST_MESSAGE(
"right side of put-call parity (call + K*df) = " << right);
179 BOOST_TEST_MESSAGE(
"left side of put-call parity (put + Fwd*df) = " << left);
180 BOOST_CHECK_CLOSE(right, left, 0.000001);
184 QuantLib::ext::shared_ptr<QuantLib::SwaptionVolatilityStructure> svs_normal(
new QuantLib::ConstantSwaptionVolatility(
185 Settings::instance().evaluationDate(), NullCalendar(), ModifiedFollowing, 0.5, Actual365Fixed(), Normal));
189 discountTS, Handle<QuantLib::SwaptionVolatilityStructure>(svs_normal), discountTS));
191 bondCallOption->setPricingEngine(bondOptionEngineNormal);
192 bondPutOption->setPricingEngine(bondOptionEngineNormal);
194 BOOST_TEST_MESSAGE(
"bond call option price = " << bondCallOption->NPV());
195 BOOST_TEST_MESSAGE(
"bond put option price = " << bondPutOption->NPV());
197 right = bondCallOption->NPV() + putCallStrikePrice * discount;
198 left = bondPutOption->NPV() + fwdbond * discount;
200 BOOST_TEST_MESSAGE(
"right side of put-call parity (call + K*df) = " << right);
201 BOOST_TEST_MESSAGE(
"left side of put-call parity (put + Fwd*df) = " << left);
202 BOOST_CHECK_CLOSE(right, left, 0.000001);
205BOOST_AUTO_TEST_SUITE_END()
206BOOST_AUTO_TEST_SUITE_END()
Black bond option engine.
Black-formula bond option engine.
BOOST_AUTO_TEST_CASE(testBondOption)
Fixture that can be used at top level.