Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions
bondtrs.cpp File Reference
#include "toplevelfixture.hpp"
#include <boost/make_shared.hpp>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <ql/cashflows/cashflows.hpp>
#include <ql/cashflows/fixedratecoupon.hpp>
#include <ql/cashflows/iborcoupon.hpp>
#include <ql/indexes/ibor/euribor.hpp>
#include <ql/instruments/bond.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/credit/flathazardrate.hpp>
#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/schedule.hpp>
#include <qle/indexes/bondindex.hpp>
#include <qle/pricingengines/discountingriskybondengine.hpp>
#include <qle/pricingengines/discountingbondtrsengine.hpp>

Go to the source code of this file.

Functions

 BOOST_DATA_TEST_CASE (testBondTRS, boost::unit_test::data::make(testData), data)
 

Function Documentation

◆ BOOST_DATA_TEST_CASE()

BOOST_DATA_TEST_CASE ( testBondTRS  ,
boost::unit_test::data::make(testData)  ,
data   
)

Definition at line 78 of file bondtrs.cpp.

78 {
79
80 BOOST_TEST_MESSAGE("Testing QuantExt Bond TRS pricing.");
81
82 Settings::instance().evaluationDate() = Date(5, Feb, 2016);
83 Date today = Settings::instance().evaluationDate();
84 Calendar calendar = TARGET();
85
86 // bond market data
87 Handle<Quote> rateQuote(QuantLib::ext::make_shared<SimpleQuote>(data.benchmarkRate));
88 Handle<Quote> issuerSpreadQuote(QuantLib::ext::make_shared<SimpleQuote>(data.defaultSpread));
89 DayCounter dc = Actual365Fixed();
90 Handle<YieldTermStructure> yieldCurve(QuantLib::ext::make_shared<FlatForward>(today, rateQuote, dc, Compounded, Annual));
91 Handle<DefaultProbabilityTermStructure> defaultCurve(
92 QuantLib::ext::make_shared<FlatHazardRate>(today, issuerSpreadQuote, dc));
93 Handle<Quote> bondSpecificSpread(QuantLib::ext::make_shared<SimpleQuote>(data.securitySpread));
94 Handle<Quote> recoveryRateQuote(QuantLib::ext::make_shared<SimpleQuote>(0.4));
95
96 // derivatives market data
97 Handle<Quote> oisQuote(QuantLib::ext::make_shared<SimpleQuote>(data.oisRate));
98 Handle<YieldTermStructure> oisCurve(QuantLib::ext::make_shared<FlatForward>(today, oisQuote, dc, Compounded, Annual));
99 Handle<Quote> iborQuote(QuantLib::ext::make_shared<SimpleQuote>(data.euriborRate));
100 Handle<YieldTermStructure> iborCurve(QuantLib::ext::make_shared<FlatForward>(today, iborQuote, dc, Compounded, Annual));
101
102 // build the underlying bond
103 Date startDate = data.seasoned ? today - 3 * Months : TARGET().advance(today, 2 * Days);
104 Date endDate = startDate + Period(5, Years);
105 BusinessDayConvention bdc = Following;
106 BusinessDayConvention bdcEnd = bdc;
107 DateGeneration::Rule rule = DateGeneration::Forward;
108 bool endOfMonth = false;
109 Date firstDate, lastDate;
110 Schedule schedule(startDate, endDate, 1 * Years, calendar, bdc, bdcEnd, rule, endOfMonth, firstDate, lastDate);
111 Real redemption = 100.0;
112 Real couponRate = 0.04;
113 Leg leg =
114 FixedRateLeg(schedule).withNotionals(redemption).withCouponRates(couponRate, dc).withPaymentAdjustment(bdc);
115
116 QuantLib::ext::shared_ptr<QuantLib::Bond> bond(QuantLib::ext::make_shared<QuantLib::Bond>(0, calendar, startDate, leg));
117
118 // build associated bond index
119 std::string secId = "SECURITY";
120 QuantLib::ext::shared_ptr<QuantExt::BondIndex> bondIndex = QuantLib::ext::make_shared<QuantExt::BondIndex>(
121 secId, false, false, NullCalendar(), bond, yieldCurve, defaultCurve, recoveryRateQuote, bondSpecificSpread,
122 Handle<YieldTermStructure>(), false);
123 Date bondFixingDate(5, Nov, 2015);
124 bondIndex->addFixing(bondFixingDate, data.bondFixing);
125
126 // build and attach bond engine
127 Period timeStep = 1 * Months;
128 QuantLib::ext::shared_ptr<PricingEngine> bondEngine(QuantLib::ext::make_shared<QuantExt::DiscountingRiskyBondEngine>(
129 yieldCurve, defaultCurve, recoveryRateQuote, bondSpecificSpread, timeStep));
130 bond->setPricingEngine(bondEngine);
131
132 // build the TRS funding leg
133 Schedule floatingSchedule(startDate, endDate, 6 * Months, calendar, bdc, bdcEnd, rule, endOfMonth, firstDate,
134 lastDate);
135 QuantLib::ext::shared_ptr<IborIndex> iborIndex = QuantLib::ext::make_shared<Euribor>(6 * Months, iborCurve);
136 Leg fundingLeg = IborLeg(schedule, iborIndex).withNotionals(redemption);
137 Date iborFixingDate(3, Nov, 2015);
138 iborIndex->addFixing(iborFixingDate, 0.03);
139 Leg fundingNotionalLeg; // no notional exchanges on funding leg
140
141 // build the valuation and payment dates from the floating schedule
142 std::vector<Date> valuationDates, paymentDates;
143 for (const auto& d : floatingSchedule.dates()) {
144 valuationDates.push_back(d);
145 if (d != floatingSchedule.dates().front())
146 paymentDates.push_back(d);
147 }
148
149 // build TRS
150 QuantLib::ext::shared_ptr<BondTRS> trs = QuantLib::ext::make_shared<BondTRS>(
151 bondIndex, 1.0, Null<Real>(), std::vector<QuantLib::Leg>{fundingLeg, fundingNotionalLeg},
152 true, valuationDates, paymentDates);
153 QuantLib::ext::shared_ptr<PricingEngine> trsEngine(new QuantExt::DiscountingBondTRSEngine(oisCurve));
154 trs->setPricingEngine(trsEngine);
155
156 // build floating rate note (risk free, i.e. zero credit spread, security spread)
157 QuantLib::ext::shared_ptr<QuantLib::Bond> floater(QuantLib::ext::make_shared<QuantLib::Bond>(0, calendar, startDate, fundingLeg));
158 Handle<Quote> floaterIssuerSpreadQuote(QuantLib::ext::make_shared<SimpleQuote>(0.0));
159 Handle<DefaultProbabilityTermStructure> floaterDefaultCurve(
160 QuantLib::ext::make_shared<FlatHazardRate>(today, floaterIssuerSpreadQuote, dc));
161 Handle<Quote> floaterSpecificSpread(QuantLib::ext::make_shared<SimpleQuote>(data.securitySpread));
162 Handle<Quote> floaterRecoveryRateQuote(QuantLib::ext::make_shared<SimpleQuote>(0.0));
163 QuantLib::ext::shared_ptr<PricingEngine> floaterEngine(QuantLib::ext::make_shared<QuantExt::DiscountingRiskyBondEngine>(
164 yieldCurve, floaterDefaultCurve, floaterRecoveryRateQuote, floaterSpecificSpread, timeStep));
165 floater->setPricingEngine(floaterEngine);
166
167 std::ostringstream output;
168
169 // Real bondNpv = bond->cleanPrice();
170 Real bondNpv = bond->NPV();
171
172 output << "Bond NPV = " << bondNpv << "\n";
173 output << "Floater NPV = " << floater->NPV() << "\n";
174 output << "TRS NPV = " << trs->NPV() << "\n";
175 output << "Bond + TRS - Floater = " << bondNpv + trs->NPV() - floater->NPV() << "\n";
176
177 BOOST_TEST_MESSAGE(output.str());
178
179 // plausibility check only:
180 // the package of a long bond and a TRS (pay total return leg, rec Euribor)
181 // is similar to a risk free floater, but in addition we receive the difference of the bond npv
182 // and par over the lifetime of the swap through the compensation payments
183 // notice this check is equivalent to: trs->NPV() ~ floater->NPV() - redemption
184 BOOST_CHECK_SMALL((bondNpv + trs->NPV() - floater->NPV()) - (bondNpv - redemption), 1.0);
185}