Coverage Report

Created: 2025-11-04 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}