QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
inflationindex.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2007 Chris Kenyon
5 Copyright (C) 2021 Ralf Konrad Eckel
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#include <ql/indexes/inflationindex.hpp>
22#include <ql/termstructures/inflationtermstructure.hpp>
23#include <ql/time/calendars/nullcalendar.hpp>
24#include <utility>
25
26namespace QuantLib {
27
28 Real CPI::laggedFixing(const ext::shared_ptr<ZeroInflationIndex>& index,
29 const Date& date,
30 const Period& observationLag,
31 CPI::InterpolationType interpolationType) {
32
33 switch (interpolationType) {
34 case AsIndex: {
35 return index->fixing(date - observationLag);
36 }
37 case Flat: {
38 auto fixingPeriod = inflationPeriod(date - observationLag, index->frequency());
39 return index->fixing(fixingPeriod.first);
40 }
41 case Linear: {
42 auto fixingPeriod = inflationPeriod(date - observationLag, index->frequency());
43 auto interpolationPeriod = inflationPeriod(date, index->frequency());
44
45 if (date == interpolationPeriod.first) {
46 // special case; no interpolation. This avoids asking for
47 // the fixing at the end of the period, which might need a
48 // forecast curve to be set.
49 return index->fixing(fixingPeriod.first);
50 }
51
52 static const auto oneDay = Period(1, Days);
53
54 auto I0 = index->fixing(fixingPeriod.first);
55 auto I1 = index->fixing(fixingPeriod.second + oneDay);
56
57 return I0 + (I1 - I0) * (date - interpolationPeriod.first) /
58 (Real)((interpolationPeriod.second + oneDay) - interpolationPeriod.first);
59 }
60 default:
61 QL_FAIL("unknown CPI interpolation type: " << int(interpolationType));
62 }
63 }
64
65
66 InflationIndex::InflationIndex(std::string familyName,
67 Region region,
68 bool revised,
69 bool interpolated,
70 Frequency frequency,
71 const Period& availabilityLag,
72 Currency currency)
73 : InflationIndex(std::move(familyName),
74 std::move(region),
75 revised,
76 frequency,
77 availabilityLag,
78 std::move(currency)) {
79 QL_DEPRECATED_DISABLE_WARNING
81 QL_DEPRECATED_ENABLE_WARNING
82 }
83
84 /* gcc complains in the constructor about the deprecated call of initializing
85 * `bool InflationIndex::interpolated_ = false;` that's why we need to disable the warning here.
86 */
87 QL_DEPRECATED_DISABLE_WARNING
88 InflationIndex::InflationIndex(std::string familyName,
89 Region region,
90 bool revised,
91 Frequency frequency,
92 const Period& availabilityLag,
93 Currency currency)
94 : familyName_(std::move(familyName)), region_(std::move(region)), revised_(revised),
95 frequency_(frequency), availabilityLag_(availabilityLag), currency_(std::move(currency)) {
96 name_ = region_.name() + " " + familyName_;
97 registerWith(Settings::instance().evaluationDate());
99 }
100 QL_DEPRECATED_ENABLE_WARNING
101
103 QL_DEPRECATED_DISABLE_WARNING
104 return interpolated_;
105 QL_DEPRECATED_ENABLE_WARNING
106 }
107
109 static NullCalendar c;
110 return c;
111 }
112
113 void InflationIndex::addFixing(const Date& fixingDate,
114 Real fixing,
115 bool forceOverwrite) {
116
117 std::pair<Date,Date> lim = inflationPeriod(fixingDate, frequency_);
118 Size n = static_cast<QuantLib::Size>(lim.second - lim.first) + 1;
119 std::vector<Date> dates(n);
120 std::vector<Rate> rates(n);
121 for (Size i=0; i<n; ++i) {
122 dates[i] = lim.first + i;
123 rates[i] = fixing;
124 }
125
126 Index::addFixings(dates.begin(), dates.end(),
127 rates.begin(), forceOverwrite);
128 }
129
130 ZeroInflationIndex::ZeroInflationIndex(const std::string& familyName,
131 const Region& region,
132 bool revised,
133 bool interpolated,
134 Frequency frequency,
135 const Period& availabilityLag,
136 const Currency& currency,
139 familyName, region, revised, frequency, availabilityLag, currency, std::move(zeroInflation)) {
140 QL_DEPRECATED_DISABLE_WARNING
142 QL_DEPRECATED_ENABLE_WARNING
143 }
144
145 ZeroInflationIndex::ZeroInflationIndex(const std::string& familyName,
146 const Region& region,
147 bool revised,
148 Frequency frequency,
149 const Period& availabilityLag,
150 const Currency& currency,
152 : InflationIndex(familyName, region, revised, frequency, availabilityLag, currency),
153 zeroInflation_(std::move(zeroInflation)) {
155 }
156
158 bool /*forecastTodaysFixing*/) const {
159 if (!needsForecast(fixingDate)) {
160 std::pair<Date,Date> p = inflationPeriod(fixingDate, frequency_);
161 const TimeSeries<Real>& ts = timeSeries();
162
163 Real I1 = ts[p.first];
164 QL_REQUIRE(I1 != Null<Real>(),
165 "Missing " << name() << " fixing for " << p.first);
166
167 QL_DEPRECATED_DISABLE_WARNING
168 if (interpolated_ && fixingDate > p.first) {
169 QL_DEPRECATED_ENABLE_WARNING
170
171 Real I2 = ts[p.second+1];
172 QL_REQUIRE(I2 != Null<Real>(),
173 "Missing " << name() << " fixing for " << p.second+1);
174
175 // Use non-lagged period for interpolation
176 Date observationDate = fixingDate + zeroInflation_->observationLag();
177 std::pair<Date, Date> p2 = inflationPeriod(observationDate, frequency_);
178 Real daysInPeriod = (p2.second + 1) - p2.first;
179 Real interpolationCoefficient = (observationDate - p2.first) / daysInPeriod;
180
181 return I1 + (I2 - I1) * interpolationCoefficient;
182 } else {
183 // we don't need the next fixing
184 return I1;
185 }
186 } else {
187 return forecastFixing(fixingDate);
188 }
189 }
190
191
192 bool ZeroInflationIndex::needsForecast(const Date& fixingDate) const {
193
194 // Stored fixings are always non-interpolated.
195 // If an interpolated fixing is required then
196 // the availability lag + one inflation period
197 // must have passed to use historical fixings
198 // (because you need the next one to interpolate).
199 // The interpolation is calculated (linearly) on demand.
200
202 Date todayMinusLag = today - availabilityLag_;
203
204 Date historicalFixingKnown =
205 inflationPeriod(todayMinusLag, frequency_).first-1;
206 Date latestNeededDate = fixingDate;
207
208 QL_DEPRECATED_DISABLE_WARNING
209 if (interpolated_) { // might need the next one too
210 std::pair<Date,Date> p = inflationPeriod(fixingDate, frequency_);
211 if (fixingDate > p.first)
212 latestNeededDate += Period(frequency_);
213 }
214 QL_DEPRECATED_ENABLE_WARNING
215
216 if (latestNeededDate <= historicalFixingKnown) {
217 // the fixing date is well before the availability lag, so
218 // we know that fixings were provided.
219 return false;
220 } else if (latestNeededDate > today) {
221 // the fixing can't be available, no matter what's in the
222 // time series
223 return true;
224 } else {
225 // we're not sure, but the fixing might be there so we
226 // check. Todo: check which fixings are not possible, to
227 // avoid using fixings in the future
228 Date first = Date(1, latestNeededDate.month(), latestNeededDate.year());
229 Real f = timeSeries()[first];
230 return (f == Null<Real>());
231 }
232 }
233
234
236 // the term structure is relative to the fixing value at the base date.
237 Date baseDate = zeroInflation_->baseDate();
238 QL_REQUIRE(!needsForecast(baseDate),
239 name() << " index fixing at base date " << baseDate << " is not available");
240 Real baseFixing = fixing(baseDate);
241
242 std::pair<Date, Date> p = inflationPeriod(fixingDate, frequency_);
243
244 QL_DEPRECATED_DISABLE_WARNING
245
246 Date firstDateInPeriod = p.first;
247 Rate Z1 = zeroInflation_->zeroRate(firstDateInPeriod, Period(0,Days), false);
249 baseDate, firstDateInPeriod);
250 Real I1 = baseFixing * std::pow(1.0 + Z1, t1);
251
252 if (interpolated_ && fixingDate > firstDateInPeriod) {
253 Date firstDateInNextPeriod = p.second + 1;
254 Rate Z2 = zeroInflation_->zeroRate(firstDateInNextPeriod, Period(0,Days), false);
256 baseDate, firstDateInNextPeriod);
257 Real I2 = baseFixing * std::pow(1.0 + Z2, t2);
258
259 // // Use non-lagged period for interpolation
260 Date observationDate = fixingDate + zeroInflation_->observationLag();
261 std::pair<Date, Date> p2 = inflationPeriod(observationDate, frequency_);
262 Real daysInPeriod = (p2.second + 1) - p2.first;
263 Real interpolationCoefficient = (observationDate - p2.first) / daysInPeriod;
264
265 return I1 + (I2 - I1) * interpolationCoefficient;
266 } else {
267 return I1;
268 }
269
270 QL_DEPRECATED_ENABLE_WARNING
271 }
272
273
274 ext::shared_ptr<ZeroInflationIndex> ZeroInflationIndex::clone(
275 const Handle<ZeroInflationTermStructure>& h) const {
276 /* using the new constructor and set interpolated to avoid the deprecated warning and
277 * error... */
278 auto clonedIndex = ext::make_shared<ZeroInflationIndex>(
280 QL_DEPRECATED_DISABLE_WARNING
281 clonedIndex->interpolated_ = interpolated_;
282 QL_DEPRECATED_ENABLE_WARNING
283 return clonedIndex;
284 }
285
286
287 YoYInflationIndex::YoYInflationIndex(const ext::shared_ptr<ZeroInflationIndex>& underlyingIndex,
288 bool interpolated,
290 : InflationIndex("YYR_" + underlyingIndex->familyName(), underlyingIndex->region(),
291 underlyingIndex->revised(), underlyingIndex->frequency(),
292 underlyingIndex->availabilityLag(), underlyingIndex->currency()),
293 interpolated_(interpolated), ratio_(true), underlyingIndex_(underlyingIndex),
294 yoyInflation_(std::move(yoyInflation)) {
297 }
298
299 QL_DEPRECATED_DISABLE_WARNING
300
301 YoYInflationIndex::YoYInflationIndex(const std::string& familyName,
302 const Region& region,
303 bool revised,
304 bool interpolated,
305 Frequency frequency,
306 const Period& availabilityLag,
307 const Currency& currency,
309 : YoYInflationIndex(familyName, region, revised, interpolated, false,
310 frequency, availabilityLag, currency, std::move(yoyInflation)) {}
311
312 QL_DEPRECATED_ENABLE_WARNING
313
314 YoYInflationIndex::YoYInflationIndex(const std::string& familyName,
315 const Region& region,
316 bool revised,
317 bool interpolated,
318 bool ratio,
319 Frequency frequency,
320 const Period& availabilityLag,
321 const Currency& currency,
323 : InflationIndex(familyName, region, revised, frequency, availabilityLag, currency),
324 interpolated_(interpolated), ratio_(ratio), yoyInflation_(std::move(yoyInflation)) {
325 if (ratio)
326 underlyingIndex_ = ext::make_shared<ZeroInflationIndex>(familyName, region, revised,
329 }
330
331
333 bool /*forecastTodaysFixing*/) const {
334
336 Date todayMinusLag = today - availabilityLag_;
337 std::pair<Date,Date> lim = inflationPeriod(todayMinusLag, frequency_);
338 Date lastFix = lim.first-1;
339
340 Date flatMustForecastOn = lastFix+1;
341 Date interpMustForecastOn = lastFix+1 - Period(frequency_);
342
343 if (interpolated() && fixingDate >= interpMustForecastOn) {
344 return forecastFixing(fixingDate);
345 }
346
347 if (!interpolated() && fixingDate >= flatMustForecastOn) {
348 return forecastFixing(fixingDate);
349 }
350
351 const TimeSeries<Real>& ts = timeSeries();
352 if (ratio()) {
353
354 auto interpolationType = interpolated() ? CPI::Linear : CPI::Flat;
355
356 Rate pastFixing = CPI::laggedFixing(underlyingIndex_, fixingDate, Period(0, Months), interpolationType);
357 Rate previousFixing = CPI::laggedFixing(underlyingIndex_, fixingDate - 1*Years, Period(0, Months), interpolationType);
358
359 return pastFixing/previousFixing - 1.0;
360
361 } else { // NOT ratio
362
363 if (interpolated()) { // NOT ratio, IS interpolated
364
365 std::pair<Date,Date> lim = inflationPeriod(fixingDate, frequency_);
366 Real dp = lim.second + 1 - lim.first;
367 Real dl = fixingDate - lim.first;
368 Rate limFirstFix = ts[lim.first];
369 QL_REQUIRE(limFirstFix != Null<Rate>(),
370 "Missing " << name() << " fixing for "
371 << lim.first );
372 Rate limSecondFix = ts[lim.second+1];
373 QL_REQUIRE(limSecondFix != Null<Rate>(),
374 "Missing " << name() << " fixing for "
375 << lim.second+1 );
376 Real linearNow = limFirstFix + (limSecondFix-limFirstFix)*dl/dp;
377
378 return linearNow;
379
380 } else { // NOT ratio, NOT interpolated
381 // so just flat
382
383 std::pair<Date,Date> lim = inflationPeriod(fixingDate, frequency_);
384 Rate pastFixing = ts[lim.first];
385 QL_REQUIRE(pastFixing != Null<Rate>(),
386 "Missing " << name() << " fixing for " << lim.first);
387 return pastFixing;
388
389 }
390 }
391 }
392
393
394 Real YoYInflationIndex::forecastFixing(const Date& fixingDate) const {
395
396 Date d;
397 if (interpolated()) {
398 d = fixingDate;
399 } else {
400 // if the value is not interpolated use the starting value
401 // by internal convention this will be consistent
402 std::pair<Date,Date> lim = inflationPeriod(fixingDate, frequency_);
403 d = lim.first;
404 }
405 return yoyInflation_->yoyRate(d,0*Days);
406 }
407
408 ext::shared_ptr<YoYInflationIndex> YoYInflationIndex::clone(
409 const Handle<YoYInflationTermStructure>& h) const {
410 if (ratio_) {
411 return ext::make_shared<YoYInflationIndex>(underlyingIndex_, interpolated_, h);
412 } else {
413 return ext::make_shared<YoYInflationIndex>(familyName_, region_, revised_,
416 }
417 }
418
419
421 detail::CPI::effectiveInterpolationType(const ext::shared_ptr<ZeroInflationIndex>& index,
423 if (type == QuantLib::CPI::AsIndex) {
424 QL_DEPRECATED_DISABLE_WARNING
425 return index->interpolated() ? QuantLib::CPI::Linear : QuantLib::CPI::Flat;
426 QL_DEPRECATED_ENABLE_WARNING
427 } else {
428 return type;
429 }
430 }
431
432}
calendar class
Definition: calendar.hpp:61
Currency specification
Definition: currency.hpp:36
Concrete date class.
Definition: date.hpp:125
Month month() const
Definition: date.cpp:82
Year year() const
Definition: date.cpp:93
Shared handle to an observable.
Definition: handle.hpp:41
const TimeSeries< Real > & timeSeries() const
returns the fixing TimeSeries
Definition: index.hpp:65
void addFixings(const TimeSeries< Real > &t, bool forceOverwrite=false)
stores historical fixings from a TimeSeries
Definition: index.cpp:33
Base class for inflation-rate indexes,.
Calendar fixingCalendar() const override
QL_DEPRECATED bool interpolated() const
std::string name() const override
Returns the name of the index.
InflationIndex(std::string familyName, Region region, bool revised, Frequency frequency, const Period &availabilitiyLag, Currency currency)
void addFixing(const Date &fixingDate, Rate fixing, bool forceOverwrite=false) override
Frequency frequency() const
QL_DEPRECATED bool interpolated_
Period availabilityLag() const
std::string familyName() const
Real fixing(const Date &fixingDate, bool forecastTodaysFixing=false) const override=0
Calendar for reproducing theoretical calculations.
template class providing a null value for a given type.
Definition: null.hpp:76
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
Frequency frequency() const
Definition: period.cpp:69
Region class, used for inflation applicability.
Definition: region.hpp:36
const std::string & name() const
Definition: region.hpp:113
DateProxy & evaluationDate()
the date at which pricing is to be performed.
Definition: settings.hpp:147
static Settings & instance()
access to the unique instance
Definition: singleton.hpp:104
Container for historical data.
Definition: timeseries.hpp:51
Base class for year-on-year inflation indices.
Handle< YoYInflationTermStructure > yoyInflation_
ext::shared_ptr< YoYInflationIndex > clone(const Handle< YoYInflationTermStructure > &h) const
Rate forecastFixing(const Date &fixingDate) const
YoYInflationIndex(const ext::shared_ptr< ZeroInflationIndex > &underlyingIndex, bool interpolated, Handle< YoYInflationTermStructure > ts={})
Constructor for year-on-year indices defined as a ratio.
Rate fixing(const Date &fixingDate, bool forecastTodaysFixing=false) const override
ext::shared_ptr< ZeroInflationIndex > underlyingIndex_
Base class for zero inflation indices.
ext::shared_ptr< ZeroInflationIndex > clone(const Handle< ZeroInflationTermStructure > &h) const
Handle< ZeroInflationTermStructure > zeroInflation_
ZeroInflationIndex(const std::string &familyName, const Region &region, bool revised, Frequency frequency, const Period &availabilityLag, const Currency &currency, Handle< ZeroInflationTermStructure > ts={})
Real forecastFixing(const Date &fixingDate) const
bool needsForecast(const Date &fixingDate) const
Real fixing(const Date &fixingDate, bool forecastTodaysFixing=false) const override
Frequency
Frequency of events.
Definition: frequency.hpp:37
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
QuantLib::CPI::InterpolationType effectiveInterpolationType(const ext::shared_ptr< ZeroInflationIndex > &index, const QuantLib::CPI::InterpolationType &type=QuantLib::CPI::AsIndex)
Definition: any.hpp:35
std::pair< Date, Date > inflationPeriod(const Date &d, Frequency frequency)
utility function giving the inflation period for a given date
Time inflationYearFraction(Frequency f, bool indexIsInterpolated, const DayCounter &dayCounter, const Date &d1, const Date &d2)
STL namespace.
static Real laggedFixing(const ext::shared_ptr< ZeroInflationIndex > &index, const Date &date, const Period &observationLag, InterpolationType interpolationType)
interpolated inflation fixing
InterpolationType
when you observe an index, how do you interpolate between fixings?
@ AsIndex
same interpolation as index
@ Linear
linearly between bracketing fixings
@ Flat
flat from previous fixing