1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2003 RiskMap srl
5 Copyright (C) 2004, 2005, 2006, 2007, 2008 StatPro Italia srl
6 Copyright (C) 2009 Chris Kenyon
7
8 This file is part of QuantLib, a free-software/open-source library
9 for financial quantitative analysts and developers - http://quantlib.org/
10
11 QuantLib is free software: you can redistribute it and/or modify it
12 under the terms of the QuantLib license. You should have received a
13 copy of the license along with this program; if not, please email
14 <quantlib-dev@lists.sf.net>. The license is also available online at
15 <http://quantlib.org/license.shtml>.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the license for more details.
20 */
21
22#include "inflationcapfloor.hpp"
23#include "utilities.hpp"
24#include <ql/cashflows/cashflows.hpp>
25#include <ql/cashflows/cashflowvectors.hpp>
26#include <ql/cashflows/inflationcouponpricer.hpp>
27#include <ql/cashflows/yoyinflationcoupon.hpp>
28#include <ql/indexes/inflation/euhicp.hpp>
29#include <ql/indexes/inflation/ukrpi.hpp>
30#include <ql/instruments/inflationcapfloor.hpp>
31#include <ql/instruments/vanillaswap.hpp>
32#include <ql/math/matrix.hpp>
33#include <ql/models/marketmodels/correlations/expcorrelations.hpp>
34#include <ql/models/marketmodels/models/flatvol.hpp>
35#include <ql/pricingengines/blackformula.hpp>
36#include <ql/pricingengines/inflation/inflationcapfloorengines.hpp>
37#include <ql/pricingengines/swap/discountingswapengine.hpp>
38#include <ql/quotes/simplequote.hpp>
39#include <ql/termstructures/inflation/inflationhelpers.hpp>
40#include <ql/termstructures/inflation/piecewiseyoyinflationcurve.hpp>
41#include <ql/termstructures/volatility/inflation/yoyinflationoptionletvolatilitystructure.hpp>
42#include <ql/termstructures/yield/flatforward.hpp>
43#include <ql/time/calendars/unitedkingdom.hpp>
44#include <ql/time/daycounters/actual360.hpp>
45#include <ql/time/daycounters/actualactual.hpp>
46#include <ql/time/daycounters/thirty360.hpp>
47#include <ql/time/schedule.hpp>
48#include <ql/utilities/dataformatters.hpp>
49
50using namespace QuantLib;
51using namespace boost::unit_test_framework;
52
53using std::fabs;
54
55namespace inflation_capfloor_test {
56
57 struct Datum {
58 Date date;
59 Rate rate;
60 };
61
62 template <class T, class U, class I>
63 std::vector<ext::shared_ptr<BootstrapHelper<T> > > makeHelpers(
64 const std::vector<Datum>& iiData,
65 const ext::shared_ptr<I> &ii, const Period &observationLag,
66 const Calendar &calendar,
67 const BusinessDayConvention &bdc,
68 const DayCounter &dc,
69 const Handle<YieldTermStructure>& discountCurve) {
70
71 std::vector<ext::shared_ptr<BootstrapHelper<T> > > instruments;
72 for (Datum datum : iiData) {
73 Date maturity = datum.date;
74 Handle<Quote> quote(ext::shared_ptr<Quote>(
75 new SimpleQuote(datum.rate/100.0)));
76 ext::shared_ptr<BootstrapHelper<T> > anInstrument(new U(
77 quote, observationLag, maturity,
78 calendar, bdc, dc, ii, discountCurve));
79 instruments.push_back(anInstrument);
80 }
81
82 return instruments;
83 }
84
85
86 struct CommonVars {
87 // common data
88
89 Frequency frequency;
90 std::vector<Real> nominals;
91 Calendar calendar;
92 BusinessDayConvention convention;
93 Natural fixingDays;
94 Date evaluationDate;
95 Natural settlementDays;
96 Date settlement;
97 Period observationLag;
98 DayCounter dc;
99 ext::shared_ptr<YoYInflationIndex> iir;
100
101 RelinkableHandle<YieldTermStructure> nominalTS;
102 ext::shared_ptr<YoYInflationTermStructure> yoyTS;
103 RelinkableHandle<YoYInflationTermStructure> hy;
104
105 // setup
106 CommonVars()
107 : nominals(1,1000000) {
108 // option variables
109 frequency = Annual;
110 // usual setup
111 calendar = UnitedKingdom();
112 convention = ModifiedFollowing;
113 Date today(13, August, 2007);
114 evaluationDate = calendar.adjust(today);
115 Settings::instance().evaluationDate() = evaluationDate;
116 settlementDays = 0;
117 fixingDays = 0;
118 settlement = calendar.advance(today,n: settlementDays,unit: Days);
119 dc = Thirty360(Thirty360::BondBasis);
120
121 // yoy index
122 // fixing data
123 Date from(1, January, 2005);
124 Date to(13, August, 2007);
125 Schedule rpiSchedule = MakeSchedule().from(effectiveDate: from).to(terminationDate: to)
126 .withTenor(1*Months)
127 .withCalendar(UnitedKingdom())
128 .withConvention(ModifiedFollowing);
129 Real fixData[] = { 189.9, 189.9, 189.6, 190.5, 191.6, 192.0,
130 192.2, 192.2, 192.6, 193.1, 193.3, 193.6,
131 194.1, 193.4, 194.2, 195.0, 196.5, 197.7,
132 198.5, 198.5, 199.2, 200.1, 200.4, 201.1,
133 202.7, 201.6, 203.1, 204.4, 205.4, 206.2,
134 207.3, -999.0, -999 };
135 auto rpi = ext::make_shared<UKRPI>();
136 for (Size i=0; i<rpiSchedule.size();i++) {
137 rpi->addFixing(fixingDate: rpiSchedule[i], fixing: fixData[i]);
138 }
139 // link from yoy index to yoy TS
140 bool interp = false;
141 iir = ext::make_shared<YoYInflationIndex>(args&: rpi, args&: interp, args&: hy);
142
143 ext::shared_ptr<YieldTermStructure> nominalFF(
144 new FlatForward(evaluationDate, 0.05, ActualActual(ActualActual::ISDA)));
145 nominalTS.linkTo(h: nominalFF);
146
147 // now build the YoY inflation curve
148 Period observationLag = Period(2,Months);
149
150 std::vector<Datum> yyData = {
151 { .date: Date(13, August, 2008), .rate: 2.95 },
152 { .date: Date(13, August, 2009), .rate: 2.95 },
153 { .date: Date(13, August, 2010), .rate: 2.93 },
154 { .date: Date(15, August, 2011), .rate: 2.955 },
155 { .date: Date(13, August, 2012), .rate: 2.945 },
156 { .date: Date(13, August, 2013), .rate: 2.985 },
157 { .date: Date(13, August, 2014), .rate: 3.01 },
158 { .date: Date(13, August, 2015), .rate: 3.035 },
159 { .date: Date(13, August, 2016), .rate: 3.055 }, // note that
160 { .date: Date(13, August, 2017), .rate: 3.075 }, // some dates will be on
161 { .date: Date(13, August, 2019), .rate: 3.105 }, // holidays but the payment
162 { .date: Date(15, August, 2022), .rate: 3.135 }, // calendar will roll them
163 { .date: Date(13, August, 2027), .rate: 3.155 },
164 { .date: Date(13, August, 2032), .rate: 3.145 },
165 { .date: Date(13, August, 2037), .rate: 3.145 }
166 };
167
168 // now build the helpers ...
169 std::vector<ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure> > > helpers =
170 makeHelpers<YoYInflationTermStructure,YearOnYearInflationSwapHelper,
171 YoYInflationIndex>(iiData: yyData, ii: iir,
172 observationLag,
173 calendar, bdc: convention, dc,
174 discountCurve: Handle<YieldTermStructure>(nominalTS));
175
176 Rate baseYYRate = yyData[0].rate/100.0;
177 ext::shared_ptr<PiecewiseYoYInflationCurve<Linear> > pYYTS(
178 new PiecewiseYoYInflationCurve<Linear>(
179 evaluationDate, calendar, dc, observationLag,
180 iir->frequency(),iir->interpolated(), baseYYRate,
181 helpers));
182 pYYTS->recalculate();
183 yoyTS = ext::dynamic_pointer_cast<YoYInflationTermStructure>(r: pYYTS);
184
185
186 // make sure that the index has the latest yoy term structure
187 hy.linkTo(h: pYYTS);
188 }
189
190 // utilities
191 Leg makeYoYLeg(const Date& startDate, Integer length) const {
192 ext::shared_ptr<YoYInflationIndex> ii =
193 ext::dynamic_pointer_cast<YoYInflationIndex>(r: iir);
194 Date endDate = calendar.advance(date: startDate,period: length*Years,convention: Unadjusted);
195 Schedule schedule(startDate, endDate, Period(frequency), calendar,
196 Unadjusted,Unadjusted,// ref periods & acc periods
197 DateGeneration::Forward, false);
198 return yoyInflationLeg(schedule, calendar, ii, observationLag)
199 .withNotionals(notionals: nominals)
200 .withPaymentDayCounter(dc)
201 .withPaymentAdjustment(convention);
202 }
203
204
205 ext::shared_ptr<PricingEngine> makeEngine(Volatility volatility, Size which) const {
206
207 ext::shared_ptr<YoYInflationIndex>
208 yyii = ext::dynamic_pointer_cast<YoYInflationIndex>(r: iir);
209
210 Handle<YoYOptionletVolatilitySurface>
211 vol(ext::make_shared<ConstantYoYOptionletVolatility>(
212 args&: volatility,
213 args: settlementDays,
214 args: calendar,
215 args: convention,
216 args: dc,
217 args: observationLag,
218 args: frequency,
219 args: iir->interpolated()));
220
221
222 switch (which) {
223 case 0:
224 return ext::shared_ptr<PricingEngine>(
225 new YoYInflationBlackCapFloorEngine(iir, vol, nominalTS));
226 break;
227 case 1:
228 return ext::shared_ptr<PricingEngine>(
229 new YoYInflationUnitDisplacedBlackCapFloorEngine(iir, vol, nominalTS));
230 break;
231 case 2:
232 return ext::shared_ptr<PricingEngine>(
233 new YoYInflationBachelierCapFloorEngine(iir, vol, nominalTS));
234 break;
235 default:
236 BOOST_FAIL("unknown engine request: which = "<<which
237 <<"should be 0=Black,1=DD,2=Bachelier");
238 break;
239 }
240 // make compiler happy
241 QL_FAIL("never get here - no engine resolution");
242 }
243
244
245 ext::shared_ptr<YoYInflationCapFloor> makeYoYCapFloor(YoYInflationCapFloor::Type type,
246 const Leg& leg,
247 Rate strike,
248 Volatility volatility,
249 Size which) const {
250 ext::shared_ptr<YoYInflationCapFloor> result;
251 switch (type) {
252 case YoYInflationCapFloor::Cap:
253 result = ext::shared_ptr<YoYInflationCapFloor>(
254 new YoYInflationCap(leg, std::vector<Rate>(1, strike)));
255 break;
256 case YoYInflationCapFloor::Floor:
257 result = ext::shared_ptr<YoYInflationCapFloor>(
258 new YoYInflationFloor(leg, std::vector<Rate>(1, strike)));
259 break;
260 default:
261 QL_FAIL("unknown YoYInflation cap/floor type");
262 }
263 result->setPricingEngine(makeEngine(volatility, which));
264 return result;
265 }
266 };
267
268}
269
270
271
272void InflationCapFloorTest::testConsistency() {
273
274 BOOST_TEST_MESSAGE("Testing consistency between yoy inflation cap,"
275 " floor and collar...");
276
277 using namespace inflation_capfloor_test;
278
279 CommonVars vars;
280
281 Integer lengths[] = { 1, 2, 3, 5, 7, 10, 15, 20 };
282 Rate cap_rates[] = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 };
283 Rate floor_rates[] = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 };
284 Volatility vols[] = { 0.001, 0.005, 0.010, 0.015, 0.020 };
285
286 for (Size whichPricer = 0; whichPricer < 3; whichPricer++) {
287 for (int& length : lengths) {
288 for (Real& cap_rate : cap_rates) {
289 for (Real& floor_rate : floor_rates) {
290 for (Real vol : vols) {
291
292 Leg leg = vars.makeYoYLeg(startDate: vars.evaluationDate, length);
293
294 ext::shared_ptr<YoYInflationCapFloor> cap = vars.makeYoYCapFloor(
295 type: YoYInflationCapFloor::Cap, leg, strike: cap_rate, volatility: vol, which: whichPricer);
296
297 ext::shared_ptr<YoYInflationCapFloor> floor = vars.makeYoYCapFloor(
298 type: YoYInflationCapFloor::Floor, leg, strike: floor_rate, volatility: vol, which: whichPricer);
299
300 YoYInflationCollar collar(leg, std::vector<Rate>(1, cap_rate),
301 std::vector<Rate>(1, floor_rate));
302 collar.setPricingEngine(vars.makeEngine(volatility: vol, which: whichPricer));
303
304 if (std::fabs(x: (cap->NPV() - floor->NPV()) - collar.NPV()) > 1e-6) {
305 BOOST_FAIL("inconsistency between cap, floor and collar:\n"
306 << " length: " << length << " years\n"
307 << " volatility: " << io::volatility(vol) << "\n"
308 << " cap value: " << cap->NPV()
309 << " at strike: " << io::rate(cap_rate) << "\n"
310 << " floor value: " << floor->NPV()
311 << " at strike: " << io::rate(floor_rate) << "\n"
312 << " collar value: " << collar.NPV());
313
314
315 // test re-composition by optionlets, N.B. ONE per year
316 Real capletsNPV = 0.0;
317 std::vector<ext::shared_ptr<YoYInflationCapFloor> > caplets;
318 for (Integer m = 0; m < length * 1; m++) {
319 caplets.push_back(x: cap->optionlet(n: m));
320 caplets[m]->setPricingEngine(vars.makeEngine(volatility: vol, which: whichPricer));
321 capletsNPV += caplets[m]->NPV();
322 }
323
324 if (std::fabs(x: cap->NPV() - capletsNPV) > 1e-6) {
325 BOOST_FAIL("sum of caplet NPVs does not equal cap NPV:\n"
326 << " length: " << length << " years\n"
327 << " volatility: " << io::volatility(vol) << "\n"
328 << " cap value: " << cap->NPV()
329 << " at strike: " << io::rate(cap_rate) << "\n"
330 << " sum of caplets value: " << capletsNPV
331 << " at strike (first): "
332 << io::rate(caplets[0]->capRates()[0]) << "\n");
333 }
334
335 Real floorletsNPV = 0.0;
336 std::vector<ext::shared_ptr<YoYInflationCapFloor> > floorlets;
337 for (Integer m = 0; m < length * 1; m++) {
338 floorlets.push_back(x: floor->optionlet(n: m));
339 floorlets[m]->setPricingEngine(vars.makeEngine(volatility: vol, which: whichPricer));
340 floorletsNPV += floorlets[m]->NPV();
341 }
342
343 if (std::fabs(x: floor->NPV() - floorletsNPV) > 1e-6) {
344 BOOST_FAIL("sum of floorlet NPVs does not equal floor NPV:\n"
345 << " length: " << length << " years\n"
346 << " volatility: " << io::volatility(vol) << "\n"
347 << " cap value: " << floor->NPV()
348 << " at strike: " << io::rate(floor_rate) << "\n"
349 << " sum of floorlets value: " << floorletsNPV
350 << " at strike (first): "
351 << io::rate(floorlets[0]->floorRates()[0]) << "\n");
352 }
353
354 Real collarletsNPV = 0.0;
355 std::vector<ext::shared_ptr<YoYInflationCapFloor> > collarlets;
356 for (Integer m = 0; m < length * 1; m++) {
357 collarlets.push_back(x: collar.optionlet(n: m));
358 collarlets[m]->setPricingEngine(vars.makeEngine(volatility: vol, which: whichPricer));
359 collarletsNPV += collarlets[m]->NPV();
360 }
361
362 if (std::fabs(x: collar.NPV() - collarletsNPV) > 1e-6) {
363 BOOST_FAIL("sum of collarlet NPVs does not equal collar NPV:\n"
364 << " length: " << length << " years\n"
365 << " volatility: " << io::volatility(vol) << "\n"
366 << " cap value: " << collar.NPV()
367 << " at strike floor: " << io::rate(floor_rate)
368 << " at strike cap: " << io::rate(cap_rate) << "\n"
369 << " sum of collarlets value: " << collarletsNPV
370 << " at strike floor (first): "
371 << io::rate(collarlets[0]->floorRates()[0])
372 << " at strike cap (first): "
373 << io::rate(collarlets[0]->capRates()[0]) << "\n");
374 }
375 }
376 }
377 }
378 }
379 }
380 } // pricer loop
381 // remove circular refernce
382 vars.hy.linkTo(h: ext::shared_ptr<YoYInflationTermStructure>());
383}
384
385
386// Test inflation cap/floor parity, i.e. that cap-floor = swap, note that this
387// is different from nominal because in nominal world standard cap/floors do
388// not have the first optionlet. This is because they set in advance so
389// there is no point. However, yoy inflation generally sets in arrears,
390// (actually in arrears with a lag of a few months) thus the first optionlet
391// is relevant. Hence we can do a parity test without a special definition
392// of the YoY cap/floor instrument.
393void InflationCapFloorTest::testParity() {
394
395 BOOST_TEST_MESSAGE("Testing yoy inflation cap/floor parity...");
396
397 using namespace inflation_capfloor_test;
398
399 CommonVars vars;
400
401 Integer lengths[] = { 1, 2, 3, 5, 7, 10, 15, 20 };
402 // vol is low ...
403 Rate strikes[] = { 0., 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 };
404 // yoy inflation vol is generally very low
405 Volatility vols[] = { 0.001, 0.005, 0.010, 0.015, 0.020 };
406
407 // cap-floor-swap parity is model-independent
408 for (Size whichPricer = 0; whichPricer < 3; whichPricer++) {
409 for (int& length : lengths) {
410 for (Real strike : strikes) {
411 for (Real vol : vols) {
412
413 Leg leg = vars.makeYoYLeg(startDate: vars.evaluationDate, length);
414
415 ext::shared_ptr<Instrument> cap = vars.makeYoYCapFloor(
416 type: YoYInflationCapFloor::Cap, leg, strike, volatility: vol, which: whichPricer);
417
418 ext::shared_ptr<Instrument> floor = vars.makeYoYCapFloor(
419 type: YoYInflationCapFloor::Floor, leg, strike, volatility: vol, which: whichPricer);
420
421 Date from = vars.nominalTS->referenceDate();
422 Date to = from + length * Years;
423 Schedule yoySchedule = MakeSchedule().from(effectiveDate: from).to(terminationDate: to)
424 .withTenor(1*Years)
425 .withCalendar(UnitedKingdom())
426 .withConvention(Unadjusted)
427 .backwards()
428 ;
429
430 YearOnYearInflationSwap swap(Swap::Payer, 1000000.0,
431 yoySchedule, // fixed schedule, but same as yoy
432 strike, vars.dc, yoySchedule, vars.iir,
433 vars.observationLag,
434 0.0, // spread on index
435 vars.dc, UnitedKingdom());
436
437 Handle<YieldTermStructure> hTS(vars.nominalTS);
438 ext::shared_ptr<PricingEngine> sppe(new DiscountingSwapEngine(hTS));
439 swap.setPricingEngine(sppe);
440
441 // N.B. nominals are 10e6
442 if (std::fabs(x: (cap->NPV()-floor->NPV()) - swap.NPV()) > 1.0e-6) {
443 BOOST_FAIL("put/call parity violated:\n"
444 << " length: " << length << " years\n"
445 << " volatility: " << io::volatility(vol) << "\n"
446 << " strike: " << io::rate(strike) << "\n"
447 << " cap value: " << cap->NPV() << "\n"
448 << " floor value: " << floor->NPV() << "\n"
449 << " swap value: " << swap.NPV());
450 }
451 }
452 }
453 }
454 }
455 // remove circular refernce
456 vars.hy.linkTo(h: ext::shared_ptr<YoYInflationTermStructure>());
457}
458
459
460
461
462void InflationCapFloorTest::testCachedValue() {
463
464 BOOST_TEST_MESSAGE("Testing Black yoy inflation cap/floor price"
465 " against cached values...");
466
467 using namespace inflation_capfloor_test;
468
469 CommonVars vars;
470
471 Size whichPricer = 0; // black
472
473 Real K = 0.0295; // one centi-point is fair rate error i.e. < 1 cp
474 Size j = 2;
475 Leg leg = vars.makeYoYLeg(startDate: vars.evaluationDate,length: j);
476 ext::shared_ptr<Instrument> cap
477 = vars.makeYoYCapFloor(type: YoYInflationCapFloor::Cap,leg, strike: K, volatility: 0.01, which: whichPricer);
478
479 ext::shared_ptr<Instrument> floor
480 = vars.makeYoYCapFloor(type: YoYInflationCapFloor::Floor,leg, strike: K, volatility: 0.01, which: whichPricer);
481
482
483 // close to atm prices
484 Real cachedCapNPVblack = 219.452;
485 Real cachedFloorNPVblack = 314.641;
486 // N.B. notionals are 10e6.
487 BOOST_CHECK_MESSAGE(fabs(cap->NPV()-cachedCapNPVblack)<0.02,"yoy cap cached NPV wrong "
488 <<cap->NPV()<<" should be "<<cachedCapNPVblack<<" Black pricer"
489 <<" diff was "<<(fabs(cap->NPV()-cachedCapNPVblack)));
490 BOOST_CHECK_MESSAGE(fabs(floor->NPV()-cachedFloorNPVblack)<0.02,"yoy floor cached NPV wrong "
491 <<floor->NPV()<<" should be "<<cachedFloorNPVblack<<" Black pricer"
492 <<" diff was "<<(fabs(floor->NPV()-cachedFloorNPVblack)));
493
494 whichPricer = 1; // dd
495
496 cap
497 = vars.makeYoYCapFloor(type: YoYInflationCapFloor::Cap,leg, strike: K, volatility: 0.01, which: whichPricer);
498
499 floor
500 = vars.makeYoYCapFloor(type: YoYInflationCapFloor::Floor,leg, strike: K, volatility: 0.01, which: whichPricer);
501
502 // close to atm prices
503 Real cachedCapNPVdd = 9114.61;
504 Real cachedFloorNPVdd = 9209.8;
505 // N.B. notionals are 10e6.
506 BOOST_CHECK_MESSAGE(fabs(cap->NPV()-cachedCapNPVdd)<0.22,"yoy cap cached NPV wrong "
507 <<cap->NPV()<<" should be "<<cachedCapNPVdd<<" dd Black pricer"
508 <<" diff was "<<(fabs(cap->NPV()-cachedCapNPVdd)));
509 BOOST_CHECK_MESSAGE(fabs(floor->NPV()-cachedFloorNPVdd)<0.22,"yoy floor cached NPV wrong "
510 <<floor->NPV()<<" should be "<<cachedFloorNPVdd<<" dd Black pricer"
511 <<" diff was "<<(fabs(floor->NPV()-cachedFloorNPVdd)));
512
513 whichPricer = 2; // bachelier
514
515 cap
516 = vars.makeYoYCapFloor(type: YoYInflationCapFloor::Cap,leg, strike: K, volatility: 0.01, which: whichPricer);
517
518 floor
519 = vars.makeYoYCapFloor(type: YoYInflationCapFloor::Floor,leg, strike: K, volatility: 0.01, which: whichPricer);
520
521 // close to atm prices
522 Real cachedCapNPVbac = 8852.4;
523 Real cachedFloorNPVbac = 8947.59;
524 // N.B. notionals are 10e6.
525 BOOST_CHECK_MESSAGE(fabs(cap->NPV()-cachedCapNPVbac)<0.22,"yoy cap cached NPV wrong "
526 <<cap->NPV()<<" should be "<<cachedCapNPVbac<<" bac Black pricer"
527 <<" diff was "<<(fabs(cap->NPV()-cachedCapNPVbac)));
528 BOOST_CHECK_MESSAGE(fabs(floor->NPV()-cachedFloorNPVbac)<0.22,"yoy floor cached NPV wrong "
529 <<floor->NPV()<<" should be "<<cachedFloorNPVbac<<" bac Black pricer"
530 <<" diff was "<<(fabs(floor->NPV()-cachedFloorNPVbac)));
531
532 // remove circular refernce
533 vars.hy.linkTo(h: ext::shared_ptr<YoYInflationTermStructure>());
534}
535
536
537test_suite* InflationCapFloorTest::suite() {
538 auto* suite = BOOST_TEST_SUITE("Inflation (year-on-year) Cap and floor tests");
539 suite->add(QUANTLIB_TEST_CASE(&InflationCapFloorTest::testConsistency));
540 suite->add(QUANTLIB_TEST_CASE(&InflationCapFloorTest::testParity));
541 suite->add(QUANTLIB_TEST_CASE(&InflationCapFloorTest::testCachedValue));
542 return suite;
543}
544
545
546

source code of quantlib/test-suite/inflationcapfloor.cpp