19#include <boost/make_shared.hpp>
20#include <boost/test/unit_test.hpp>
28#include <oret/toplevelfixture.hpp>
29#include <ql/cashflows/cpicoupon.hpp>
30#include <ql/cashflows/cpicouponpricer.hpp>
31#include <ql/cashflows/iborcoupon.hpp>
32#include <ql/indexes/inflation/ukrpi.hpp>
33#include <ql/termstructures/inflation/inflationhelpers.hpp>
34#include <ql/termstructures/inflation/piecewisezeroinflationcurve.hpp>
35#include <ql/termstructures/yield/discountcurve.hpp>
36#include <ql/time/calendars/unitedkingdom.hpp>
37#include <ql/time/daycounters/actual365fixed.hpp>
38#include <ql/time/daycounters/actualactual.hpp>
41using namespace boost::unit_test_framework;
54 asof_ = Date(18, July, 2016);
57 vector<Date> datesGBP = {
asof_,
88 vector<DiscountFactor> dfsGBP = {1, 0.9955, 0.9953, 0.9947, 0.9941, 0.9933, 0.9924, 0.9914,
89 0.9908, 0.9901, 0.9895, 0.9888, 0.9881, 0.9874, 0.9868, 0.9862,
90 0.9855, 0.9849, 0.9842, 0.9836, 0.9743, 0.9634, 0.9510, 0.9361,
91 0.9192, 0.9011, 0.8822, 0.8637, 0.7792, 0.7079};
94 vector<Date> datesZCII = {
asof_,
109 vector<Rate> ratesZCII = {2.825, 2.9425, 2.975, 2.983, 3.0, 3.01, 3.008,
110 3.009, 3.013, 3.0445, 3.044, 3.09, 3.109, 3.108};
113 Schedule fixingDatesUKRPI =
114 MakeSchedule().from(Date(1, May, 2015)).to(Date(1, July, 2016)).withTenor(1 * Months);
115 Real fixingRatesUKRPI[] = {258.5, 258.9, 258.6, 259.8, 259.6, 259.5, 259.8, 260.6,
116 258.8, 260.0, 261.1, 261.4, 262.1, -999.0, -999.0};
120 intDiscCurve(datesGBP, dfsGBP, ActualActual(ActualActual::ISDA), UnitedKingdom());
123 hGBP = Handle<IborIndex>(
124 parseIborIndex(
"GBP-LIBOR-6M", intDiscCurve(datesGBP, dfsGBP, ActualActual(ActualActual::ISDA), UnitedKingdom())));
128 hGBP->addFixing(Date(18, July, 2016), 0.0061731);
131 QuantLib::ext::shared_ptr<UKRPI> ii;
132 QuantLib::ext::shared_ptr<ZeroInflationTermStructure> cpiTS;
133 RelinkableHandle<ZeroInflationTermStructure> hcpi;
134 ii = QuantLib::ext::shared_ptr<UKRPI>(
new UKRPI(hcpi));
135 for (Size i = 0; i < fixingDatesUKRPI.size(); i++) {
137 ii->addFixing(fixingDatesUKRPI[i], fixingRatesUKRPI[i],
true);
140 vector<QuantLib::ext::shared_ptr<BootstrapHelper<ZeroInflationTermStructure>>> instruments;
141 for (Size i = 0; i < datesZCII.size(); i++) {
142 Handle<Quote> quote(QuantLib::ext::shared_ptr<Quote>(
new SimpleQuote(ratesZCII[i] / 100.0)));
143 QuantLib::ext::shared_ptr<BootstrapHelper<ZeroInflationTermStructure>> anInstrument(
144 new ZeroCouponInflationSwapHelper(
145 quote, Period(2, Months), datesZCII[i], UnitedKingdom(), ModifiedFollowing, ActualActual(ActualActual::ISDA), ii,
148 instruments.push_back(anInstrument);
152 Rate baseZeroRate = ratesZCII[0] / 100.0;
154 asof_, UnitedKingdom(), ActualActual(ActualActual::ISDA), Period(2, Months), ii->frequency(),
155 baseZeroRate, instruments));
156 pCPIts->recalculate();
157 cpiTS = QuantLib::ext::dynamic_pointer_cast<ZeroInflationTermStructure>(pCPIts);
158 hUKRPI = Handle<ZeroInflationIndex>(
163 Handle<IborIndex> hGBP;
164 Handle<ZeroInflationIndex> hUKRPI;
167 Handle<YieldTermStructure> intDiscCurve(vector<Date> dates, vector<DiscountFactor> dfs, DayCounter dc,
169 QuantLib::ext::shared_ptr<YieldTermStructure> idc(
170 new QuantLib::InterpolatedDiscountCurve<LogLinear>(dates, dfs, dc, cal));
171 return Handle<YieldTermStructure>(idc);
176BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)
178BOOST_AUTO_TEST_SUITE(CPISwapTests)
182 BOOST_TEST_MESSAGE(
"Testing CPI Swap Price...");
185 Date today(18, July, 2016);
186 Settings::instance().evaluationDate() = today;
187 QuantLib::ext::shared_ptr<TestMarket> market = QuantLib::ext::make_shared<TestMarket>();
188 Date marketDate = market->asofDate();
189 BOOST_CHECK_EQUAL(today, marketDate);
190 Settings::instance().evaluationDate() = marketDate;
193 Handle<YieldTermStructure> dts = market->discountCurve(
"GBP");
194 QL_REQUIRE(!dts.empty(),
"GBP discount curve not found");
195 BOOST_CHECK_CLOSE(market->discountCurve(
"GBP")->discount(today + 1 * Years), 0.9914, 0.0001);
198 Handle<IborIndex> iis = market->iborIndex(
"GBP-LIBOR-6M");
199 QL_REQUIRE(!iis.empty(),
"GBP LIBOR 6M ibor Index not found");
201 "CPISwap: Projected Libor fixing: " << market->iborIndex(
"GBP-LIBOR-6M")->forecastFixing(today + 1 * Years));
204 Handle<ZeroInflationIndex> infidx = market->zeroInflationIndex(
"UKRPI");
205 QL_REQUIRE(!infidx.empty(),
"UKRPI inflation index not found");
206 BOOST_TEST_MESSAGE(
"CPISwap: Projected UKRPI rate: " << infidx->fixing(today + 1 * Years));
212 Date startDate = today;
213 Date endDate = today + 5 * Years;
216 std::ostringstream oss;
217 oss << io::iso_date(startDate);
218 string start(oss.str());
221 oss << io::iso_date(endDate);
222 string end(oss.str());
226 string rule =
"Forward";
231 bool isInArrears =
false;
232 string dc =
"ACT/ACT";
233 vector<Real> notional(1, 10000000);
234 string paymentConvention =
"F";
237 bool isPayerLibor =
true;
238 string indexLibor =
"GBP-LIBOR-6M";
239 vector<Real> spread(1, 0);
240 LegData legLibor(QuantLib::ext::make_shared<FloatingLegData>(indexLibor, 0, isInArrears, spread), isPayerLibor,
"GBP",
241 scheduleLibor,
"A365F", notional, vector<string>(), paymentConvention);
244 bool isPayerCPI =
false;
245 string indexCPI =
"UKRPI";
246 Real baseCPI = 210.0;
247 string CPIlag =
"2M";
248 std::vector<double> fixedRate(1, 0.02);
249 bool interpolated =
false;
251 QuantLib::ext::make_shared<CPILegData>(indexCPI, start, baseCPI, CPIlag, (interpolated ?
"Linear" :
"Flat"), fixedRate),
252 isPayerCPI,
"GBP", scheduleCPI, dc, notional, vector<string>(), paymentConvention,
false,
true);
255 QuantLib::ext::shared_ptr<Trade> CPIswap(
new ore::data::Swap(env, legLibor, legCPI));
258 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
259 engineData->model(
"Swap") =
"DiscountedCashflows";
260 engineData->engine(
"Swap") =
"DiscountingSwapEngine";
261 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
264 QuantLib::ext::shared_ptr<Portfolio> portfolio(
new Portfolio());
265 CPIswap->id() =
"CPI_Swap";
267 portfolio->add(CPIswap);
268 portfolio->build(engineFactory);
271 Schedule floatSchedule(startDate, endDate, 6 * Months, UnitedKingdom(), ModifiedFollowing, ModifiedFollowing,
272 DateGeneration::Forward,
false);
273 Schedule cpiSchedule(startDate, endDate, 1 * Years, UnitedKingdom(), ModifiedFollowing, ModifiedFollowing,
274 DateGeneration::Forward,
false);
275 Leg floatLeg = IborLeg(floatSchedule, *market->hGBP).withNotionals(10000000.0);
276 Leg cpiLeg =
CPILeg(cpiSchedule, *market->hUKRPI, baseCPI, 2 * Months)
282 auto pricer = QuantLib::ext::make_shared<CPICouponPricer>(market->hGBP->forwardingTermStructure());
283 for (
auto const& c : cpiLeg) {
284 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<CPICoupon>(c))
285 cpn->setPricer(pricer);
289 auto dscEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(market->hGBP->forwardingTermStructure());
290 qlSwap.setPricingEngine(dscEngine);
291 BOOST_TEST_MESSAGE(
"Leg 1 NPV: ORE = "
292 << QuantLib::ext::static_pointer_cast<QuantLib::Swap>(CPIswap->instrument()->qlInstrument())->legNPV(0)
293 <<
" QL = " << qlSwap.legNPV(0));
294 BOOST_TEST_MESSAGE(
"Leg 2 NPV: ORE = "
295 << QuantLib::ext::static_pointer_cast<QuantLib::Swap>(CPIswap->instrument()->qlInstrument())->legNPV(1)
296 <<
" QL = " << qlSwap.legNPV(1));
297 BOOST_CHECK_CLOSE(CPIswap->instrument()->NPV(), qlSwap.NPV(), 1E-8);
300BOOST_AUTO_TEST_SUITE_END()
302BOOST_AUTO_TEST_SUITE_END()
Engine builder for Swaps.
CPILeg & withNotionals(Real notional)
CPILeg & withPaymentAdjustment(BusinessDayConvention)
CPILeg & withFixedRates(Real fixedRate)
CPILeg & withPaymentDayCounter(const DayCounter &)
CPILeg & withObservationInterpolation(CPI::InterpolationType)
Serializable object holding generic trade data, reporting dimensions.
Serializable object holding leg data.
static const string defaultConfiguration
Default configuration label.
map< tuple< string, YieldCurveType, string >, Handle< YieldTermStructure > > yieldCurves_
map< pair< string, string >, Handle< IborIndex > > iborIndices_
map< pair< string, string >, Handle< ZeroInflationIndex > > zeroInflationIndices_
Serializable schedule data.
Serializable object holding schedule Rules data.
Serializable Swap, Single and Cross Currency.
BOOST_AUTO_TEST_CASE(testCPISwapPrice)
A class to hold pricing engine parameters.
QuantLib::ext::shared_ptr< ZeroInflationIndex > parseZeroInflationIndex(const string &s, const Handle< ZeroInflationTermStructure > &h)
Convert std::string to QuantLib::ZeroInflationIndex.
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h)
Convert std::string to QuantLib::IborIndex.
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
An implementation of the Market class that stores the required objects in maps.
Swap trade data model and serialization.