Coverage Report

Created: 2026-03-31 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/cashflows/cpicoupon.hpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2011 Chris Kenyon
5
 Copyright (C) 2022 Quaternion Risk Management Ltd
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 cpicoupon.hpp
22
    \brief Coupon paying a zero-inflation index
23
*/
24
25
#ifndef quantlib_cpicoupon_hpp
26
#define quantlib_cpicoupon_hpp
27
28
#include <ql/cashflows/inflationcoupon.hpp>
29
#include <ql/cashflows/indexedcashflow.hpp>
30
#include <ql/indexes/inflationindex.hpp>
31
#include <ql/time/schedule.hpp>
32
33
namespace QuantLib {
34
35
36
    class CPICouponPricer;
37
38
    //! %Coupon paying the performance of a CPI (zero inflation) index
39
    /*! The performance is relative to the index value on the base date.
40
41
        The other inflation value is taken from the refPeriodEnd date
42
        with observation lag, so any roll/calendar etc. will be built
43
        in by the caller.  By default this is done in the
44
        InflationCoupon which uses ModifiedPreceding with fixing days
45
        assumed positive meaning earlier, i.e. always stay in same
46
        month (relative to referencePeriodEnd).
47
48
        This is more sophisticated than an %IndexedCashFlow because it
49
        does date calculations itself.
50
51
        \todo we do not do any convexity adjustment for lags different
52
              to the natural ZCIIS lag that was used to create the
53
              forward inflation curve.
54
    */
55
    class CPICoupon : public InflationCoupon {
56
      public:
57
        //! \name Constructors
58
        //@{
59
        /*! This constructor takes the base CPI to be used in the calculations. */
60
        CPICoupon(Real baseCPI,
61
                  const Date& paymentDate,
62
                  Real nominal,
63
                  const Date& startDate,
64
                  const Date& endDate,
65
                  const ext::shared_ptr<ZeroInflationIndex>& index,
66
                  const Period& observationLag,
67
                  CPI::InterpolationType observationInterpolation,
68
                  const DayCounter& dayCounter,
69
                  Real fixedRate,
70
                  const Date& refPeriodStart = Date(),
71
                  const Date& refPeriodEnd = Date(),
72
                  const Date& exCouponDate = Date());
73
74
        /*! This constructor takes a base date; the coupon will use it
75
            to retrieve the base CPI to be used in the calculations.
76
        */
77
        CPICoupon(const Date& baseDate,
78
                  const Date& paymentDate,
79
                  Real nominal,
80
                  const Date& startDate,
81
                  const Date& endDate,
82
                  const ext::shared_ptr<ZeroInflationIndex>& index,
83
                  const Period& observationLag,
84
                  CPI::InterpolationType observationInterpolation,
85
                  const DayCounter& dayCounter,
86
                  Real fixedRate,
87
                  const Date& refPeriodStart = Date(),
88
                  const Date& refPeriodEnd = Date(),
89
                  const Date& exCouponDate = Date());
90
91
        /*! This constructor takes both a base CPI and a base date.
92
            If both are passed, the base CPI is used in the calculations.
93
        */
94
        CPICoupon(Real baseCPI,
95
                  const Date& baseDate,
96
                  const Date& paymentDate,
97
                  Real nominal,
98
                  const Date& startDate,
99
                  const Date& endDate,
100
                  const ext::shared_ptr<ZeroInflationIndex>& index,
101
                  const Period& observationLag,
102
                  CPI::InterpolationType observationInterpolation,
103
                  const DayCounter& dayCounter,
104
                  Real fixedRate,
105
                  const Date& refPeriodStart = Date(),
106
                  const Date& refPeriodEnd = Date(),
107
                  const Date& exCouponDate = Date());
108
        //@}
109
110
        //! \name Inspectors
111
        //@{
112
        //! fixed rate that will be inflated by the index ratio
113
        Real fixedRate() const;
114
115
        //! base value for the CPI index
116
        /*! \warning make sure that the interpolation used to create
117
                     this is what you are using for the fixing,
118
                     i.e. the observationInterpolation.
119
        */
120
        Rate baseCPI() const;
121
122
        //! base date for the base fixing of the CPI index
123
        Date baseDate() const;
124
125
        //! how do you observe the index?  as-is, flat, linear?
126
        CPI::InterpolationType observationInterpolation() const;
127
128
        //! index used
129
        ext::shared_ptr<ZeroInflationIndex> cpiIndex() const;
130
        //@}
131
132
        //! \name Calculations
133
        //@{
134
        Real accruedAmount(const Date&) const override;
135
136
        //! the index value observed (with a lag) at the end date
137
        Rate indexFixing() const override;
138
139
        //! the ratio between the index fixing at the passed date and the base CPI
140
        /*! No adjustments are applied */
141
        Rate indexRatio(Date d) const;
142
143
        //! the ratio between the end index fixing and the base CPI
144
        /*! This might include adjustments calculated by the pricer */
145
        Rate adjustedIndexGrowth() const;
146
        //@}
147
148
        //! \name Visitability
149
        //@{
150
        void accept(AcyclicVisitor&) override;
151
        //@}
152
      protected:
153
        Real baseCPI_;
154
        Real fixedRate_;
155
        CPI::InterpolationType observationInterpolation_;
156
        Date baseDate_;
157
158
        bool checkPricerImpl(const ext::shared_ptr<InflationCouponPricer>&) const override;
159
    };
160
161
162
    //! Cash flow paying the performance of a CPI (zero inflation) index
163
    /*! It is NOT a coupon, i.e. no accruals. */
164
    class CPICashFlow : public IndexedCashFlow {
165
      public:
166
        CPICashFlow(Real notional,
167
                    const ext::shared_ptr<ZeroInflationIndex>& index,
168
                    const Date& baseDate,
169
                    Real baseFixing,
170
                    const Date& observationDate,
171
                    const Period& observationLag,
172
                    CPI::InterpolationType interpolation,
173
                    const Date& paymentDate,
174
                    bool growthOnly = false);
175
176
        //! value used on base date
177
        /*! This does not have to agree with index on that date. */
178
        Real baseFixing() const override;
179
        //! you may not have a valid date
180
        Date baseDate() const override;
181
182
0
        Date observationDate() const { return observationDate_; }
183
0
        Period observationLag() const { return observationLag_; }
184
        //! do you want linear/constant/as-index interpolation of future data?
185
0
        virtual CPI::InterpolationType interpolation() const {
186
0
            return interpolation_;
187
0
        }
188
0
        virtual Frequency frequency() const { return frequency_; }
189
190
        ext::shared_ptr<ZeroInflationIndex> cpiIndex() const;
191
192
        Real indexFixing() const override;
193
194
      protected:
195
        Real baseFixing_;
196
        Date observationDate_;
197
        Period observationLag_;
198
        CPI::InterpolationType interpolation_;
199
        Frequency frequency_;
200
    };
201
202
203
    //! Helper class building a sequence of capped/floored CPI coupons.
204
    /*! Also allowing for the inflated notional at the end...
205
        especially if there is only one date in the schedule.
206
        If the fixed rate is zero you get a FixedRateCoupon, otherwise
207
        you get a ZeroInflationCoupon.
208
    */
209
    class CPILeg {
210
      public:
211
        CPILeg(Schedule schedule,
212
               ext::shared_ptr<ZeroInflationIndex> index,
213
               Real baseCPI,
214
               const Period& observationLag);
215
        CPILeg& withNotionals(Real notional);
216
        CPILeg& withNotionals(const std::vector<Real>& notionals);
217
        CPILeg& withFixedRates(Real fixedRate);
218
        CPILeg& withFixedRates(const std::vector<Real>& fixedRates);
219
        CPILeg& withPaymentDayCounter(const DayCounter&);
220
        CPILeg& withPaymentAdjustment(BusinessDayConvention);
221
        CPILeg& withPaymentCalendar(const Calendar&);
222
        CPILeg& withObservationInterpolation(CPI::InterpolationType);
223
        CPILeg& withSubtractInflationNominal(bool);
224
        CPILeg& withCaps(Rate cap);
225
        CPILeg& withCaps(const std::vector<Rate>& caps);
226
        CPILeg& withFloors(Rate floor);
227
        CPILeg& withFloors(const std::vector<Rate>& floors);
228
        CPILeg& withExCouponPeriod(const Period&,
229
                                         const Calendar&,
230
                                         BusinessDayConvention,
231
                                         bool endOfMonth = false);
232
        CPILeg& withBaseDate(const Date& baseDate);
233
234
        operator Leg() const;
235
236
      private:
237
        Schedule schedule_;
238
        ext::shared_ptr<ZeroInflationIndex> index_;
239
        Real baseCPI_;
240
        Period observationLag_;
241
        std::vector<Real> notionals_;
242
        std::vector<Real> fixedRates_;
243
        DayCounter paymentDayCounter_;
244
        BusinessDayConvention paymentAdjustment_ = ModifiedFollowing;
245
        Calendar paymentCalendar_;
246
        CPI::InterpolationType observationInterpolation_ = CPI::AsIndex;
247
        bool subtractInflationNominal_ = true;
248
        std::vector<Rate> caps_, floors_;
249
        Period exCouponPeriod_;
250
        Calendar exCouponCalendar_;
251
        BusinessDayConvention exCouponAdjustment_ = Following;
252
        bool exCouponEndOfMonth_ = false;
253
        Date baseDate_;
254
    };
255
256
257
    // inline definitions
258
259
0
    inline Real CPICoupon::fixedRate() const {
260
0
        return fixedRate_;
261
0
    }
262
263
0
    inline Rate CPICoupon::adjustedIndexGrowth() const {
264
0
        return rate()/fixedRate();
265
0
    }
266
267
0
    inline Rate CPICoupon::indexFixing() const {
268
0
        return CPI::laggedFixing(cpiIndex(), accrualEndDate(), observationLag(), observationInterpolation());
269
0
    }
270
271
0
    inline Rate CPICoupon::baseCPI() const {
272
0
        return baseCPI_;
273
0
    }
274
275
0
    inline Date CPICoupon::baseDate() const {
276
0
        return baseDate_;
277
0
    }
278
279
0
    inline CPI::InterpolationType CPICoupon::observationInterpolation() const {
280
0
        return observationInterpolation_;
281
0
    }
282
283
0
    inline ext::shared_ptr<ZeroInflationIndex> CPICoupon::cpiIndex() const {
284
0
        return ext::dynamic_pointer_cast<ZeroInflationIndex>(index());
285
0
    }
286
287
288
0
    inline ext::shared_ptr<ZeroInflationIndex> CPICashFlow::cpiIndex() const {
289
0
        return ext::dynamic_pointer_cast<ZeroInflationIndex>(index());
290
0
    }
291
292
}
293
294
#endif