/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 |