| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2009 Chris Kenyon |
| 5 | |
| 6 | This file is part of QuantLib, a free-software/open-source library |
| 7 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 8 | |
| 9 | QuantLib is free software: you can redistribute it and/or modify it |
| 10 | under the terms of the QuantLib license. You should have received a |
| 11 | copy of the license along with this program; if not, please email |
| 12 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 13 | <http://quantlib.org/license.shtml>. |
| 14 | |
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 17 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 18 | */ |
| 19 | |
| 20 | #include "inflationvolatility.hpp" |
| 21 | #include "utilities.hpp" |
| 22 | |
| 23 | #include <ql/math/interpolations/cubicinterpolation.hpp> |
| 24 | #include <ql/math/interpolations/bicubicsplineinterpolation.hpp> |
| 25 | #include <ql/termstructures/yield/zerocurve.hpp> |
| 26 | #include <ql/termstructures/inflation/interpolatedyoyinflationcurve.hpp> |
| 27 | |
| 28 | #include <ql/cashflows/inflationcoupon.hpp> |
| 29 | #include <ql/cashflows/inflationcouponpricer.hpp> |
| 30 | |
| 31 | #include <ql/experimental/inflation/yoycapfloortermpricesurface.hpp> |
| 32 | #include <ql/pricingengines/inflation/inflationcapfloorengines.hpp> |
| 33 | #include <ql/experimental/inflation/yoyoptionletstripper.hpp> |
| 34 | |
| 35 | #include <ql/experimental/inflation/kinterpolatedyoyoptionletvolatilitysurface.hpp> |
| 36 | #include <ql/experimental/inflation/interpolatedyoyoptionletstripper.hpp> |
| 37 | |
| 38 | #include <ql/cashflows/capflooredinflationcoupon.hpp> |
| 39 | #include <ql/indexes/inflation/euhicp.hpp> |
| 40 | #include <ql/indexes/inflation/ukrpi.hpp> |
| 41 | |
| 42 | #include <iostream> |
| 43 | |
| 44 | |
| 45 | // local namespace for data |
| 46 | //************************************************************************* |
| 47 | namespace inflation_volatility_test { |
| 48 | |
| 49 | using namespace QuantLib; |
| 50 | |
| 51 | // local data globals |
| 52 | Handle<YieldTermStructure> nominalEUR; |
| 53 | Handle<YieldTermStructure> nominalGBP; |
| 54 | |
| 55 | RelinkableHandle<YoYInflationTermStructure> yoyEU; |
| 56 | RelinkableHandle<YoYInflationTermStructure> yoyUK; |
| 57 | |
| 58 | std::vector<Rate> cStrikesEU; |
| 59 | std::vector<Rate> fStrikesEU; |
| 60 | std::vector<Period> cfMaturitiesEU; |
| 61 | ext::shared_ptr<Matrix> cPriceEU; |
| 62 | ext::shared_ptr<Matrix> fPriceEU; |
| 63 | |
| 64 | ext::shared_ptr<YoYInflationIndex> yoyIndexUK; |
| 65 | ext::shared_ptr<YoYInflationIndex> yoyIndexEU; |
| 66 | |
| 67 | std::vector<Rate> cStrikesUK; |
| 68 | std::vector<Rate> fStrikesUK; |
| 69 | std::vector<Period> cfMaturitiesUK; |
| 70 | ext::shared_ptr<Matrix> cPriceUK; |
| 71 | ext::shared_ptr<Matrix> fPriceUK; |
| 72 | |
| 73 | ext::shared_ptr<InterpolatedYoYCapFloorTermPriceSurface<Bicubic,Cubic> > priceSurfEU; |
| 74 | |
| 75 | void reset() { |
| 76 | nominalEUR = Handle<YieldTermStructure>(); |
| 77 | nominalGBP = Handle<YieldTermStructure>(); |
| 78 | priceSurfEU.reset(); |
| 79 | yoyEU.linkTo(h: ext::shared_ptr<YoYInflationTermStructure>()); |
| 80 | yoyUK.linkTo(h: ext::shared_ptr<YoYInflationTermStructure>()); |
| 81 | yoyIndexUK.reset(); |
| 82 | yoyIndexEU.reset(); |
| 83 | cPriceEU.reset(); |
| 84 | fPriceEU.reset(); |
| 85 | cPriceUK.reset(); |
| 86 | fPriceUK.reset(); |
| 87 | yoyIndexUK.reset(); |
| 88 | |
| 89 | cStrikesEU.clear(); |
| 90 | fStrikesEU.clear(); |
| 91 | cStrikesUK.clear(); |
| 92 | fStrikesUK.clear(); |
| 93 | cfMaturitiesEU.clear(); |
| 94 | cfMaturitiesUK.clear(); |
| 95 | } |
| 96 | |
| 97 | void setup() { |
| 98 | |
| 99 | // make sure of the evaluation date |
| 100 | Date eval = Date(Day(23), Month(11), Year(2007)); |
| 101 | Settings::instance().evaluationDate() = eval; |
| 102 | |
| 103 | yoyIndexUK = ext::make_shared<YoYInflationIndex>(args: ext::make_shared<UKRPI>(), args: true, args&: yoyUK); |
| 104 | yoyIndexEU = ext::make_shared<YoYInflationIndex>(args: ext::make_shared<EUHICP>(), args: true, args&: yoyEU); |
| 105 | |
| 106 | // nominal yield curve (interpolated; times assume year parts have 365 days) |
| 107 | Real timesEUR[] = {0.0109589, 0.0684932, 0.263014, 0.317808, 0.567123, 0.816438, |
| 108 | 1.06575, 1.31507, 1.56438, 2.0137, 3.01918, 4.01644, |
| 109 | 5.01644, 6.01644, 7.01644, 8.01644, 9.02192, 10.0192, |
| 110 | 12.0192, 15.0247, 20.0301, 25.0356, 30.0329, 40.0384, |
| 111 | 50.0466}; |
| 112 | Real ratesEUR[] = {0.0415600, 0.0426840, 0.0470980, 0.0458506, 0.0449550, 0.0439784, |
| 113 | 0.0431887, 0.0426604, 0.0422925, 0.0424591, 0.0421477, 0.0421853, |
| 114 | 0.0424016, 0.0426969, 0.0430804, 0.0435011, 0.0439368, 0.0443825, |
| 115 | 0.0452589, 0.0463389, 0.0472636, 0.0473401, 0.0470629, 0.0461092, |
| 116 | 0.0450794}; |
| 117 | |
| 118 | Real timesGBP[] = {0.008219178, 0.010958904, 0.01369863, 0.019178082, 0.073972603, |
| 119 | 0.323287671, 0.57260274, 0.821917808, 1.071232877, 1.320547945, |
| 120 | 1.506849315, 2.002739726, 3.002739726, 4.002739726, 5.005479452, |
| 121 | 6.010958904, 7.008219178, 8.005479452, 9.008219178, 10.00821918, |
| 122 | 12.01369863, 15.0109589, 20.01369863, 25.01917808, 30.02191781, |
| 123 | 40.03287671, 50.03561644, 60.04109589, 70.04931507}; |
| 124 | Real ratesGBP[] = {0.0577363, 0.0582314, 0.0585265, 0.0587165, 0.0596598, |
| 125 | 0.0612506, 0.0589676, 0.0570512, 0.0556147, 0.0546082, |
| 126 | 0.0549492, 0.053801, 0.0529333, 0.0524068, 0.0519712, |
| 127 | 0.0516615, 0.0513711, 0.0510433, 0.0507974, 0.0504833, |
| 128 | 0.0498998, 0.0490464, 0.04768, 0.0464862, 0.045452, |
| 129 | 0.0437699, 0.0425311, 0.0420073, 0.041151}; |
| 130 | |
| 131 | std::vector <Real> r; |
| 132 | std::vector <Date> d; |
| 133 | Size nTimesEUR = LENGTH(timesEUR); |
| 134 | Size nTimesGBP = LENGTH(timesGBP); |
| 135 | for (Size i = 0; i < nTimesEUR; i++) { |
| 136 | r.push_back(x: ratesEUR[i]); |
| 137 | Size ys = (Size)floor(x: timesEUR[i]); |
| 138 | Size ds = (Size)((timesEUR[i]-(Real)ys)*365); |
| 139 | Date dd = eval + Period(ys,Years) + Period(ds,Days); |
| 140 | d.push_back( x: dd ); |
| 141 | } |
| 142 | |
| 143 | ext::shared_ptr<InterpolatedZeroCurve<Cubic> > |
| 144 | euriborTS(new InterpolatedZeroCurve<Cubic>(d, r, Actual365Fixed())); |
| 145 | Handle<YieldTermStructure> nominalHeur(euriborTS, false); |
| 146 | nominalEUR = nominalHeur; // copy to global |
| 147 | |
| 148 | d.clear(); |
| 149 | r.clear(); |
| 150 | for (Size i = 0; i < nTimesGBP; i++) { |
| 151 | r.push_back(x: ratesGBP[i]); |
| 152 | Size ys = (Size)floor(x: timesGBP[i]); |
| 153 | Size ds = (Size)((timesGBP[i]-(Real)ys)*365); |
| 154 | Date dd = eval + Period(ys,Years) + Period(ds,Days); |
| 155 | d.push_back( x: dd ); |
| 156 | } |
| 157 | |
| 158 | ext::shared_ptr<InterpolatedZeroCurve<Cubic> > |
| 159 | gbpLiborTS(new InterpolatedZeroCurve<Cubic>(d, r, Actual365Fixed())); |
| 160 | Handle<YieldTermStructure> nominalHgbp(gbpLiborTS, false); |
| 161 | nominalGBP = nominalHgbp; // copy to global |
| 162 | |
| 163 | // times = years - lag, where the lag is 2 months or 2/12 |
| 164 | // because this data is derived from cap/floor data that |
| 165 | // is based on a 2 month lag. |
| 166 | |
| 167 | // note that these are NOT swap rates |
| 168 | // also not that the first value MUST be in the base period |
| 169 | // i.e. the first rate is for a negative time |
| 170 | Real yoyEUrates[] = {0.0237951, |
| 171 | 0.0238749, 0.0240334, 0.0241934, 0.0243567, 0.0245323, |
| 172 | 0.0247213, 0.0249348, 0.0251768, 0.0254337, 0.0257258, |
| 173 | 0.0260217, 0.0263006, 0.0265538, 0.0267803, 0.0269378, |
| 174 | 0.0270608, 0.0271363, 0.0272, 0.0272512, 0.0272927, |
| 175 | 0.027317, 0.0273615, 0.0273811, 0.0274063, 0.0274307, |
| 176 | 0.0274625, 0.027527, 0.0275952, 0.0276734, 0.027794}; |
| 177 | |
| 178 | d.clear(); |
| 179 | r.clear(); |
| 180 | Date baseDate = TARGET().advance(eval, n: -2, unit: Months, convention: ModifiedFollowing); |
| 181 | for (Size i = 0; i < LENGTH(yoyEUrates); i++) { |
| 182 | Date dd = TARGET().advance(baseDate, n: i, unit: Years, convention: ModifiedFollowing); |
| 183 | d.push_back(x: dd); |
| 184 | r.push_back(x: yoyEUrates[i]); |
| 185 | } |
| 186 | |
| 187 | bool indexIsInterpolated = true; // actually false for UKRPI but smooth surfaces are |
| 188 | // better for finding intersections etc |
| 189 | |
| 190 | ext::shared_ptr<InterpolatedYoYInflationCurve<Linear> > |
| 191 | pYTSEU( new InterpolatedYoYInflationCurve<Linear>( |
| 192 | eval, TARGET(), Actual365Fixed(), Period(2,Months), Monthly, |
| 193 | indexIsInterpolated, d, r) ); |
| 194 | yoyEU.linkTo(h: pYTSEU); |
| 195 | |
| 196 | // price data |
| 197 | const Size ncStrikesEU = 6; |
| 198 | const Size nfStrikesEU = 6; |
| 199 | const Size ncfMaturitiesEU = 7; |
| 200 | Real capStrikesEU[ncStrikesEU] = {0.02, 0.025, 0.03, 0.035, 0.04, 0.05}; |
| 201 | Period capMaturitiesEU[ncfMaturitiesEU] = {3*Years, 5*Years, 7*Years, |
| 202 | 10*Years, 15*Years, 20*Years, 30*Years}; |
| 203 | Real capPricesEU[ncStrikesEU][ncfMaturitiesEU] = |
| 204 | {{116.225, 204.945, 296.285, 434.29, 654.47, 844.775, 1132.33}, |
| 205 | {34.305, 71.575, 114.1, 184.33, 307.595, 421.395, 602.35}, |
| 206 | {6.37, 19.085, 35.635, 66.42, 127.69, 189.685, 296.195}, |
| 207 | {1.325, 5.745, 12.585, 26.945, 58.95, 94.08, 158.985}, |
| 208 | {0.501, 2.37, 5.38, 13.065, 31.91, 53.95, 96.97}, |
| 209 | {0.501, 0.695, 1.47, 4.415, 12.86, 23.75, 46.7}}; |
| 210 | |
| 211 | Real floorStrikesEU[nfStrikesEU] = {-0.01, 0.00, 0.005, 0.01, 0.015, 0.02}; |
| 212 | Real floorPricesEU[nfStrikesEU][ncfMaturitiesEU] = |
| 213 | {{0.501, 0.851, 2.44, 6.645, 16.23, 26.85, 46.365}, |
| 214 | {0.501, 2.236, 5.555, 13.075, 28.46, 44.525, 73.08}, |
| 215 | {1.025, 3.935, 9.095, 19.64, 39.93, 60.375, 96.02}, |
| 216 | {2.465, 7.885, 16.155, 31.6, 59.34, 86.21, 132.045}, |
| 217 | {6.9, 17.92, 32.085, 56.08, 95.95, 132.85, 194.18}, |
| 218 | {23.52, 47.625, 74.085, 114.355, 175.72, 229.565, 316.285}}; |
| 219 | |
| 220 | // now load the data into vector and Matrix classes |
| 221 | cStrikesEU.clear(); |
| 222 | fStrikesEU.clear(); |
| 223 | cfMaturitiesEU.clear(); |
| 224 | for (Real& i : capStrikesEU) |
| 225 | cStrikesEU.push_back(x: i); |
| 226 | for (Real& i : floorStrikesEU) |
| 227 | fStrikesEU.push_back(x: i); |
| 228 | for (auto& i : capMaturitiesEU) |
| 229 | cfMaturitiesEU.push_back(x: i); |
| 230 | ext::shared_ptr<Matrix> tcPriceEU(new Matrix(ncStrikesEU, ncfMaturitiesEU)); |
| 231 | ext::shared_ptr<Matrix> tfPriceEU(new Matrix(nfStrikesEU, ncfMaturitiesEU)); |
| 232 | for(Size i = 0; i < ncStrikesEU; i++) { |
| 233 | for(Size j = 0; j < ncfMaturitiesEU; j++) { |
| 234 | (*tcPriceEU)[i][j] = capPricesEU[i][j]; |
| 235 | } |
| 236 | } |
| 237 | for(Size i = 0; i < nfStrikesEU; i++) { |
| 238 | for(Size j = 0; j < ncfMaturitiesEU; j++) { |
| 239 | (*tfPriceEU)[i][j] = floorPricesEU[i][j]; |
| 240 | } |
| 241 | } |
| 242 | cPriceEU = tcPriceEU; // copy to global |
| 243 | fPriceEU = tfPriceEU; |
| 244 | } |
| 245 | |
| 246 | |
| 247 | void setupPriceSurface() { |
| 248 | |
| 249 | // construct: |
| 250 | // calendar, business day convention, and day counter are |
| 251 | // taken from the nominal base give the reference date for |
| 252 | // the inflation options (generally 2 or 3 months before |
| 253 | // nominal reference date) |
| 254 | Natural fixingDays = 0; |
| 255 | Size lag = 3;// must be 3 because we use an interpolated index (EU) |
| 256 | Period yyLag = Period(lag,Months); |
| 257 | Rate baseRate = 1; // not really used |
| 258 | DayCounter dc = Actual365Fixed(); |
| 259 | TARGET cal; |
| 260 | BusinessDayConvention bdc = ModifiedFollowing; |
| 261 | const ext::shared_ptr<QuantLib::YieldTermStructure>& pn = nominalEUR.currentLink(); |
| 262 | Handle<QuantLib::YieldTermStructure> n(pn,false); |
| 263 | ext::shared_ptr<InterpolatedYoYCapFloorTermPriceSurface<Bicubic,Cubic> > |
| 264 | cfEUprices(new InterpolatedYoYCapFloorTermPriceSurface<Bicubic,Cubic>( |
| 265 | fixingDays, |
| 266 | yyLag, yoyIndexEU, baseRate, |
| 267 | n, dc, |
| 268 | cal, bdc, |
| 269 | cStrikesEU, fStrikesEU, cfMaturitiesEU, |
| 270 | (*cPriceEU), (*fPriceEU))); |
| 271 | |
| 272 | priceSurfEU = cfEUprices; |
| 273 | } |
| 274 | |
| 275 | } |
| 276 | |
| 277 | //*************************************************************************** |
| 278 | |
| 279 | |
| 280 | |
| 281 | void InflationVolTest::testYoYPriceSurfaceToVol() { |
| 282 | BOOST_TEST_MESSAGE("Testing conversion from YoY price surface " |
| 283 | "to YoY volatility surface..." ); |
| 284 | |
| 285 | using namespace inflation_volatility_test; |
| 286 | |
| 287 | setup(); |
| 288 | |
| 289 | // first get the price surface set up |
| 290 | setupPriceSurface(); |
| 291 | |
| 292 | // caplet pricer, recall that setCapletVolatility(Handle<YoYOptionletVolatilitySurface>) |
| 293 | // exists ... we'll use it with the -Curve variant of the surface |
| 294 | // test UNIT DISPLACED pricer |
| 295 | ext::shared_ptr<YoYOptionletVolatilitySurface> pVS; |
| 296 | Handle<YoYOptionletVolatilitySurface> hVS(pVS, false); // pVS does NOT own whatever it points to later, hence the handle does not either |
| 297 | ext::shared_ptr<YoYInflationUnitDisplacedBlackCapFloorEngine> |
| 298 | yoyPricerUD(new YoYInflationUnitDisplacedBlackCapFloorEngine(yoyIndexEU,hVS,nominalEUR)); //hVS |
| 299 | // N.B. the vol gets set in the stripper ... else no point! |
| 300 | |
| 301 | // cap stripper |
| 302 | ext::shared_ptr<YoYOptionletStripper> yoyOptionletStripper( |
| 303 | new InterpolatedYoYOptionletStripper<Linear>() ); |
| 304 | |
| 305 | // now set up all the variables for the stripping |
| 306 | Natural settlementDays = 0; |
| 307 | TARGET cal; |
| 308 | BusinessDayConvention bdc = ModifiedFollowing; |
| 309 | DayCounter dc = Actual365Fixed(); |
| 310 | |
| 311 | ext::shared_ptr<YoYCapFloorTermPriceSurface> capFloorPrices = priceSurfEU; |
| 312 | Period lag = priceSurfEU->observationLag(); |
| 313 | |
| 314 | Real slope = -0.5; //when you have bad data, i.e. very low/constant |
| 315 | //prices for short dated extreem strikes |
| 316 | //then you cannot assume constant caplet vol |
| 317 | //(else arbitrage) |
| 318 | // N.B. if this is too extreme then can't |
| 319 | // get a no-arbitrage solution anyway |
| 320 | // the way the slope is used means that the slope is |
| 321 | // proportional to the level so higher slopes at |
| 322 | // the edges when things are more volatile |
| 323 | |
| 324 | // Actually is doesn't matter what the interpolation is because we only |
| 325 | // intend to use the K values that correspond to quotes ... for model fitting. |
| 326 | ext::shared_ptr<KInterpolatedYoYOptionletVolatilitySurface<Linear> > yoySurf(new |
| 327 | KInterpolatedYoYOptionletVolatilitySurface<Linear>(settlementDays, |
| 328 | cal, bdc, dc, lag, capFloorPrices, yoyPricerUD, yoyOptionletStripper, |
| 329 | slope) ); |
| 330 | |
| 331 | // now use it for something ... like stating what the T=const lines look like |
| 332 | const Real volATyear1[] = { |
| 333 | 0.0128, 0.0093, 0.0083, 0.0073, 0.0064, |
| 334 | 0.0058, 0.0042, 0.0046, 0.0053, 0.0064, |
| 335 | 0.0098 |
| 336 | }; |
| 337 | const Real volATyear3[] = { |
| 338 | 0.0079, 0.0058, 0.0051, 0.0045, 0.0039, |
| 339 | 0.0035, 0.0026, 0.0028, 0.0033, 0.0039, |
| 340 | 0.0060 |
| 341 | }; |
| 342 | |
| 343 | Date d = yoySurf->baseDate() + Period(1,Years); |
| 344 | auto someSlice = yoySurf->Dslice(d); |
| 345 | |
| 346 | Size n = someSlice.first.size(); |
| 347 | Real eps = 0.0001; |
| 348 | for(Size i = 0; i < n; i++){ |
| 349 | QL_REQUIRE( fabs(someSlice.second[i] - volATyear1[i]) < eps, |
| 350 | " could not recover 1yr vol: " << someSlice.second[i] |
| 351 | << " vs " << volATyear1[i] ); |
| 352 | } |
| 353 | |
| 354 | d = yoySurf->baseDate() + Period(3,Years); |
| 355 | auto someOtherSlice = yoySurf->Dslice(d); |
| 356 | n = someOtherSlice.first.size(); |
| 357 | for(Size i = 0; i < n; i++){ |
| 358 | QL_REQUIRE(fabs(someOtherSlice.second[i]-volATyear3[i]) < eps, |
| 359 | "could not recover 3yr vol: " |
| 360 | << someOtherSlice.second[i]<< " vs " << volATyear3[i] ); |
| 361 | } |
| 362 | |
| 363 | reset(); |
| 364 | } |
| 365 | |
| 366 | |
| 367 | |
| 368 | |
| 369 | void InflationVolTest::testYoYPriceSurfaceToATM() { |
| 370 | BOOST_TEST_MESSAGE("Testing conversion from YoY cap-floor surface " |
| 371 | "to YoY inflation term structure..." ); |
| 372 | |
| 373 | using namespace inflation_volatility_test; |
| 374 | |
| 375 | setup(); |
| 376 | |
| 377 | setupPriceSurface(); |
| 378 | |
| 379 | auto yyATMt = priceSurfEU->atmYoYSwapTimeRates(); |
| 380 | auto yyATMd = priceSurfEU->atmYoYSwapDateRates(); |
| 381 | |
| 382 | // Real dy = (Real)lag / 12.0; |
| 383 | const Real crv[] = {0.024586, 0.0247575, 0.0249396, 0.0252596, |
| 384 | 0.0258498, 0.0262883, 0.0267915}; |
| 385 | const Real swaps[] = {0.024586, 0.0247575, 0.0249396, 0.0252596, |
| 386 | 0.0258498, 0.0262883, 0.0267915}; |
| 387 | const Real ayoy[] = {0.0247659, 0.0251437, 0.0255945, 0.0265234, |
| 388 | 0.0280457, 0.0285534, 0.0295884}; |
| 389 | Real eps = 2e-5; |
| 390 | for(Size i = 0; i < yyATMt.first.size(); i++) { |
| 391 | QL_REQUIRE(fabs( yyATMt.second[i] - crv[i] ) < eps, |
| 392 | "could not recover cached yoy swap curve " |
| 393 | << yyATMt.second[i]<< " vs " << crv[i]); |
| 394 | } |
| 395 | |
| 396 | for(Size i = 0; i < yyATMd.first.size(); i++) { |
| 397 | QL_REQUIRE(fabs( priceSurfEU->atmYoYSwapRate(yyATMd.first[i]) - swaps[i] ) < eps, |
| 398 | "could not recover yoy swap curve " |
| 399 | << priceSurfEU->atmYoYSwapRate(yyATMd.first[i]) << " vs " << swaps[i]); |
| 400 | } |
| 401 | for(Size i = 0; i < yyATMd.first.size(); i++) { |
| 402 | QL_REQUIRE(fabs( priceSurfEU->atmYoYRate(yyATMd.first[i]) - ayoy[i] ) < eps, |
| 403 | " could not recover cached yoy curve " |
| 404 | << priceSurfEU->atmYoYRate(yyATMd.first[i]) << " vs " << ayoy[i] |
| 405 | <<" at " <<yyATMd.first[i]); |
| 406 | } |
| 407 | reset(); |
| 408 | } |
| 409 | |
| 410 | |
| 411 | boost::unit_test_framework::test_suite* InflationVolTest::suite() { |
| 412 | auto* suite = BOOST_TEST_SUITE("yoyOptionletStripper (yoy inflation vol) tests" ); |
| 413 | |
| 414 | suite->add(QUANTLIB_TEST_CASE(&InflationVolTest::testYoYPriceSurfaceToATM)); |
| 415 | suite->add(QUANTLIB_TEST_CASE(&InflationVolTest::testYoYPriceSurfaceToVol)); |
| 416 | |
| 417 | return suite; |
| 418 | } |
| 419 | |
| 420 | |
| 421 | |