• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lballabio / QuantLib / 18902330216

29 Oct 2025 08:56AM UTC coverage: 74.321% (+0.4%) from 73.914%
18902330216

Pull #2344

github

web-flow
Merge a8095fd90 into d823f4ecb
Pull Request #2344: add multicurve bootstrap

100 of 104 new or added lines in 8 files covered. (96.15%)

216 existing lines in 13 files now uncovered.

57073 of 76793 relevant lines covered (74.32%)

8779123.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.3
/ql/experimental/inflation/yoycapfloortermpricesurface.hpp
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2

3
/*
4
 Copyright (C) 2009 Chris Kenyon
5
 Copyright (C) 2009 Bernd Engelmann
6

7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9

10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15

16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20

21
/*! \file yoycapfloortermpricesurface.hpp
22
    \brief yoy inflation cap and floor term-price structure
23
*/
24

25
#ifndef quantlib_yoy_capfloor_term_price_surface_hpp
26
#define quantlib_yoy_capfloor_term_price_surface_hpp
27

28
#include <ql/indexes/inflationindex.hpp>
29
#include <ql/termstructures/inflation/piecewiseyoyinflationcurve.hpp>
30
#include <ql/termstructures/inflation/inflationhelpers.hpp>
31
#include <ql/experimental/inflation/polynomial2Dspline.hpp>
32
#include <cmath>
33

34
namespace QuantLib {
35

36
    //! Abstract base class, inheriting from InflationTermStructure
37
    /*! Since this can create a yoy term structure it does take
38
        a YoY index.
39

40
        \todo deal with index interpolation.
41
    */
42
    class YoYCapFloorTermPriceSurface : public TermStructure {
43
      public:
44
        YoYCapFloorTermPriceSurface(Natural fixingDays,
45
                                    const Period& yyLag,
46
                                    const ext::shared_ptr<YoYInflationIndex>& yii,
47
                                    CPI::InterpolationType interpolation,
48
                                    Handle<YieldTermStructure> nominal,
49
                                    const DayCounter& dc,
50
                                    const Calendar& cal,
51
                                    const BusinessDayConvention& bdc,
52
                                    const std::vector<Rate>& cStrikes,
53
                                    const std::vector<Rate>& fStrikes,
54
                                    const std::vector<Period>& cfMaturities,
55
                                    const Matrix& cPrice,
56
                                    const Matrix& fPrice);
57

58
        bool indexIsInterpolated() const;
59
        virtual Period observationLag() const;
60
        virtual Frequency frequency() const;
61

62
        //! atm yoy swaps from put-call parity on cap/floor data
63
        /*! uses interpolation (on surface price data), yearly maturities. */
64
        virtual std::pair<std::vector<Time>, std::vector<Rate> >
65
        atmYoYSwapTimeRates() const = 0;
66
        virtual std::pair<std::vector<Date>, std::vector<Rate> >
67
        atmYoYSwapDateRates() const = 0;
68

69
        //! derived from yoy swap rates
70
        virtual ext::shared_ptr<YoYInflationTermStructure> YoYTS() const = 0;
71
        //! index yoy is based on
72
        ext::shared_ptr<YoYInflationIndex> yoyIndex() const { return yoyIndex_; }
73

74
        //! inspectors
75
        /*! \note you don't know if price() is a cap or a floor
76
                  without checking the YoYSwapATM level.
77
            \note atm cap/floor prices are generally
78
                  inaccurate because they are from extrapolation
79
                  and intersection.
80
        */
81
        //@{
82
        virtual BusinessDayConvention businessDayConvention() const {return bdc_;}
1✔
UNCOV
83
        virtual Natural fixingDays() const {return fixingDays_;}
×
84
        virtual Date baseDate() const = 0;
85
        virtual Real price(const Date& d, Rate k) const = 0;
86
        virtual Real capPrice(const Date& d, Rate k) const = 0;
87
        virtual Real floorPrice(const Date& d, Rate k) const = 0;
88
        virtual Rate atmYoYSwapRate(const Date &d,
89
                                    bool extrapolate = true) const = 0;
90
        virtual Rate atmYoYRate(const Date &d,
91
                                const Period &obsLag = Period(-1,Days),
92
                                bool extrapolate = true) const = 0;
93

94
        virtual Real price(const Period& d, Rate k) const;
95
        virtual Real capPrice(const Period& d, Rate k) const;
96
        virtual Real floorPrice(const Period& d, Rate k) const;
97
        virtual Rate atmYoYSwapRate(const Period &d,
98
                                    bool extrapolate = true) const;
99
        virtual Rate atmYoYRate(const Period &d,
100
                                const Period &obsLag = Period(-1,Days),
101
                                bool extrapolate = true) const;
102

103
        virtual std::vector<Rate> strikes() const {return cfStrikes_;}
25✔
UNCOV
104
        virtual std::vector<Rate> capStrikes() const {return cStrikes_;}
×
105
        virtual std::vector<Rate> floorStrikes() const {return fStrikes_;}
1✔
106
        virtual std::vector<Period> maturities() const {return cfMaturities_;}
166✔
UNCOV
107
        virtual Rate minStrike() const {return cfStrikes_.front();};
×
UNCOV
108
        virtual Rate maxStrike() const {return cfStrikes_.back();};
×
109
        virtual Date minMaturity() const {return referenceDate()+cfMaturities_.front();}// \TODO deal with index interpolation
33✔
UNCOV
110
        virtual Date maxMaturity() const {return referenceDate()+cfMaturities_.back();}
×
111
        //@}
112

113
        virtual Date yoyOptionDateFromTenor(const Period& p) const;
114

115
      protected:
UNCOV
116
        virtual bool checkStrike(Rate K) {
×
UNCOV
117
            return ( minStrike() <= K && K <= maxStrike() );
×
118
        }
UNCOV
119
        virtual bool checkMaturity(const Date& d) {
×
UNCOV
120
            return ( minMaturity() <= d && d <= maxMaturity() );
×
121
        }
122

123
        // defaults, mostly used for building yoy-fwd curve from put-call parity
124
        //  ext::shared_ptr<YieldTermStructure> nominal_;
125
        //  Period lag_;
126
        //  Calendar cal_;
127
        Natural fixingDays_;
128
        BusinessDayConvention bdc_;
129
        ext::shared_ptr<YoYInflationIndex> yoyIndex_;
130
        Period observationLag_;
131
        Handle<YieldTermStructure> nominalTS_;
132
        // data
133
        std::vector<Rate> cStrikes_;
134
        std::vector<Rate> fStrikes_;
135
        std::vector<Period> cfMaturities_;
136
        mutable std::vector<Real> cfMaturityTimes_;
137
        Matrix cPrice_;
138
        Matrix fPrice_;
139
        bool indexIsInterpolated_;
140
        // constructed
141
        mutable std::vector<Rate> cfStrikes_;
142
        mutable ext::shared_ptr<YoYInflationTermStructure> yoy_;
143
        mutable std::pair<std::vector<Time>, std::vector<Rate> > atmYoYSwapTimeRates_;
144
        mutable std::pair<std::vector<Date>, std::vector<Rate> > atmYoYSwapDateRates_;
145
    };
146

147

148
    template<class Interpolator2D, class Interpolator1D>
149
    class InterpolatedYoYCapFloorTermPriceSurface
150
        : public YoYCapFloorTermPriceSurface {
151
      public:
152
        InterpolatedYoYCapFloorTermPriceSurface(
153
                      Natural fixingDays,
154
                      const Period &yyLag,  // observation lag
155
                      const ext::shared_ptr<YoYInflationIndex>& yii,
156
                      CPI::InterpolationType interpolation,
157
                      const Handle<YieldTermStructure> &nominal,
158
                      const DayCounter &dc,
159
                      const Calendar &cal,
160
                      const BusinessDayConvention &bdc,
161
                      const std::vector<Rate> &cStrikes,
162
                      const std::vector<Rate> &fStrikes,
163
                      const std::vector<Period> &cfMaturities,
164
                      const Matrix &cPrice,
165
                      const Matrix &fPrice,
166
                      const Interpolator2D &interpolator2d = Interpolator2D(),
167
                      const Interpolator1D &interpolator1d = Interpolator1D());
168

169
        //! inflation term structure interface
170
        //@{
UNCOV
171
        Date maxDate() const override { return yoy_->maxDate(); }
×
172
        Date baseDate() const override { return yoy_->baseDate(); }
11✔
173
        //@}
174
        Natural fixingDays() const override { return fixingDays_; }
1✔
175

176
        //! \name YoYCapFloorTermPriceSurface interface
177
        //@{
178
        std::pair<std::vector<Time>, std::vector<Rate> > atmYoYSwapTimeRates() const override {
1✔
179
            return atmYoYSwapTimeRates_;
1✔
180
        }
181
        std::pair<std::vector<Date>, std::vector<Rate> > atmYoYSwapDateRates() const override {
1✔
182
            return atmYoYSwapDateRates_;
1✔
183
        }
184
        ext::shared_ptr<YoYInflationTermStructure> YoYTS() const override { return yoy_; }
1✔
185
        Rate price(const Date& d, Rate k) const override;
186
        Real floorPrice(const Date& d, Rate k) const override;
187
        Real capPrice(const Date& d, Rate k) const override;
188
        Rate atmYoYSwapRate(const Date& d, bool extrapolate = true) const override {
129✔
189
            return atmYoYSwapRateCurve_(timeFromReference(d),extrapolate);
129✔
190
        }
191
        Rate atmYoYRate(const Date& d,
7✔
192
                        const Period& obsLag = Period(-1, Days),
193
                        bool extrapolate = true) const override {
194
            // work in terms of maturity-of-instruments
195
            // so ask for rate with observation lag
196
            Period p = (obsLag == Period(-1, Days)) ? observationLag() : obsLag;
7✔
197
            // Third parameter = force linear interpolation of yoy
198
            return yoy_->yoyRate(d, p, false, extrapolate);
7✔
199
        }
200
        //@}
201

202
        //! \name LazyObject interface
203
        //@{
204
        void update() override;
205
        void performCalculations() const;
206
        //@}
207

208
      protected:
209
        //! intersection of cap and floor price surfaces at given strikes
210
        void intersect() const;
211
        class ObjectiveFunction {
212
          public:
213
            ObjectiveFunction(Time t, const Interpolation2D&, const Interpolation2D&);
214
            Real operator()(Rate guess) const;
215
          protected:
216
            const Time t_;
217
            const Interpolation2D &a_, &b_; // work on references
218
        };
219

220
        //! mess of making it, i.e. create instruments from quotes and bootstrap
221
        void calculateYoYTermStructure() const;
222

223
        // data for surfaces and curve
224
        mutable std::vector<Rate> cStrikesB_;
225
        mutable std::vector<Rate> fStrikesB_;
226
        mutable Matrix cPriceB_;
227
        mutable Matrix fPriceB_;
228
        mutable Interpolation2D capPrice_, floorPrice_;
229
        mutable Interpolation2D floorPrice2_;
230
        mutable Interpolator2D interpolator2d_;
231
        mutable Interpolation atmYoYSwapRateCurve_;
232
        mutable Interpolator1D interpolator1d_;
233
    };
234

235

236
    // inline definitions
237

238
    inline bool YoYCapFloorTermPriceSurface::indexIsInterpolated() const {
239
        return indexIsInterpolated_;
1✔
240
    }
241

242
    inline Period YoYCapFloorTermPriceSurface::observationLag() const {
82✔
243
        return observationLag_;
82✔
244
    }
245

246
    inline Frequency YoYCapFloorTermPriceSurface::frequency() const {
1✔
247
        return yoyIndex_->frequency();
1✔
248
    }
249

250
    // template definitions
251

252
    #ifndef __DOXYGEN__
253

254
    template<class I2D, class I1D>
255
    InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
2✔
256
    InterpolatedYoYCapFloorTermPriceSurface(
257
                                    Natural fixingDays,
258
                                    const Period &yyLag,
259
                                    const ext::shared_ptr<YoYInflationIndex>& yii,
260
                                    CPI::InterpolationType interpolation,
261
                                    const Handle<YieldTermStructure> &nominal,
262
                                    const DayCounter &dc,
263
                                    const Calendar &cal,
264
                                    const BusinessDayConvention &bdc,
265
                                    const std::vector<Rate> &cStrikes,
266
                                    const std::vector<Rate> &fStrikes,
267
                                    const std::vector<Period> &cfMaturities,
268
                                    const Matrix &cPrice,
269
                                    const Matrix &fPrice,
270
                                    const I2D &interpolator2d,
271
                                    const I1D &interpolator1d)
272
    : YoYCapFloorTermPriceSurface(fixingDays, yyLag, yii,
273
                                  interpolation, nominal, dc, cal, bdc,
274
                                  cStrikes, fStrikes, cfMaturities,
275
                                  cPrice, fPrice),
276
      interpolator2d_(interpolator2d), interpolator1d_(interpolator1d) {
4✔
277
        performCalculations();
2✔
278
    }
2✔
279

280
    #endif
281

282
    template<class I2D, class I1D>
UNCOV
283
    void InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
×
284
    update() {
UNCOV
285
        notifyObservers();
×
UNCOV
286
    }
×
287

288

289
    template<class I2D, class I1D>
290
    void InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
2✔
291
    performCalculations() const {
292
        // calculate all the useful things
293
        // ... first the intersection of the cap and floor surfs
294
        intersect();
2✔
295

296
        // ... then the yoy term structure, which requires instruments
297
        // and a bootstrap
298
        calculateYoYTermStructure();
2✔
299
    }
2✔
300

301

302
    template<class I2D, class I1D>
303
    InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::ObjectiveFunction::
14✔
304
    ObjectiveFunction(const Time t,
305
                      const Interpolation2D &a,
306
                      const Interpolation2D &b)
307
    : t_(t), a_(a), b_(b) {
14✔
308
        // do nothing more
309
    }
14✔
310

311

312
    template<class I2D, class I1D>
UNCOV
313
    Rate InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
×
314
    price(const Date &d, const Rate k) const {
UNCOV
315
        Rate atm = atmYoYSwapRate(d);
×
UNCOV
316
        return k > atm ? capPrice(d,k): floorPrice(d,k);
×
317
    }
318

319

320
    template<class I2D, class I1D>
321
    Rate InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
40✔
322
    capPrice(const Date &d, const Rate k) const {
323
        Time t = timeFromReference(d);
40✔
324
        return capPrice_(t,k);
40✔
325
    }
326

327

328
    template<class I2D, class I1D>
329
    Rate InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
48✔
330
    floorPrice(const Date &d, const Rate k) const {
331
        Time t = timeFromReference(d);
48✔
332
        return floorPrice_(t,k);
48✔
333
    }
334

335

336
    template<class I2D, class I1D>
337
    Real InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::ObjectiveFunction::
112✔
338
    operator()(Rate guess) const {
339
        // allow extrapolation because the overlap is typically insufficient
340
        // looking for a zero
341
        return ( a_(t_,guess,true) - b_(t_,guess,true) );
112✔
342
    }
343

344

345
    template<class I2D, class I1D>
346
    void InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
2✔
347
    intersect() const {
348

349

350
        // TODO: define the constants outside the code
351
        const Real maxSearchRange = 0.0201;
352
        const Real maxExtrapolationMaturity = 5.01;
353
        const Real searchStep = 0.0050;
354
        const Real intrinsicValueAddOn = 0.001;
355

356
        std::vector<bool> validMaturity(cfMaturities_.size(),false);
2✔
357

358
        cfMaturityTimes_.clear();
2✔
359
        for (Size i=0; i<cfMaturities_.size();i++) {
16✔
360
            cfMaturityTimes_.push_back(timeFromReference(
14✔
361
                    yoyOptionDateFromTenor(cfMaturities_[i])));
28✔
362
        }
363

364
        capPrice_ = interpolator2d_.interpolate(
2✔
365
                            cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
4✔
366
                            cStrikes_.begin(), cStrikes_.end(),
4✔
367
                            cPrice_
2✔
368
                            );
369
        capPrice_.enableExtrapolation();
370

371
        floorPrice_ = interpolator2d_.interpolate(
2✔
372
                            cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
4✔
373
                            fStrikes_.begin(), fStrikes_.end(),
4✔
374
                            fPrice_
2✔
375
                            );
376
        floorPrice_.enableExtrapolation();
377

378
        atmYoYSwapDateRates_.first.clear();
2✔
379
        atmYoYSwapDateRates_.second.clear();
2✔
380
        atmYoYSwapTimeRates_.first.clear();
2✔
381
        atmYoYSwapTimeRates_.second.clear();
2✔
382
        Brent solver;
383
        Real solverTolerance_ = 1e-7;
384
        Real lo,hi,guess;
385
        std::vector<Real> minSwapRateIntersection(cfMaturityTimes_.size());
2✔
386
        std::vector<Real> maxSwapRateIntersection(cfMaturityTimes_.size());
2✔
387
        std::vector<Time> tmpSwapMaturities;
388
        std::vector<Rate> tmpSwapRates;
389
        for (Size i = 0; i < cfMaturities_.size(); i++) {
16✔
390
            Time t = cfMaturityTimes_[i];
14✔
391
            // determine the sum of discount factors
392
            Size numYears = (Size)std::lround(t);
14✔
393
            Real sumDiscount = 0.0;
394
            for (Size j=0; j<numYears; ++j)
194✔
395
                sumDiscount += nominalTS_->discount(j + 1.0);
180✔
396
            // determine the minimum value of the ATM swap point
397
            Real tmpMinSwapRateIntersection = -1.e10;
398
            Real tmpMaxSwapRateIntersection = 1.e10;
399
            for (Size j=0; j<fStrikes_.size(); ++j) {
98✔
400
                Real price = floorPrice_(t,fStrikes_[j]);
84✔
401
                Real minSwapRate = fStrikes_[j] - price / (sumDiscount * 10000);
84✔
402
                if (minSwapRate > tmpMinSwapRateIntersection)
84✔
403
                    tmpMinSwapRateIntersection = minSwapRate;
404
            }
405
            for (Size j=0; j<cStrikes_.size(); ++j) {
98✔
406
                Real price = capPrice_(t,cStrikes_[j]);
84✔
407
                Real maxSwapRate = cStrikes_[j] + price / (sumDiscount * 10000);
84✔
408
                if (maxSwapRate < tmpMaxSwapRateIntersection)
84✔
409
                    tmpMaxSwapRateIntersection = maxSwapRate;
410
            }
411
            maxSwapRateIntersection[i] = tmpMaxSwapRateIntersection;
14✔
412
            minSwapRateIntersection[i] = tmpMinSwapRateIntersection;
14✔
413

414
            // find the interval where the intersection lies
415
            bool trialsExceeded = false;
416
            int numTrials = (int)(maxSearchRange / searchStep);
417
            if ( floorPrice_(t,fStrikes_.back()) > capPrice_(t,fStrikes_.back()) ) {
14✔
418
                int counter = 1;
419
                bool stop = false;
420
                Real strike = 0.0;
UNCOV
421
                while (!stop) {
×
UNCOV
422
                    strike = fStrikes_.back() - counter * searchStep;
×
UNCOV
423
                    if (floorPrice_(t, strike) < capPrice_(t, strike))
×
424
                        stop = true;
UNCOV
425
                    counter++;
×
UNCOV
426
                    if (counter == numTrials + 1) {
×
UNCOV
427
                        if (!stop) {
×
428
                            stop = true;
429
                            trialsExceeded = true;
430
                        }
431
                    }
432
                }
433
                lo = strike;
UNCOV
434
                hi = strike + searchStep;
×
435
            } else {
436
                int counter = 1;
437
                bool stop = false;
438
                Real strike = 0.0;
439
                while (!stop) {
36✔
440
                    strike = fStrikes_.back() + counter * searchStep;
22✔
441
                    if (floorPrice_(t, strike) > capPrice_(t, strike))
22✔
442
                        stop = true;
443
                    counter++;
22✔
444
                    if (counter == numTrials + 1) {
22✔
UNCOV
445
                        if (!stop) {
×
446
                            stop = true;
447
                            trialsExceeded = true;
448
                        }
449
                    }
450
                }
451
                lo = strike - searchStep;
14✔
452
                hi = strike;
453
            }
454

455
            guess = (hi+lo)/2.0;
14✔
456
            Rate kI = -999.999;
14✔
457

458
            if (!trialsExceeded) {
14✔
459
                try{
460
                    kI = solver.solve(  ObjectiveFunction(t, capPrice_, floorPrice_), solverTolerance_, guess, lo, hi );
14✔
UNCOV
461
                } catch( std::exception &e) {
×
UNCOV
462
                    QL_FAIL("cap/floor intersection finding failed at t = " << t << ", error msg: "<< e.what());
×
463
                }
464
                // error message if kI is economically nonsensical (only if t is large)
465
                if (kI <= minSwapRateIntersection[i]) {
14✔
UNCOV
466
                    if (t > maxExtrapolationMaturity)
×
UNCOV
467
                        QL_FAIL("cap/floor intersection finding failed at t = " << t <<
×
468
                                ", error msg: intersection value is below the arbitrage free lower bound "
469
                                << minSwapRateIntersection[i]);
470
                }
471
                else
472
                {
473
                    tmpSwapMaturities.push_back(t);
14✔
474
                    tmpSwapRates.push_back(kI);
14✔
475
                    validMaturity[i] = true;
476
                }
477
            }
478
            else
479
            {
480
                // error message if t is too large
UNCOV
481
                if (t > maxExtrapolationMaturity)
×
UNCOV
482
                    QL_FAIL("cap/floor intersection finding failed at t = " << t <<
×
483
                            ", error msg: no interection found inside the admissible range");
484
            }
485
        }
486

487
        // extrapolation of swap rates if necessary
488
        //Polynomial2D tmpInterpol;
489
        //Interpolation interpol = tmpInterpol.interpolate(tmpSwapMaturities.begin(), tmpSwapMaturities.end(), tmpSwapRates.begin());
490
        //interpol.enableExtrapolation();
491
        int counter = 0;
492
        for (Size i=0; i<cfMaturities_.size(); ++i) {
16✔
493
            if ( !validMaturity[i] ) {
14✔
UNCOV
494
                atmYoYSwapDateRates_.first.push_back(referenceDate()+cfMaturities_[i]);
×
UNCOV
495
                atmYoYSwapTimeRates_.first.push_back(timeFromReference(referenceDate()+cfMaturities_[i]));
×
496
                // atmYoYSwapRates_->second.push_back(interpol((*cfMaturities_)[i]));
497
                // Heuristic: overwrite the the swap rate with a value that guarantees that the
498
                // intrinsic value of all options is lower than the price
UNCOV
499
                Real newSwapRate = minSwapRateIntersection[i] + intrinsicValueAddOn;
×
UNCOV
500
                if (newSwapRate > maxSwapRateIntersection[i])
×
UNCOV
501
                    newSwapRate = 0.5 * (minSwapRateIntersection[i] + maxSwapRateIntersection[i]);
×
UNCOV
502
                atmYoYSwapTimeRates_.second.push_back(newSwapRate);
×
UNCOV
503
                atmYoYSwapDateRates_.second.push_back(newSwapRate);
×
504
            } else {
505
                atmYoYSwapTimeRates_.first.push_back(tmpSwapMaturities[counter]);
14✔
506
                atmYoYSwapTimeRates_.second.push_back(tmpSwapRates[counter]);
14✔
507
                atmYoYSwapDateRates_.first.push_back(
508
                    yoyOptionDateFromTenor(cfMaturities_.at(counter)));
28✔
509
                atmYoYSwapDateRates_.second.push_back(tmpSwapRates[counter]);
14✔
510
                counter++;
14✔
511
            }
512
        }
513

514
        // create the swap curve using the factory
515
        atmYoYSwapRateCurve_ =
2✔
516
            interpolator1d_.interpolate(atmYoYSwapTimeRates_.first.begin(),
4✔
517
                                        atmYoYSwapTimeRates_.first.end(),
4✔
518
                                        atmYoYSwapTimeRates_.second.begin());
4✔
519
    }
2✔
520

521

522
    template<class I2D, class I1D>
523
    void InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
2✔
524
    calculateYoYTermStructure() const {
525

526
        // which yoy-swap points to use in building the yoy-fwd curve?
527
        // for now pick every year
528
        Size nYears = (Size)std::lround(timeFromReference(referenceDate()+cfMaturities_.back()));
4✔
529

530
        std::vector<ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure> > > YYhelpers;
531
        for (Size i=1; i<=nYears; i++) {
62✔
532
            Date maturity = nominalTS_->referenceDate() + Period(i,Years);
60✔
533
            Handle<Quote> quote(ext::shared_ptr<Quote>(
60✔
534
                               new SimpleQuote( atmYoYSwapRate( maturity ) )));//!
60✔
535
            auto anInstrument =
120✔
536
                ext::make_shared<YearOnYearInflationSwapHelper>(
537
                                quote, observationLag(), maturity,
120✔
538
                                calendar(), bdc_, dayCounter(),
60✔
539
                                yoyIndex(),
540
                                this->indexIsInterpolated() ? CPI::Linear: CPI::Flat,
120✔
541
                                nominalTS_);
542
            YYhelpers.push_back (anInstrument);
60✔
543
        }
544

545
        Date baseDate =
2✔
546
            inflationPeriod(nominalTS_->referenceDate() - observationLag(),
4✔
547
                            yoyIndex()->frequency()).first;
2✔
548
        // usually this base rate is known
549
        // however for the data to be self-consistent
550
        // we pick this as the end of the curve
551
        Rate baseYoYRate = atmYoYSwapRate( referenceDate() );//!
2✔
552

553
        // Linear is OK because we have every year
554
        auto pYITS =
2✔
555
            ext::make_shared<PiecewiseYoYInflationCurve<Linear>>(
556
                      nominalTS_->referenceDate(), baseDate, baseYoYRate,
2✔
557
                      yoyIndex()->frequency(), dayCounter(), YYhelpers);
8✔
558
        pYITS->recalculate();
2✔
559
        yoy_ = pYITS;   // store
2✔
560

561
        // check that helpers are repriced
562
        const Real eps = 1e-5;
563
        for (Size i=0; i<YYhelpers.size(); i++) {
62✔
564
            Rate original = atmYoYSwapRate( yoyOptionDateFromTenor(Period(i+1,Years)) );
60✔
565
            QL_REQUIRE(fabs(YYhelpers[i]->impliedQuote() - original) <eps,
60✔
566
                       "could not reprice helper "<< i
567
                       << ", data " << original
568
                       << ", implied quote " << YYhelpers[i]->impliedQuote()
569
            );
570
        }
571
    }
2✔
572

573
}
574

575

576
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc