Coverage Report

Created: 2026-02-03 07:02

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
0
    Rate ZeroInflationTermStructure::zeroRate(const Date &d, bool extrapolate) const {
135
0
        QL_DEPRECATED_DISABLE_WARNING
136
0
        return zeroRate(d, Period(0, Days), false, extrapolate);
137
0
        QL_DEPRECATED_ENABLE_WARNING
138
0
    }
139
140
    Rate ZeroInflationTermStructure::zeroRate(const Date &d, const Period& instObsLag,
141
                                              bool forceLinearInterpolation,
142
0
                                              bool extrapolate) const {
143
144
0
        Period useLag = instObsLag;
145
0
        if (instObsLag == Period(-1,Days)) {
146
0
            useLag = Period(0, Days);
147
0
        }
148
149
0
        Rate zeroRate;
150
0
        if (forceLinearInterpolation) {
151
0
            std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency());
152
0
            dd.second = dd.second + Period(1,Days);
153
0
            Real dp = dd.second - dd.first;
154
0
            Real dt = d - dd.first;
155
            // if we are interpolating we only check the exact point
156
            // this prevents falling off the end at curve maturity
157
0
            InflationTermStructure::checkRange(d, extrapolate);
158
0
            Time t1 = timeFromReference(dd.first);
159
0
            Time t2 = timeFromReference(dd.second);
160
0
            Rate z1 = zeroRateImpl(t1);
161
0
            Rate z2 = zeroRateImpl(t2);
162
0
            zeroRate = z1 + (z2-z1) * (dt/dp);
163
0
        } else {
164
0
            std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency());
165
0
            InflationTermStructure::checkRange(dd.first, extrapolate);
166
0
            Time t = timeFromReference(dd.first);
167
0
            zeroRate = zeroRateImpl(t);
168
0
        }
169
170
0
        if (hasSeasonality()) {
171
0
            zeroRate = seasonality()->correctZeroRate(d-useLag, zeroRate, *this);
172
0
        }
173
0
        return zeroRate;
174
0
    }
175
176
    Rate ZeroInflationTermStructure::zeroRate(Time t,
177
0
                                              bool extrapolate) const {
178
0
        checkRange(t, extrapolate);
179
0
        return zeroRateImpl(t);
180
0
    }
181
182
183
    YoYInflationTermStructure::YoYInflationTermStructure(
184
                                    Date baseDate,
185
                                    Rate baseYoYRate,
186
                                    Frequency frequency,
187
                                    const DayCounter& dayCounter,
188
                                    const ext::shared_ptr<Seasonality> &seasonality)
189
0
    : InflationTermStructure(baseDate, frequency, dayCounter, seasonality, baseYoYRate) {}
190
191
    YoYInflationTermStructure::YoYInflationTermStructure(
192
                                    const Date& referenceDate,
193
                                    Date baseDate,
194
                                    Rate baseYoYRate,
195
                                    Frequency frequency,
196
                                    const DayCounter& dayCounter,
197
                                    const ext::shared_ptr<Seasonality> &seasonality)
198
0
    : InflationTermStructure(referenceDate, baseDate, frequency, dayCounter, seasonality, baseYoYRate) {}
199
200
    YoYInflationTermStructure::YoYInflationTermStructure(
201
                                    Natural settlementDays,
202
                                    const Calendar& calendar,
203
                                    Date baseDate,
204
                                    Rate baseYoYRate,
205
                                    Frequency frequency,
206
                                    const DayCounter& dayCounter,
207
                                    const ext::shared_ptr<Seasonality> &seasonality)
208
0
    : InflationTermStructure(settlementDays, calendar, baseDate, frequency, dayCounter, seasonality, baseYoYRate) {}
209
210
0
    Rate YoYInflationTermStructure::yoyRate(const Date &d, bool extrapolate) const {
211
0
        QL_DEPRECATED_DISABLE_WARNING
212
0
        return yoyRate(d, Period(0, Days), false, extrapolate);
213
0
        QL_DEPRECATED_ENABLE_WARNING
214
0
    }
215
216
    Rate YoYInflationTermStructure::yoyRate(const Date &d, const Period& instObsLag,
217
                                            bool forceLinearInterpolation,
218
0
                                            bool extrapolate) const {
219
220
0
        Period useLag = instObsLag;
221
0
        if (instObsLag == Period(-1,Days)) {
222
0
            useLag = Period(0, Days);
223
0
        }
224
225
0
        Rate yoyRate;
226
0
        if (forceLinearInterpolation) {
227
0
            std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency());
228
0
            dd.second = dd.second + Period(1,Days);
229
0
            Real dp = dd.second - dd.first;
230
0
            Real dt = (d-useLag) - dd.first;
231
            // if we are interpolating we only check the exact point
232
            // this prevents falling off the end at curve maturity
233
0
            InflationTermStructure::checkRange(d, extrapolate);
234
0
            Time t1 = timeFromReference(dd.first);
235
0
            Time t2 = timeFromReference(dd.second);
236
0
            Rate y1 = yoyRateImpl(t1);
237
0
            Rate y2 = yoyRateImpl(t2);
238
0
            yoyRate = y1 + (y2-y1) * (dt/dp);
239
0
        } else {
240
0
            std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency());
241
0
            InflationTermStructure::checkRange(dd.first, extrapolate);
242
0
            Time t = timeFromReference(dd.first);
243
0
            yoyRate = yoyRateImpl(t);
244
0
        }
245
246
0
        if (hasSeasonality()) {
247
0
            yoyRate = seasonality()->correctYoYRate(d-useLag, yoyRate, *this);
248
0
        }
249
0
        return yoyRate;
250
0
    }
251
252
    Rate YoYInflationTermStructure::yoyRate(Time t,
253
0
                                            bool extrapolate) const {
254
0
        checkRange(t, extrapolate);
255
0
        return yoyRateImpl(t);
256
0
    }
257
258
259
260
261
    std::pair<Date,Date> inflationPeriod(const Date& d,
262
0
                                         Frequency frequency) {
263
0
        Month month = d.month();
264
0
        Year year = d.year();
265
266
0
        Month startMonth, endMonth;
267
0
        switch (frequency) {
268
0
          case Annual:
269
0
          case Semiannual:
270
0
          case EveryFourthMonth:
271
0
          case Quarterly:
272
0
          case Bimonthly: {
273
0
                int nMonths = 12 / frequency;
274
0
                startMonth = Month(month - (month - 1) % nMonths);
275
0
                endMonth = Month(startMonth + nMonths - 1);
276
0
            }
277
0
            break;
278
0
          case Monthly:
279
0
            startMonth = endMonth = month;
280
0
            break;
281
0
          default:
282
0
            QL_FAIL("Frequency not handled: " << frequency);
283
0
            break;
284
0
        };
285
286
0
        return {Date(1, startMonth, year), Date::endOfMonth(Date(1, endMonth, year))};
287
0
    }
288
289
290
    Time inflationYearFraction(Frequency f, bool indexIsInterpolated,
291
                               const DayCounter &dayCounter,
292
0
                               const Date &d1, const Date &d2) {
293
294
0
        Time t=0;
295
0
        if (indexIsInterpolated) {
296
            // N.B. we do not use linear interpolation between flat
297
            // fixing forecasts for forecasts.  This avoids awkwardnesses
298
            // when bootstrapping the inflation curve.
299
0
            t = dayCounter.yearFraction(d1, d2);
300
0
        } else {
301
            // I.e. fixing is constant for the whole inflation period.
302
            // Use the value for half way along the period.
303
            // But the inflation time is the time between period starts
304
0
            std::pair<Date,Date> limD1 = inflationPeriod(d1, f);
305
0
            std::pair<Date,Date> limD2 = inflationPeriod(d2, f);
306
0
            t = dayCounter.yearFraction(limD1.first, limD2.first);
307
0
        }
308
309
0
        return t;
310
0
    }
311
312
313
}