/src/quantlib/ql/termstructures/inflationtermstructure.cpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2007, 2009 Chris Kenyon |
5 | | |
6 | | This file is part of QuantLib, a free-software/open-source library |
7 | | for financial quantitative analysts and developers - http://quantlib.org/ |
8 | | |
9 | | QuantLib is free software: you can redistribute it and/or modify it |
10 | | under the terms of the QuantLib license. You should have received a |
11 | | copy of the license along with this program; if not, please email |
12 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
13 | | <https://www.quantlib.org/license.shtml>. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, but WITHOUT |
16 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
18 | | */ |
19 | | |
20 | | #include <ql/indexes/inflationindex.hpp> |
21 | | #include <ql/termstructures/inflationtermstructure.hpp> |
22 | | #include <utility> |
23 | | |
24 | | namespace QuantLib { |
25 | | |
26 | | QL_DEPRECATED_DISABLE_WARNING |
27 | | |
28 | | InflationTermStructure::InflationTermStructure( |
29 | | Date baseDate, |
30 | | Frequency frequency, |
31 | | const DayCounter& dayCounter, |
32 | | ext::shared_ptr<Seasonality> seasonality, |
33 | | Rate baseRate) |
34 | 0 | : TermStructure(dayCounter), seasonality_(std::move(seasonality)), |
35 | 0 | frequency_(frequency), baseRate_(baseRate), baseDate_(baseDate) { |
36 | 0 | if (seasonality_ != nullptr) { |
37 | 0 | QL_REQUIRE(seasonality_->isConsistent(*this), |
38 | 0 | "Seasonality inconsistent with inflation term structure"); |
39 | 0 | } |
40 | 0 | } |
41 | | |
42 | | InflationTermStructure::InflationTermStructure( |
43 | | const Date& referenceDate, |
44 | | Date baseDate, |
45 | | Frequency frequency, |
46 | | const DayCounter& dayCounter, |
47 | | ext::shared_ptr<Seasonality> seasonality, |
48 | | Rate baseRate) |
49 | 0 | : TermStructure(referenceDate, Calendar(), dayCounter), seasonality_(std::move(seasonality)), |
50 | 0 | frequency_(frequency), baseRate_(baseRate), baseDate_(baseDate) { |
51 | 0 | if (seasonality_ != nullptr) { |
52 | 0 | QL_REQUIRE(seasonality_->isConsistent(*this), |
53 | 0 | "Seasonality inconsistent with inflation term structure"); |
54 | 0 | } |
55 | 0 | } |
56 | | |
57 | | InflationTermStructure::InflationTermStructure( |
58 | | Natural settlementDays, |
59 | | const Calendar& calendar, |
60 | | Date baseDate, |
61 | | Frequency frequency, |
62 | | const DayCounter& dayCounter, |
63 | | ext::shared_ptr<Seasonality> seasonality, |
64 | | Rate baseRate) |
65 | 0 | : TermStructure(settlementDays, calendar, dayCounter), seasonality_(std::move(seasonality)), |
66 | 0 | frequency_(frequency), baseRate_(baseRate), baseDate_(baseDate) { |
67 | 0 | if (seasonality_ != nullptr) { |
68 | 0 | QL_REQUIRE(seasonality_->isConsistent(*this), |
69 | 0 | "Seasonality inconsistent with inflation term structure"); |
70 | 0 | } |
71 | 0 | } |
72 | | |
73 | | QL_DEPRECATED_ENABLE_WARNING |
74 | | |
75 | 0 | Date InflationTermStructure::baseDate() const { |
76 | 0 | return baseDate_; |
77 | 0 | } |
78 | | |
79 | | void InflationTermStructure::setSeasonality( |
80 | 0 | const ext::shared_ptr<Seasonality>& seasonality) { |
81 | | // always reset, whether with null or new pointer |
82 | 0 | seasonality_ = seasonality; |
83 | 0 | if (seasonality_ != nullptr) { |
84 | 0 | QL_REQUIRE(seasonality_->isConsistent(*this), |
85 | 0 | "Seasonality inconsistent with inflation term structure"); |
86 | 0 | } |
87 | 0 | update(); |
88 | 0 | } |
89 | | |
90 | | |
91 | | void InflationTermStructure::checkRange(const Date& d, |
92 | 0 | bool extrapolate) const { |
93 | 0 | QL_REQUIRE(d >= baseDate(), |
94 | 0 | "date (" << d << ") is before base date (" << baseDate() << ")"); |
95 | 0 | QL_REQUIRE(extrapolate || allowsExtrapolation() || d <= maxDate(), |
96 | 0 | "date (" << d << ") is past max curve date (" |
97 | 0 | << maxDate() << ")"); |
98 | 0 | } |
99 | | |
100 | | void InflationTermStructure::checkRange(Time t, |
101 | 0 | bool extrapolate) const { |
102 | 0 | QL_REQUIRE(t >= timeFromReference(baseDate()), |
103 | 0 | "time (" << t << ") is before base date"); |
104 | 0 | QL_REQUIRE(extrapolate || allowsExtrapolation() || t <= maxTime(), |
105 | 0 | "time (" << t << ") is past max curve time (" |
106 | 0 | << maxTime() << ")"); |
107 | 0 | } |
108 | | |
109 | | |
110 | | ZeroInflationTermStructure::ZeroInflationTermStructure( |
111 | | Date baseDate, |
112 | | Frequency frequency, |
113 | | const DayCounter& dayCounter, |
114 | | const ext::shared_ptr<Seasonality>& seasonality) |
115 | 0 | : InflationTermStructure(baseDate, frequency, dayCounter, seasonality) {} |
116 | | |
117 | | ZeroInflationTermStructure::ZeroInflationTermStructure( |
118 | | const Date& referenceDate, |
119 | | Date baseDate, |
120 | | Frequency frequency, |
121 | | const DayCounter& dayCounter, |
122 | | const ext::shared_ptr<Seasonality>& seasonality) |
123 | 0 | : InflationTermStructure(referenceDate, baseDate, frequency, dayCounter, seasonality) {} |
124 | | |
125 | | ZeroInflationTermStructure::ZeroInflationTermStructure( |
126 | | Natural settlementDays, |
127 | | const Calendar& calendar, |
128 | | Date baseDate, |
129 | | Frequency frequency, |
130 | | const DayCounter& dayCounter, |
131 | | const ext::shared_ptr<Seasonality>& seasonality) |
132 | 0 | : InflationTermStructure(settlementDays, calendar, baseDate, frequency, dayCounter, seasonality) {} |
133 | | |
134 | | Rate ZeroInflationTermStructure::zeroRate(const Date &d, const Period& instObsLag, |
135 | | bool forceLinearInterpolation, |
136 | 0 | bool extrapolate) const { |
137 | |
|
138 | 0 | Period useLag = instObsLag; |
139 | 0 | if (instObsLag == Period(-1,Days)) { |
140 | 0 | useLag = Period(0, Days); |
141 | 0 | } |
142 | |
|
143 | 0 | Rate zeroRate; |
144 | 0 | if (forceLinearInterpolation) { |
145 | 0 | std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency()); |
146 | 0 | dd.second = dd.second + Period(1,Days); |
147 | 0 | Real dp = dd.second - dd.first; |
148 | 0 | Real dt = d - dd.first; |
149 | | // if we are interpolating we only check the exact point |
150 | | // this prevents falling off the end at curve maturity |
151 | 0 | InflationTermStructure::checkRange(d, extrapolate); |
152 | 0 | Time t1 = timeFromReference(dd.first); |
153 | 0 | Time t2 = timeFromReference(dd.second); |
154 | 0 | Rate z1 = zeroRateImpl(t1); |
155 | 0 | Rate z2 = zeroRateImpl(t2); |
156 | 0 | zeroRate = z1 + (z2-z1) * (dt/dp); |
157 | 0 | } else { |
158 | 0 | std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency()); |
159 | 0 | InflationTermStructure::checkRange(dd.first, extrapolate); |
160 | 0 | Time t = timeFromReference(dd.first); |
161 | 0 | zeroRate = zeroRateImpl(t); |
162 | 0 | } |
163 | |
|
164 | 0 | if (hasSeasonality()) { |
165 | 0 | zeroRate = seasonality()->correctZeroRate(d-useLag, zeroRate, *this); |
166 | 0 | } |
167 | 0 | return zeroRate; |
168 | 0 | } |
169 | | |
170 | | Rate ZeroInflationTermStructure::zeroRate(Time t, |
171 | 0 | bool extrapolate) const { |
172 | 0 | checkRange(t, extrapolate); |
173 | 0 | return zeroRateImpl(t); |
174 | 0 | } |
175 | | |
176 | | |
177 | | QL_DEPRECATED_DISABLE_WARNING |
178 | | |
179 | | YoYInflationTermStructure::YoYInflationTermStructure( |
180 | | Date baseDate, |
181 | | Rate baseYoYRate, |
182 | | Frequency frequency, |
183 | | const DayCounter& dayCounter, |
184 | | const ext::shared_ptr<Seasonality> &seasonality) |
185 | 0 | : InflationTermStructure(baseDate, frequency, dayCounter, seasonality, baseYoYRate) {} |
186 | | |
187 | | YoYInflationTermStructure::YoYInflationTermStructure( |
188 | | const Date& referenceDate, |
189 | | Date baseDate, |
190 | | Rate baseYoYRate, |
191 | | Frequency frequency, |
192 | | const DayCounter& dayCounter, |
193 | | const ext::shared_ptr<Seasonality> &seasonality) |
194 | 0 | : InflationTermStructure(referenceDate, baseDate, frequency, dayCounter, seasonality, baseYoYRate) {} |
195 | | |
196 | | YoYInflationTermStructure::YoYInflationTermStructure( |
197 | | Natural settlementDays, |
198 | | const Calendar& calendar, |
199 | | Date baseDate, |
200 | | Rate baseYoYRate, |
201 | | Frequency frequency, |
202 | | const DayCounter& dayCounter, |
203 | | const ext::shared_ptr<Seasonality> &seasonality) |
204 | 0 | : InflationTermStructure(settlementDays, calendar, baseDate, frequency, dayCounter, seasonality, baseYoYRate) {} |
205 | | |
206 | | YoYInflationTermStructure::YoYInflationTermStructure( |
207 | | Date baseDate, |
208 | | Rate baseYoYRate, |
209 | | Frequency frequency, |
210 | | bool indexIsInterpolated, |
211 | | const DayCounter& dayCounter, |
212 | | const ext::shared_ptr<Seasonality> &seasonality) |
213 | 0 | : YoYInflationTermStructure(baseDate, baseYoYRate, frequency, dayCounter, seasonality) { |
214 | 0 | indexIsInterpolated_ = indexIsInterpolated; |
215 | 0 | } |
216 | | |
217 | | YoYInflationTermStructure::YoYInflationTermStructure( |
218 | | const Date& referenceDate, |
219 | | Date baseDate, |
220 | | Rate baseYoYRate, |
221 | | Frequency frequency, |
222 | | bool indexIsInterpolated, |
223 | | const DayCounter& dayCounter, |
224 | | const ext::shared_ptr<Seasonality> &seasonality) |
225 | 0 | : YoYInflationTermStructure(referenceDate, baseDate, baseYoYRate, |
226 | 0 | frequency, dayCounter, seasonality) { |
227 | 0 | indexIsInterpolated_ = indexIsInterpolated; |
228 | 0 | } |
229 | | |
230 | | YoYInflationTermStructure::YoYInflationTermStructure( |
231 | | Natural settlementDays, |
232 | | const Calendar& calendar, |
233 | | Date baseDate, |
234 | | Rate baseYoYRate, |
235 | | Frequency frequency, |
236 | | bool indexIsInterpolated, |
237 | | const DayCounter& dayCounter, |
238 | | const ext::shared_ptr<Seasonality> &seasonality) |
239 | 0 | : YoYInflationTermStructure(settlementDays, calendar, baseDate, baseYoYRate, |
240 | 0 | frequency, dayCounter, seasonality) { |
241 | 0 | indexIsInterpolated_ = indexIsInterpolated; |
242 | 0 | } |
243 | | |
244 | | QL_DEPRECATED_ENABLE_WARNING |
245 | | |
246 | | Rate YoYInflationTermStructure::yoyRate(const Date &d, const Period& instObsLag, |
247 | | bool forceLinearInterpolation, |
248 | 0 | bool extrapolate) const { |
249 | |
|
250 | 0 | Period useLag = instObsLag; |
251 | 0 | if (instObsLag == Period(-1,Days)) { |
252 | 0 | useLag = Period(0, Days); |
253 | 0 | } |
254 | |
|
255 | 0 | Rate yoyRate; |
256 | 0 | if (forceLinearInterpolation) { |
257 | 0 | std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency()); |
258 | 0 | dd.second = dd.second + Period(1,Days); |
259 | 0 | Real dp = dd.second - dd.first; |
260 | 0 | Real dt = (d-useLag) - dd.first; |
261 | | // if we are interpolating we only check the exact point |
262 | | // this prevents falling off the end at curve maturity |
263 | 0 | InflationTermStructure::checkRange(d, extrapolate); |
264 | 0 | Time t1 = timeFromReference(dd.first); |
265 | 0 | Time t2 = timeFromReference(dd.second); |
266 | 0 | Rate y1 = yoyRateImpl(t1); |
267 | 0 | Rate y2 = yoyRateImpl(t2); |
268 | 0 | yoyRate = y1 + (y2-y1) * (dt/dp); |
269 | 0 | } else { |
270 | 0 | QL_DEPRECATED_DISABLE_WARNING |
271 | 0 | if (indexIsInterpolated()) { |
272 | 0 | InflationTermStructure::checkRange(d-useLag, extrapolate); |
273 | 0 | Time t = timeFromReference(d-useLag); |
274 | 0 | yoyRate = yoyRateImpl(t); |
275 | 0 | } else { |
276 | 0 | std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency()); |
277 | 0 | InflationTermStructure::checkRange(dd.first, extrapolate); |
278 | 0 | Time t = timeFromReference(dd.first); |
279 | 0 | yoyRate = yoyRateImpl(t); |
280 | 0 | } |
281 | 0 | QL_DEPRECATED_ENABLE_WARNING |
282 | 0 | } |
283 | |
|
284 | 0 | if (hasSeasonality()) { |
285 | 0 | yoyRate = seasonality()->correctYoYRate(d-useLag, yoyRate, *this); |
286 | 0 | } |
287 | 0 | return yoyRate; |
288 | 0 | } |
289 | | |
290 | | Rate YoYInflationTermStructure::yoyRate(Time t, |
291 | 0 | bool extrapolate) const { |
292 | 0 | checkRange(t, extrapolate); |
293 | 0 | return yoyRateImpl(t); |
294 | 0 | } |
295 | | |
296 | | |
297 | | |
298 | | |
299 | | std::pair<Date,Date> inflationPeriod(const Date& d, |
300 | 0 | Frequency frequency) { |
301 | 0 | Month month = d.month(); |
302 | 0 | Year year = d.year(); |
303 | |
|
304 | 0 | Month startMonth, endMonth; |
305 | 0 | switch (frequency) { |
306 | 0 | case Annual: |
307 | 0 | case Semiannual: |
308 | 0 | case EveryFourthMonth: |
309 | 0 | case Quarterly: |
310 | 0 | case Bimonthly: { |
311 | 0 | int nMonths = 12 / frequency; |
312 | 0 | startMonth = Month(month - (month - 1) % nMonths); |
313 | 0 | endMonth = Month(startMonth + nMonths - 1); |
314 | 0 | } |
315 | 0 | break; |
316 | 0 | case Monthly: |
317 | 0 | startMonth = endMonth = month; |
318 | 0 | break; |
319 | 0 | default: |
320 | 0 | QL_FAIL("Frequency not handled: " << frequency); |
321 | 0 | break; |
322 | 0 | }; |
323 | |
|
324 | 0 | return {Date(1, startMonth, year), Date::endOfMonth(Date(1, endMonth, year))}; |
325 | 0 | } |
326 | | |
327 | | |
328 | | Time inflationYearFraction(Frequency f, bool indexIsInterpolated, |
329 | | const DayCounter &dayCounter, |
330 | 0 | const Date &d1, const Date &d2) { |
331 | |
|
332 | 0 | Time t=0; |
333 | 0 | if (indexIsInterpolated) { |
334 | | // N.B. we do not use linear interpolation between flat |
335 | | // fixing forecasts for forecasts. This avoids awkwardnesses |
336 | | // when bootstrapping the inflation curve. |
337 | 0 | t = dayCounter.yearFraction(d1, d2); |
338 | 0 | } else { |
339 | | // I.e. fixing is constant for the whole inflation period. |
340 | | // Use the value for half way along the period. |
341 | | // But the inflation time is the time between period starts |
342 | 0 | std::pair<Date,Date> limD1 = inflationPeriod(d1, f); |
343 | 0 | std::pair<Date,Date> limD2 = inflationPeriod(d2, f); |
344 | 0 | t = dayCounter.yearFraction(limD1.first, limD2.first); |
345 | 0 | } |
346 | |
|
347 | 0 | return t; |
348 | 0 | } |
349 | | |
350 | | |
351 | | } |