Coverage Report

Created: 2025-08-28 06:30

/src/quantlib/ql/experimental/inflation/yoycapfloortermpricesurface.hpp
Line
Count
Source (jump to first uncovered line)
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
 <http://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
        /*! \deprecated Use the overload that passes an interpolation type instead.
59
                        Deprecated in version 1.36.
60
        */
61
        [[deprecated("Use the overload that passes an interpolation type instead")]]
62
        YoYCapFloorTermPriceSurface(Natural fixingDays,
63
                                    const Period& yyLag,
64
                                    const ext::shared_ptr<YoYInflationIndex>& yii,
65
                                    Rate baseRate,
66
                                    Handle<YieldTermStructure> nominal,
67
                                    const DayCounter& dc,
68
                                    const Calendar& cal,
69
                                    const BusinessDayConvention& bdc,
70
                                    const std::vector<Rate>& cStrikes,
71
                                    const std::vector<Rate>& fStrikes,
72
                                    const std::vector<Period>& cfMaturities,
73
                                    const Matrix& cPrice,
74
                                    const Matrix& fPrice);
75
76
        bool indexIsInterpolated() const;
77
        virtual Period observationLag() const;
78
        virtual Frequency frequency() const;
79
80
        //! atm yoy swaps from put-call parity on cap/floor data
81
        /*! uses interpolation (on surface price data), yearly maturities. */
82
        virtual std::pair<std::vector<Time>, std::vector<Rate> >
83
        atmYoYSwapTimeRates() const = 0;
84
        virtual std::pair<std::vector<Date>, std::vector<Rate> >
85
        atmYoYSwapDateRates() const = 0;
86
87
        //! derived from yoy swap rates
88
        virtual ext::shared_ptr<YoYInflationTermStructure> YoYTS() const = 0;
89
        //! index yoy is based on
90
0
        ext::shared_ptr<YoYInflationIndex> yoyIndex() const { return yoyIndex_; }
91
92
        //! inspectors
93
        /*! \note you don't know if price() is a cap or a floor
94
                  without checking the YoYSwapATM level.
95
            \note atm cap/floor prices are generally
96
                  inaccurate because they are from extrapolation
97
                  and intersection.
98
        */
99
        //@{
100
0
        virtual BusinessDayConvention businessDayConvention() const {return bdc_;}
101
0
        virtual Natural fixingDays() const {return fixingDays_;}
102
        virtual Date baseDate() const = 0;
103
        virtual Real price(const Date& d, Rate k) const = 0;
104
        virtual Real capPrice(const Date& d, Rate k) const = 0;
105
        virtual Real floorPrice(const Date& d, Rate k) const = 0;
106
        virtual Rate atmYoYSwapRate(const Date &d,
107
                                    bool extrapolate = true) const = 0;
108
        virtual Rate atmYoYRate(const Date &d,
109
                                const Period &obsLag = Period(-1,Days),
110
                                bool extrapolate = true) const = 0;
111
112
        virtual Real price(const Period& d, Rate k) const;
113
        virtual Real capPrice(const Period& d, Rate k) const;
114
        virtual Real floorPrice(const Period& d, Rate k) const;
115
        virtual Rate atmYoYSwapRate(const Period &d,
116
                                    bool extrapolate = true) const;
117
        virtual Rate atmYoYRate(const Period &d,
118
                                const Period &obsLag = Period(-1,Days),
119
                                bool extrapolate = true) const;
120
121
0
        virtual std::vector<Rate> strikes() const {return cfStrikes_;}
122
0
        virtual std::vector<Rate> capStrikes() const {return cStrikes_;}
123
0
        virtual std::vector<Rate> floorStrikes() const {return fStrikes_;}
124
0
        virtual std::vector<Period> maturities() const {return cfMaturities_;}
125
0
        virtual Rate minStrike() const {return cfStrikes_.front();};
126
0
        virtual Rate maxStrike() const {return cfStrikes_.back();};
127
0
        virtual Date minMaturity() const {return referenceDate()+cfMaturities_.front();}// \TODO deal with index interpolation
128
0
        virtual Date maxMaturity() const {return referenceDate()+cfMaturities_.back();}
129
        //@}
130
131
        virtual Date yoyOptionDateFromTenor(const Period& p) const;
132
133
      protected:
134
0
        virtual bool checkStrike(Rate K) {
135
0
            return ( minStrike() <= K && K <= maxStrike() );
136
0
        }
137
0
        virtual bool checkMaturity(const Date& d) {
138
0
            return ( minMaturity() <= d && d <= maxMaturity() );
139
0
        }
140
141
        // defaults, mostly used for building yoy-fwd curve from put-call parity
142
        //  ext::shared_ptr<YieldTermStructure> nominal_;
143
        //  Period lag_;
144
        //  Calendar cal_;
145
        Natural fixingDays_;
146
        BusinessDayConvention bdc_;
147
        ext::shared_ptr<YoYInflationIndex> yoyIndex_;
148
        Period observationLag_;
149
        Handle<YieldTermStructure> nominalTS_;
150
        // data
151
        std::vector<Rate> cStrikes_;
152
        std::vector<Rate> fStrikes_;
153
        std::vector<Period> cfMaturities_;
154
        mutable std::vector<Real> cfMaturityTimes_;
155
        Matrix cPrice_;
156
        Matrix fPrice_;
157
        bool indexIsInterpolated_;
158
        // constructed
159
        mutable std::vector<Rate> cfStrikes_;
160
        mutable ext::shared_ptr<YoYInflationTermStructure> yoy_;
161
        mutable std::pair<std::vector<Time>, std::vector<Rate> > atmYoYSwapTimeRates_;
162
        mutable std::pair<std::vector<Date>, std::vector<Rate> > atmYoYSwapDateRates_;
163
    };
164
165
166
    template<class Interpolator2D, class Interpolator1D>
167
    class InterpolatedYoYCapFloorTermPriceSurface
168
        : public YoYCapFloorTermPriceSurface {
169
      public:
170
        InterpolatedYoYCapFloorTermPriceSurface(
171
                      Natural fixingDays,
172
                      const Period &yyLag,  // observation lag
173
                      const ext::shared_ptr<YoYInflationIndex>& yii,
174
                      CPI::InterpolationType interpolation,
175
                      const Handle<YieldTermStructure> &nominal,
176
                      const DayCounter &dc,
177
                      const Calendar &cal,
178
                      const BusinessDayConvention &bdc,
179
                      const std::vector<Rate> &cStrikes,
180
                      const std::vector<Rate> &fStrikes,
181
                      const std::vector<Period> &cfMaturities,
182
                      const Matrix &cPrice,
183
                      const Matrix &fPrice,
184
                      const Interpolator2D &interpolator2d = Interpolator2D(),
185
                      const Interpolator1D &interpolator1d = Interpolator1D());
186
187
        /*! \deprecated Use the overload that passes an interpolation type instead.
188
                        Deprecated in version 1.36.
189
        */
190
        [[deprecated("Use the overload that passes an interpolation type instead")]]
191
        InterpolatedYoYCapFloorTermPriceSurface(
192
                      Natural fixingDays,
193
                      const Period &yyLag,  // observation lag
194
                      const ext::shared_ptr<YoYInflationIndex>& yii,
195
                      Rate baseRate,
196
                      const Handle<YieldTermStructure> &nominal,
197
                      const DayCounter &dc,
198
                      const Calendar &cal,
199
                      const BusinessDayConvention &bdc,
200
                      const std::vector<Rate> &cStrikes,
201
                      const std::vector<Rate> &fStrikes,
202
                      const std::vector<Period> &cfMaturities,
203
                      const Matrix &cPrice,
204
                      const Matrix &fPrice,
205
                      const Interpolator2D &interpolator2d = Interpolator2D(),
206
                      const Interpolator1D &interpolator1d = Interpolator1D());
207
208
        //! inflation term structure interface
209
        //@{
210
        Date maxDate() const override { return yoy_->maxDate(); }
211
        Date baseDate() const override { return yoy_->baseDate(); }
212
        //@}
213
        Natural fixingDays() const override { return fixingDays_; }
214
215
        //! \name YoYCapFloorTermPriceSurface interface
216
        //@{
217
        std::pair<std::vector<Time>, std::vector<Rate> > atmYoYSwapTimeRates() const override {
218
            return atmYoYSwapTimeRates_;
219
        }
220
        std::pair<std::vector<Date>, std::vector<Rate> > atmYoYSwapDateRates() const override {
221
            return atmYoYSwapDateRates_;
222
        }
223
        ext::shared_ptr<YoYInflationTermStructure> YoYTS() const override { return yoy_; }
224
        Rate price(const Date& d, Rate k) const override;
225
        Real floorPrice(const Date& d, Rate k) const override;
226
        Real capPrice(const Date& d, Rate k) const override;
227
        Rate atmYoYSwapRate(const Date& d, bool extrapolate = true) const override {
228
            return atmYoYSwapRateCurve_(timeFromReference(d),extrapolate);
229
        }
230
        Rate atmYoYRate(const Date& d,
231
                        const Period& obsLag = Period(-1, Days),
232
                        bool extrapolate = true) const override {
233
            // work in terms of maturity-of-instruments
234
            // so ask for rate with observation lag
235
            Period p = (obsLag == Period(-1, Days)) ? observationLag() : obsLag;
236
            // Third parameter = force linear interpolation of yoy
237
            return yoy_->yoyRate(d, p, false, extrapolate);
238
        }
239
        //@}
240
241
        //! \name LazyObject interface
242
        //@{
243
        void update() override;
244
        void performCalculations() const;
245
        //@}
246
247
      protected:
248
        //! intersection of cap and floor price surfaces at given strikes
249
        void intersect() const;
250
        class ObjectiveFunction {
251
          public:
252
            ObjectiveFunction(Time t, const Interpolation2D&, const Interpolation2D&);
253
            Real operator()(Rate guess) const;
254
          protected:
255
            const Time t_;
256
            const Interpolation2D &a_, &b_; // work on references
257
        };
258
259
        //! mess of making it, i.e. create instruments from quotes and bootstrap
260
        void calculateYoYTermStructure() const;
261
262
        // data for surfaces and curve
263
        mutable std::vector<Rate> cStrikesB_;
264
        mutable std::vector<Rate> fStrikesB_;
265
        mutable Matrix cPriceB_;
266
        mutable Matrix fPriceB_;
267
        mutable Interpolation2D capPrice_, floorPrice_;
268
        mutable Interpolation2D floorPrice2_;
269
        mutable Interpolator2D interpolator2d_;
270
        mutable Interpolation atmYoYSwapRateCurve_;
271
        mutable Interpolator1D interpolator1d_;
272
    };
273
274
275
    // inline definitions
276
277
0
    inline bool YoYCapFloorTermPriceSurface::indexIsInterpolated() const {
278
0
        return indexIsInterpolated_;
279
0
    }
280
281
0
    inline Period YoYCapFloorTermPriceSurface::observationLag() const {
282
0
        return observationLag_;
283
0
    }
284
285
0
    inline Frequency YoYCapFloorTermPriceSurface::frequency() const {
286
0
        return yoyIndex_->frequency();
287
0
    }
288
289
    // template definitions
290
291
    #ifndef __DOXYGEN__
292
293
    template<class I2D, class I1D>
294
    InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
295
    InterpolatedYoYCapFloorTermPriceSurface(
296
                                    Natural fixingDays,
297
                                    const Period &yyLag,
298
                                    const ext::shared_ptr<YoYInflationIndex>& yii,
299
                                    CPI::InterpolationType interpolation,
300
                                    const Handle<YieldTermStructure> &nominal,
301
                                    const DayCounter &dc,
302
                                    const Calendar &cal,
303
                                    const BusinessDayConvention &bdc,
304
                                    const std::vector<Rate> &cStrikes,
305
                                    const std::vector<Rate> &fStrikes,
306
                                    const std::vector<Period> &cfMaturities,
307
                                    const Matrix &cPrice,
308
                                    const Matrix &fPrice,
309
                                    const I2D &interpolator2d,
310
                                    const I1D &interpolator1d)
311
    : YoYCapFloorTermPriceSurface(fixingDays, yyLag, yii,
312
                                  interpolation, nominal, dc, cal, bdc,
313
                                  cStrikes, fStrikes, cfMaturities,
314
                                  cPrice, fPrice),
315
      interpolator2d_(interpolator2d), interpolator1d_(interpolator1d) {
316
        performCalculations();
317
    }
318
319
    template<class I2D, class I1D>
320
    InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
321
    InterpolatedYoYCapFloorTermPriceSurface(
322
                                    Natural fixingDays,
323
                                    const Period &yyLag,
324
                                    const ext::shared_ptr<YoYInflationIndex>& yii,
325
                                    Rate baseRate,
326
                                    const Handle<YieldTermStructure> &nominal,
327
                                    const DayCounter &dc,
328
                                    const Calendar &cal,
329
                                    const BusinessDayConvention &bdc,
330
                                    const std::vector<Rate> &cStrikes,
331
                                    const std::vector<Rate> &fStrikes,
332
                                    const std::vector<Period> &cfMaturities,
333
                                    const Matrix &cPrice,
334
                                    const Matrix &fPrice,
335
                                    const I2D &interpolator2d,
336
                                    const I1D &interpolator1d)
337
    : InterpolatedYoYCapFloorTermPriceSurface(fixingDays, yyLag, yii, CPI::AsIndex,
338
                                              nominal, dc, cal, bdc,
339
                                              cStrikes, fStrikes, cfMaturities,
340
                                              cPrice, fPrice,
341
                                              interpolator2d, interpolator1d) {}
342
343
    #endif
344
345
    template<class I2D, class I1D>
346
    void InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
347
    update() {
348
        notifyObservers();
349
    }
350
351
352
    template<class I2D, class I1D>
353
    void InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
354
    performCalculations() const {
355
        // calculate all the useful things
356
        // ... first the intersection of the cap and floor surfs
357
        intersect();
358
359
        // ... then the yoy term structure, which requires instruments
360
        // and a bootstrap
361
        calculateYoYTermStructure();
362
    }
363
364
365
    template<class I2D, class I1D>
366
    InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::ObjectiveFunction::
367
    ObjectiveFunction(const Time t,
368
                      const Interpolation2D &a,
369
                      const Interpolation2D &b)
370
    : t_(t), a_(a), b_(b) {
371
        // do nothing more
372
    }
373
374
375
    template<class I2D, class I1D>
376
    Rate InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
377
    price(const Date &d, const Rate k) const {
378
        Rate atm = atmYoYSwapRate(d);
379
        return k > atm ? capPrice(d,k): floorPrice(d,k);
380
    }
381
382
383
    template<class I2D, class I1D>
384
    Rate InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
385
    capPrice(const Date &d, const Rate k) const {
386
        Time t = timeFromReference(d);
387
        return capPrice_(t,k);
388
    }
389
390
391
    template<class I2D, class I1D>
392
    Rate InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
393
    floorPrice(const Date &d, const Rate k) const {
394
        Time t = timeFromReference(d);
395
        return floorPrice_(t,k);
396
    }
397
398
399
    template<class I2D, class I1D>
400
    Real InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::ObjectiveFunction::
401
    operator()(Rate guess) const {
402
        // allow extrapolation because the overlap is typically insufficient
403
        // looking for a zero
404
        return ( a_(t_,guess,true) - b_(t_,guess,true) );
405
    }
406
407
408
    template<class I2D, class I1D>
409
    void InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
410
    intersect() const {
411
412
413
        // TODO: define the constants outside the code
414
        const Real maxSearchRange = 0.0201;
415
        const Real maxExtrapolationMaturity = 5.01;
416
        const Real searchStep = 0.0050;
417
        const Real intrinsicValueAddOn = 0.001;
418
419
        std::vector<bool> validMaturity(cfMaturities_.size(),false);
420
421
        cfMaturityTimes_.clear();
422
        for (Size i=0; i<cfMaturities_.size();i++) {
423
            cfMaturityTimes_.push_back(timeFromReference(
424
                    yoyOptionDateFromTenor(cfMaturities_[i])));
425
        }
426
427
        capPrice_ = interpolator2d_.interpolate(
428
                            cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
429
                            cStrikes_.begin(), cStrikes_.end(),
430
                            cPrice_
431
                            );
432
        capPrice_.enableExtrapolation();
433
434
        floorPrice_ = interpolator2d_.interpolate(
435
                            cfMaturityTimes_.begin(),cfMaturityTimes_.end(),
436
                            fStrikes_.begin(), fStrikes_.end(),
437
                            fPrice_
438
                            );
439
        floorPrice_.enableExtrapolation();
440
441
        atmYoYSwapDateRates_.first.clear();
442
        atmYoYSwapDateRates_.second.clear();
443
        atmYoYSwapTimeRates_.first.clear();
444
        atmYoYSwapTimeRates_.second.clear();
445
        Brent solver;
446
        Real solverTolerance_ = 1e-7;
447
        Real lo,hi,guess;
448
        std::vector<Real> minSwapRateIntersection(cfMaturityTimes_.size());
449
        std::vector<Real> maxSwapRateIntersection(cfMaturityTimes_.size());
450
        std::vector<Time> tmpSwapMaturities;
451
        std::vector<Rate> tmpSwapRates;
452
        for (Size i = 0; i < cfMaturities_.size(); i++) {
453
            Time t = cfMaturityTimes_[i];
454
            // determine the sum of discount factors
455
            Size numYears = (Size)std::lround(t);
456
            Real sumDiscount = 0.0;
457
            for (Size j=0; j<numYears; ++j)
458
                sumDiscount += nominalTS_->discount(j + 1.0);
459
            // determine the minimum value of the ATM swap point
460
            Real tmpMinSwapRateIntersection = -1.e10;
461
            Real tmpMaxSwapRateIntersection = 1.e10;
462
            for (Size j=0; j<fStrikes_.size(); ++j) {
463
                Real price = floorPrice_(t,fStrikes_[j]);
464
                Real minSwapRate = fStrikes_[j] - price / (sumDiscount * 10000);
465
                if (minSwapRate > tmpMinSwapRateIntersection)
466
                    tmpMinSwapRateIntersection = minSwapRate;
467
            }
468
            for (Size j=0; j<cStrikes_.size(); ++j) {
469
                Real price = capPrice_(t,cStrikes_[j]);
470
                Real maxSwapRate = cStrikes_[j] + price / (sumDiscount * 10000);
471
                if (maxSwapRate < tmpMaxSwapRateIntersection)
472
                    tmpMaxSwapRateIntersection = maxSwapRate;
473
            }
474
            maxSwapRateIntersection[i] = tmpMaxSwapRateIntersection;
475
            minSwapRateIntersection[i] = tmpMinSwapRateIntersection;
476
477
            // find the interval where the intersection lies
478
            bool trialsExceeded = false;
479
            int numTrials = (int)(maxSearchRange / searchStep);
480
            if ( floorPrice_(t,fStrikes_.back()) > capPrice_(t,fStrikes_.back()) ) {
481
                int counter = 1;
482
                bool stop = false;
483
                Real strike = 0.0;
484
                while (!stop) {
485
                    strike = fStrikes_.back() - counter * searchStep;
486
                    if (floorPrice_(t, strike) < capPrice_(t, strike))
487
                        stop = true;
488
                    counter++;
489
                    if (counter == numTrials + 1) {
490
                        if (!stop) {
491
                            stop = true;
492
                            trialsExceeded = true;
493
                        }
494
                    }
495
                }
496
                lo = strike;
497
                hi = strike + searchStep;
498
            } else {
499
                int counter = 1;
500
                bool stop = false;
501
                Real strike = 0.0;
502
                while (!stop) {
503
                    strike = fStrikes_.back() + counter * searchStep;
504
                    if (floorPrice_(t, strike) > capPrice_(t, strike))
505
                        stop = true;
506
                    counter++;
507
                    if (counter == numTrials + 1) {
508
                        if (!stop) {
509
                            stop = true;
510
                            trialsExceeded = true;
511
                        }
512
                    }
513
                }
514
                lo = strike - searchStep;
515
                hi = strike;
516
            }
517
518
            guess = (hi+lo)/2.0;
519
            Rate kI = -999.999;
520
521
            if (!trialsExceeded) {
522
                try{
523
                    kI = solver.solve(  ObjectiveFunction(t, capPrice_, floorPrice_), solverTolerance_, guess, lo, hi );
524
                } catch( std::exception &e) {
525
                    QL_FAIL("cap/floor intersection finding failed at t = " << t << ", error msg: "<< e.what());
526
                }
527
                // error message if kI is economically nonsensical (only if t is large)
528
                if (kI <= minSwapRateIntersection[i]) {
529
                    if (t > maxExtrapolationMaturity)
530
                        QL_FAIL("cap/floor intersection finding failed at t = " << t <<
531
                                ", error msg: intersection value is below the arbitrage free lower bound "
532
                                << minSwapRateIntersection[i]);
533
                }
534
                else
535
                {
536
                    tmpSwapMaturities.push_back(t);
537
                    tmpSwapRates.push_back(kI);
538
                    validMaturity[i] = true;
539
                }
540
            }
541
            else
542
            {
543
                // error message if t is too large
544
                if (t > maxExtrapolationMaturity)
545
                    QL_FAIL("cap/floor intersection finding failed at t = " << t <<
546
                            ", error msg: no interection found inside the admissible range");
547
            }
548
        }
549
550
        // extrapolation of swap rates if necessary
551
        //Polynomial2D tmpInterpol;
552
        //Interpolation interpol = tmpInterpol.interpolate(tmpSwapMaturities.begin(), tmpSwapMaturities.end(), tmpSwapRates.begin());
553
        //interpol.enableExtrapolation();
554
        int counter = 0;
555
        for (Size i=0; i<cfMaturities_.size(); ++i) {
556
            if ( !validMaturity[i] ) {
557
                atmYoYSwapDateRates_.first.push_back(referenceDate()+cfMaturities_[i]);
558
                atmYoYSwapTimeRates_.first.push_back(timeFromReference(referenceDate()+cfMaturities_[i]));
559
                // atmYoYSwapRates_->second.push_back(interpol((*cfMaturities_)[i]));
560
                // Heuristic: overwrite the the swap rate with a value that guarantees that the
561
                // intrinsic value of all options is lower than the price
562
                Real newSwapRate = minSwapRateIntersection[i] + intrinsicValueAddOn;
563
                if (newSwapRate > maxSwapRateIntersection[i])
564
                    newSwapRate = 0.5 * (minSwapRateIntersection[i] + maxSwapRateIntersection[i]);
565
                atmYoYSwapTimeRates_.second.push_back(newSwapRate);
566
                atmYoYSwapDateRates_.second.push_back(newSwapRate);
567
            } else {
568
                atmYoYSwapTimeRates_.first.push_back(tmpSwapMaturities[counter]);
569
                atmYoYSwapTimeRates_.second.push_back(tmpSwapRates[counter]);
570
                atmYoYSwapDateRates_.first.push_back(
571
                    yoyOptionDateFromTenor(cfMaturities_.at(counter)));
572
                atmYoYSwapDateRates_.second.push_back(tmpSwapRates[counter]);
573
                counter++;
574
            }
575
        }
576
577
        // create the swap curve using the factory
578
        atmYoYSwapRateCurve_ =
579
            interpolator1d_.interpolate(atmYoYSwapTimeRates_.first.begin(),
580
                                        atmYoYSwapTimeRates_.first.end(),
581
                                        atmYoYSwapTimeRates_.second.begin());
582
    }
583
584
585
    template<class I2D, class I1D>
586
    void InterpolatedYoYCapFloorTermPriceSurface<I2D,I1D>::
587
    calculateYoYTermStructure() const {
588
589
        // which yoy-swap points to use in building the yoy-fwd curve?
590
        // for now pick every year
591
        Size nYears = (Size)std::lround(timeFromReference(referenceDate()+cfMaturities_.back()));
592
593
        std::vector<ext::shared_ptr<BootstrapHelper<YoYInflationTermStructure> > > YYhelpers;
594
        for (Size i=1; i<=nYears; i++) {
595
            Date maturity = nominalTS_->referenceDate() + Period(i,Years);
596
            Handle<Quote> quote(ext::shared_ptr<Quote>(
597
                               new SimpleQuote( atmYoYSwapRate( maturity ) )));//!
598
            auto anInstrument =
599
                ext::make_shared<YearOnYearInflationSwapHelper>(
600
                                quote, observationLag(), maturity,
601
                                calendar(), bdc_, dayCounter(),
602
                                yoyIndex(),
603
                                this->indexIsInterpolated() ? CPI::Linear: CPI::Flat,
604
                                nominalTS_);
605
            YYhelpers.push_back (anInstrument);
606
        }
607
608
        Date baseDate =
609
            inflationPeriod(nominalTS_->referenceDate() - observationLag(),
610
                            yoyIndex()->frequency()).first;
611
        // usually this base rate is known
612
        // however for the data to be self-consistent
613
        // we pick this as the end of the curve
614
        Rate baseYoYRate = atmYoYSwapRate( referenceDate() );//!
615
616
        // Linear is OK because we have every year
617
        auto pYITS =
618
            ext::make_shared<PiecewiseYoYInflationCurve<Linear>>(
619
                      nominalTS_->referenceDate(), baseDate, baseYoYRate,
620
                      yoyIndex()->frequency(), dayCounter(), YYhelpers);
621
        pYITS->recalculate();
622
        yoy_ = pYITS;   // store
623
624
        // check that helpers are repriced
625
        const Real eps = 1e-5;
626
        for (Size i=0; i<YYhelpers.size(); i++) {
627
            Rate original = atmYoYSwapRate( yoyOptionDateFromTenor(Period(i+1,Years)) );
628
            QL_REQUIRE(fabs(YYhelpers[i]->impliedQuote() - original) <eps,
629
                       "could not reprice helper "<< i
630
                       << ", data " << original
631
                       << ", implied quote " << YYhelpers[i]->impliedQuote()
632
            );
633
        }
634
    }
635
636
}
637
638
639
#endif