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 <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 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
33namespace 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 CPICoupon(Real baseCPI,
60 const Date& paymentDate,
61 Real nominal,
62 const Date& startDate,
63 const Date& endDate,
64 const ext::shared_ptr<ZeroInflationIndex>& index,
65 const Period& observationLag,
66 CPI::InterpolationType observationInterpolation,
67 const DayCounter& dayCounter,
68 Real fixedRate,
69 const Date& refPeriodStart = Date(),
70 const Date& refPeriodEnd = Date(),
71 const Date& exCouponDate = Date());
72
73 CPICoupon(const Date& baseDate, // user provided, could be arbitrary
74 const Date& paymentDate,
75 Real nominal,
76 const Date& startDate,
77 const Date& endDate,
78 const ext::shared_ptr<ZeroInflationIndex>& index,
79 const Period& observationLag,
80 CPI::InterpolationType observationInterpolation,
81 const DayCounter& dayCounter,
82 Real fixedRate,
83 const Date& refPeriodStart = Date(),
84 const Date& refPeriodEnd = Date(),
85 const Date& exCouponDate = Date());
86
87 CPICoupon(Real baseCPI, // user provided, could be arbitrary
88 const Date& baseDate,
89 const Date& paymentDate,
90 Real nominal,
91 const Date& startDate,
92 const Date& endDate,
93 const ext::shared_ptr<ZeroInflationIndex>& index,
94 const Period& observationLag,
95 CPI::InterpolationType observationInterpolation,
96 const DayCounter& dayCounter,
97 Real fixedRate,
98 const Date& refPeriodStart = Date(),
99 const Date& refPeriodEnd = Date(),
100 const Date& exCouponDate = Date());
101
102 /*! \deprecated Use one of the constructors without spread.
103 Deprecated in version 1.31.
104 */
105 QL_DEPRECATED
106 CPICoupon(Real baseCPI, // user provided, could be arbitrary
107 const Date& paymentDate,
108 Real nominal,
109 const Date& startDate,
110 const Date& endDate,
111 const ext::shared_ptr<ZeroInflationIndex>& index,
112 const Period& observationLag,
113 CPI::InterpolationType observationInterpolation,
114 const DayCounter& dayCounter,
115 Real fixedRate,
116 Spread spread,
117 const Date& refPeriodStart = Date(),
118 const Date& refPeriodEnd = Date(),
119 const Date& exCouponDate = Date());
120
121 /*! \deprecated Use one of the constructors without spread.
122 Deprecated in version 1.31.
123 */
124 QL_DEPRECATED
125 CPICoupon(const Date& baseDate, // user provided, could be arbitrary
126 const Date& paymentDate,
127 Real nominal,
128 const Date& startDate,
129 const Date& endDate,
130 const ext::shared_ptr<ZeroInflationIndex>& index,
131 const Period& observationLag,
132 CPI::InterpolationType observationInterpolation,
133 const DayCounter& dayCounter,
134 Real fixedRate,
135 Spread spread,
136 const Date& refPeriodStart = Date(),
137 const Date& refPeriodEnd = Date(),
138 const Date& exCouponDate = Date());
139
140 /*! \deprecated Use one of the constructors without spread.
141 Deprecated in version 1.31.
142 */
143 QL_DEPRECATED
144 CPICoupon(Real baseCPI, // user provided, could be arbitrary
145 const Date& baseDate,
146 const Date& paymentDate,
147 Real nominal,
148 const Date& startDate,
149 const Date& endDate,
150 const ext::shared_ptr<ZeroInflationIndex>& index,
151 const Period& observationLag,
152 CPI::InterpolationType observationInterpolation,
153 const DayCounter& dayCounter,
154 Real fixedRate,
155 Spread spread,
156 const Date& refPeriodStart = Date(),
157 const Date& refPeriodEnd = Date(),
158 const Date& exCouponDate = Date());
159 //@}
160
161 QL_DEPRECATED_DISABLE_WARNING
162 ~CPICoupon() override = default;
163 QL_DEPRECATED_ENABLE_WARNING
164
165 //! \name Inspectors
166 //@{
167 //! fixed rate that will be inflated by the index ratio
168 Real fixedRate() const;
169
170 /*! \deprecated Do not use this method. A spread doesn't make sense for this coupon.
171 Deprecated in version 1.31.
172 */
173 [[deprecated("Do not use this method. A spread doesn't make sense for this coupon.")]]
174 Spread spread() const;
175
176 //! base value for the CPI index
177 /*! \warning make sure that the interpolation used to create
178 this is what you are using for the fixing,
179 i.e. the observationInterpolation.
180 */
181 Rate baseCPI() const;
182
183 //! base date for the base fixing of the CPI index
184 Date baseDate() const;
185
186 //! how do you observe the index? as-is, flat, linear?
187 CPI::InterpolationType observationInterpolation() const;
188
189 //! index used
190 ext::shared_ptr<ZeroInflationIndex> cpiIndex() const;
191 //@}
192
193 //! \name Calculations
194 //@{
195 Real accruedAmount(const Date&) const override;
196
197 //! the index value observed (with a lag) at the end date
198 Rate indexFixing() const override;
199
200 //! the ratio between the index fixing at the passed date and the base CPI
201 /*! No adjustments are applied */
202 Rate indexRatio(Date d) const;
203
204 //! the ratio between the end index fixing and the base CPI
205 /*! This might include adjustments calculated by the pricer */
206 Rate adjustedIndexGrowth() const;
207 //@}
208
209 //! \name Visitability
210 //@{
211 void accept(AcyclicVisitor&) override;
212 //@}
213 protected:
214 Real baseCPI_;
215 Real fixedRate_;
216 /*! \deprecated Don't use this data member. A spread doesn't make sense for this coupon.
217 Deprecated in version 1.31.
218 */
219 [[deprecated("Do not use this data member. A spread doesn't make sense for this coupon.")]]
220 Spread spread_;
221 CPI::InterpolationType observationInterpolation_;
222 Date baseDate_;
223
224 bool checkPricerImpl(const ext::shared_ptr<InflationCouponPricer>&) const override;
225 };
226
227
228 //! Cash flow paying the performance of a CPI (zero inflation) index
229 /*! It is NOT a coupon, i.e. no accruals. */
230 class CPICashFlow : public IndexedCashFlow {
231 public:
232 CPICashFlow(Real notional,
233 const ext::shared_ptr<ZeroInflationIndex>& index,
234 const Date& baseDate,
235 Real baseFixing,
236 const Date& observationDate,
237 const Period& observationLag,
238 CPI::InterpolationType interpolation,
239 const Date& paymentDate,
240 bool growthOnly = false);
241
242 //! value used on base date
243 /*! This does not have to agree with index on that date. */
244 Real baseFixing() const override;
245 //! you may not have a valid date
246 Date baseDate() const override;
247
248 Date observationDate() const { return observationDate_; }
249 Period observationLag() const { return observationLag_; }
250 //! do you want linear/constant/as-index interpolation of future data?
251 virtual CPI::InterpolationType interpolation() const {
252 return interpolation_;
253 }
254 virtual Frequency frequency() const { return frequency_; }
255
256 ext::shared_ptr<ZeroInflationIndex> cpiIndex() const;
257
258 Real indexFixing() const override;
259
260 Real amount() const override;
261
262 protected:
263 Real baseFixing_;
264 Date observationDate_;
265 Period observationLag_;
266 CPI::InterpolationType interpolation_;
267 Frequency frequency_;
268 };
269
270
271 //! Helper class building a sequence of capped/floored CPI coupons.
272 /*! Also allowing for the inflated notional at the end...
273 especially if there is only one date in the schedule.
274 If the fixed rate is zero you get a FixedRateCoupon, otherwise
275 you get a ZeroInflationCoupon.
276 */
277 class CPILeg {
278 public:
279 CPILeg(const Schedule& schedule,
280 ext::shared_ptr<ZeroInflationIndex> index,
281 Real baseCPI,
282 const Period& observationLag);
283 CPILeg& withNotionals(Real notional);
284 CPILeg& withNotionals(const std::vector<Real>& notionals);
285 CPILeg& withFixedRates(Real fixedRate);
286 CPILeg& withFixedRates(const std::vector<Real>& fixedRates);
287 CPILeg& withPaymentDayCounter(const DayCounter&);
288 CPILeg& withPaymentAdjustment(BusinessDayConvention);
289 CPILeg& withPaymentCalendar(const Calendar&);
290 CPILeg& withObservationInterpolation(CPI::InterpolationType);
291 CPILeg& withSubtractInflationNominal(bool);
292 /*! \deprecated Do not use this method. A spread doesn't make sense for these coupons.
293 Deprecated in version 1.31.
294 */
295 [[deprecated("Do not use this method. A spread doesn't make sense for these coupons.")]]
296 CPILeg& withSpreads(Spread spread);
297 /*! \deprecated Do not use this method. A spread doesn't make sense for these coupons.
298 Deprecated in version 1.31.
299 */
300 [[deprecated("Do not use this method. A spread doesn't make sense for these coupons.")]]
301 CPILeg& withSpreads(const std::vector<Spread>& spreads);
302 CPILeg& withCaps(Rate cap);
303 CPILeg& withCaps(const std::vector<Rate>& caps);
304 CPILeg& withFloors(Rate floor);
305 CPILeg& withFloors(const std::vector<Rate>& floors);
306 CPILeg& withExCouponPeriod(const Period&,
307 const Calendar&,
308 BusinessDayConvention,
309 bool endOfMonth = false);
310 CPILeg& withBaseDate(const Date& baseDate);
311
312 operator Leg() const;
313
314 private:
315 Schedule schedule_;
316 ext::shared_ptr<ZeroInflationIndex> index_;
317 Real baseCPI_;
318 Period observationLag_;
319 std::vector<Real> notionals_;
320 std::vector<Real> fixedRates_;
321 DayCounter paymentDayCounter_;
322 BusinessDayConvention paymentAdjustment_ = ModifiedFollowing;
323 Calendar paymentCalendar_;
324 CPI::InterpolationType observationInterpolation_ = CPI::AsIndex;
325 bool subtractInflationNominal_ = true;
326 std::vector<Spread> spreads_;
327 std::vector<Rate> caps_, floors_;
328 Period exCouponPeriod_;
329 Calendar exCouponCalendar_;
330 BusinessDayConvention exCouponAdjustment_ = Following;
331 bool exCouponEndOfMonth_ = false;
332 Date baseDate_ = Null<Date>();
333 };
334
335
336 // inline definitions
337
338 inline Real CPICoupon::fixedRate() const {
339 return fixedRate_;
340 }
341
342 inline Real CPICoupon::spread() const {
343 QL_DEPRECATED_DISABLE_WARNING
344 return spread_;
345 QL_DEPRECATED_ENABLE_WARNING
346 }
347
348 inline Rate CPICoupon::adjustedIndexGrowth() const {
349 QL_DEPRECATED_DISABLE_WARNING
350 return (rate()-spread())/fixedRate();
351 QL_DEPRECATED_ENABLE_WARNING
352 }
353
354 inline Rate CPICoupon::indexFixing() const {
355 return CPI::laggedFixing(index: cpiIndex(), date: accrualEndDate(), observationLag: observationLag(), interpolationType: observationInterpolation());
356 }
357
358 inline Rate CPICoupon::baseCPI() const {
359 return baseCPI_;
360 }
361
362 inline Date CPICoupon::baseDate() const {
363 return baseDate_;
364 }
365
366 inline CPI::InterpolationType CPICoupon::observationInterpolation() const {
367 return observationInterpolation_;
368 }
369
370 inline ext::shared_ptr<ZeroInflationIndex> CPICoupon::cpiIndex() const {
371 return ext::dynamic_pointer_cast<ZeroInflationIndex>(r: index());
372 }
373
374
375 inline ext::shared_ptr<ZeroInflationIndex> CPICashFlow::cpiIndex() const {
376 return ext::dynamic_pointer_cast<ZeroInflationIndex>(r: index());
377 }
378
379}
380
381#endif
382

source code of quantlib/ql/cashflows/cpicoupon.hpp