QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
seasonality.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2008 Piero Del Boca
5 Copyright (C) 2009 Chris Kenyon
6 Copyright (C) 2015 Bernd Lewerenz
7
8This file is part of QuantLib, a free-software/open-source library
9for financial quantitative analysts and developers - http://quantlib.org/
10
11QuantLib is free software: you can redistribute it and/or modify it
12under the terms of the QuantLib license. You should have received a
13copy of the license along with this program; if not, please email
14<quantlib-dev@lists.sf.net>. The license is also available online at
15<http://quantlib.org/license.shtml>.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the license for more details.
20*/
21
22
23#include <ql/termstructures/inflation/seasonality.hpp>
24#include <ql/termstructures/inflationtermstructure.hpp>
25#include <ql/errors.hpp>
26
27namespace QuantLib {
28
30 return true;
31 }
32
33
34 //Multiplicative Seasonality on price = on CPI/RPI/HICP/etc
35
37 {
38 // NOLINTBEGIN(clang-analyzer-optin.cplusplus.VirtualCall)
39 switch (this->frequency()) {
40 case Semiannual: //2
41 case EveryFourthMonth: //3
42 case Quarterly: //4
43 case Bimonthly: //6
44 case Monthly: //12
45 case Biweekly: // etc.
46 case Weekly:
47 case Daily:
48 QL_REQUIRE(!this->seasonalityFactors().empty(), "no seasonality factors given");
49 QL_REQUIRE( (this->seasonalityFactors().size() %
50 this->frequency()) == 0,
51 "For frequency " << this->frequency()
52 << " require multiple of " << ((int)this->frequency()) << " factors "
53 << this->seasonalityFactors().size() << " were given.");
54 break;
55 default:
56 QL_FAIL("bad frequency specified: " << this->frequency()
57 << ", only semi-annual through daily permitted.");
58 break;
59 }
60 // NOLINTEND(clang-analyzer-optin.cplusplus.VirtualCall)
61 }
62
63
65 {
66 // If multi-year is the specification consistent with the term structure start date?
67 // We do NOT test daily seasonality because this will, in general, never be consistent
68 // given weekends, holidays, leap years, etc.
69 if(this->frequency() == Daily) return true;
70 if(Size(this->frequency()) == seasonalityFactors().size()) return true;
71
72 // how many years do you need to test?
73 Size nTest = seasonalityFactors().size() / this->frequency();
74 // ... relative to the start of the inflation curve
75 std::pair<Date,Date> lim = inflationPeriod(iTS.baseDate(), iTS.frequency());
76 Date curveBaseDate = lim.second;
77 Real factorBase = this->seasonalityFactor(curveBaseDate);
78
79 Real eps = 0.00001;
80 for (Size i = 1; i < nTest; i++) {
81 Real factorAt = this->seasonalityFactor(curveBaseDate+Period(i,Years));
82 QL_REQUIRE(std::fabs(factorAt-factorBase)<eps,"seasonality is inconsistent with inflation term structure, factors "
83 << factorBase << " and later factor " << factorAt << ", " << i << " years later from inflation curve "
84 <<" with base date at " << curveBaseDate);
85 }
86
87 return true;
88 }
89
90
92 const std::vector<Rate>& seasonalityFactors)
93 {
95 }
96
97 void MultiplicativePriceSeasonality::set(const Date& seasonalityBaseDate, const Frequency frequency,
98 const std::vector<Rate>& seasonalityFactors)
99 {
101 seasonalityFactors_ = std::vector<Rate>(seasonalityFactors.size());
102 for(Size i=0; i<seasonalityFactors.size(); i++) {
104 }
106 // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
107 validate();
108 }
109
112 }
113
115 return frequency_;
116 }
117
119 return seasonalityFactors_;
120 }
121
122
124 const Rate r,
125 const InflationTermStructure& iTS) const {
126 // Mimic the logic in ZeroInflationIndex::forecastFixing for choosing the
127 // curveBaseDate and effective fixing date. This means that we should retrieve
128 // the input seasonality adjustments when we look at I_{SA}(t) / I_{NSA}(t).
129 Date curveBaseDate = iTS.baseDate();
130 Date effectiveFixingDate = inflationPeriod(d, iTS.frequency()).first;
131
132 return seasonalityCorrection(r, effectiveFixingDate, iTS.dayCounter(), curveBaseDate, true);
133 }
134
135
137 const Rate r,
138 const InflationTermStructure& iTS) const {
139 std::pair<Date,Date> lim = inflationPeriod(iTS.baseDate(), iTS.frequency());
140 Date curveBaseDate = lim.second;
141 return seasonalityCorrection(r, d, iTS.dayCounter(), curveBaseDate, false);
142 }
143
144
146
147 Date from = seasonalityBaseDate();
148 Frequency factorFrequency = frequency();
149 Size nFactors = seasonalityFactors().size();
150 Period factorPeriod(factorFrequency);
151 Size which = 0;
152 if (from==to) {
153 which = 0;
154 } else {
155 // days, weeks, months, years are the only time unit possibilities
156 Integer diffDays = std::abs(to - from); // in days
157 Integer dir = 1;
158 if(from > to)dir = -1;
159 Integer diff;
160 if (factorPeriod.units() == Days) {
161 diff = dir*diffDays;
162 } else if (factorPeriod.units() == Weeks) {
163 diff = dir * (diffDays / 7);
164 } else if (factorPeriod.units() == Months) {
165 std::pair<Date,Date> lim = inflationPeriod(to, factorFrequency);
166 diff = diffDays / (31*factorPeriod.length());
167 Date go = from + dir*diff*factorPeriod;
168 while ( !(lim.first <= go && go <= lim.second) ) {
169 go += dir*factorPeriod;
170 diff++;
171 }
172 diff=dir*diff;
173 } else if (factorPeriod.units() == Years) {
174 QL_FAIL("seasonality period time unit is not allowed to be : " << factorPeriod.units());
175 } else {
176 QL_FAIL("Unknown time unit: " << factorPeriod.units());
177 }
178 // now adjust to the available number of factors, direction dependent
179
180 if (dir==1) {
181 which = diff % nFactors;
182 } else {
183 which = (nFactors - (-diff % nFactors)) % nFactors;
184 }
185 }
186
187 return seasonalityFactors()[which];
188 }
189
190
192 const Date& atDate,
193 const DayCounter& dc,
194 const Date& curveBaseDate,
195 const bool isZeroRate) const {
196 // need _two_ corrections in order to get: seasonality = factor[atDate-seasonalityBase] / factor[reference-seasonalityBase]
197 // i.e. for ZERO inflation rates you have the true fixing at the curve base so this factor must be normalized to one
198 // for YoY inflation rates your reference point is the year before
199
200 Real factorAt = this->seasonalityFactor(atDate);
201
202 //Getting seasonality correction for either ZC or YoY
203 Rate f;
204 if (isZeroRate) {
205 Rate factorBase = this->seasonalityFactor(curveBaseDate);
206 Real seasonalityAt = factorAt / factorBase;
207 std::pair<Date,Date> p = inflationPeriod(atDate,frequency());
208 Time timeFromCurveBase = dc.yearFraction(curveBaseDate, p.first);
209 f = std::pow(seasonalityAt, 1/timeFromCurveBase);
210 }
211 else {
212 Rate factor1Ybefore = this->seasonalityFactor(atDate - Period(1,Years));
213 f = factorAt / factor1Ybefore;
214 }
215
216 return (rate + 1)*f - 1;
217 }
218
219
221
222 Integer dir = 1;
223 Date from = seasonalityBaseDate();
224 Size fromMonth = from.month();
225 Size toMonth = to.month();
226
227 Period factorPeriod(frequency());
228
229 if (toMonth < fromMonth)
230 {
231 Size dummy = fromMonth;
232 fromMonth = toMonth;
233 toMonth = dummy;
234 dir = 0; // We calculate invers Factor in loop
235 }
236
237 QL_REQUIRE(seasonalityFactors().size() == 12 &&
238 factorPeriod.units() == Months,
239 "12 monthly seasonal factors needed for Kerkhof Seasonality:"
240 << " got " << seasonalityFactors().size());
241
242 Real seasonalCorrection = 1.0;
243 for (Size i = fromMonth ; i<toMonth; i++)
244 {
245 seasonalCorrection *= seasonalityFactors()[i];
246
247 }
248
249 if (dir == 0) // invers Factor required
250 {
251 seasonalCorrection = 1/seasonalCorrection;
252 }
253
254 return seasonalCorrection;
255 }
256
258 const Date& atDate,
259 const DayCounter& dc,
260 const Date& curveBaseDate,
261 const bool isZeroRate) const {
262
263 Real indexFactor = this->seasonalityFactor(atDate);
264
265 // Getting seasonality correction
266 Rate f;
267 if (isZeroRate) {
268 std::pair<Date,Date> lim = inflationPeriod(curveBaseDate, Monthly);
269 Time timeFromCurveBase = dc.yearFraction(lim.first, atDate);
270 f = std::pow(indexFactor, 1/timeFromCurveBase);
271 }
272 else {
273 QL_FAIL("Seasonal Kerkhof model is not defined on YoY rates");
274 }
275
276 return (rate + 1)*f - 1;
277 }
278
279}
Concrete date class.
Definition: date.hpp:125
Month month() const
Definition: date.cpp:82
day counter class
Definition: daycounter.hpp:44
Time yearFraction(const Date &, const Date &, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date()) const
Returns the period between two dates as a fraction of year.
Definition: daycounter.hpp:128
Interface for inflation term structures.
virtual Date baseDate() const =0
minimum (base) date
Rate seasonalityCorrection(Rate rate, const Date &atDate, const DayCounter &dc, const Date &curveBaseDate, bool isZeroRate) const override
Real seasonalityFactor(const Date &to) const override
The factor returned is NOT normalized relative to ANYTHING.
virtual std::vector< Rate > seasonalityFactors() const
virtual Date seasonalityBaseDate() const
inspectors
Rate correctYoYRate(const Date &d, Rate r, const InflationTermStructure &iTS) const override
Rate correctZeroRate(const Date &d, Rate r, const InflationTermStructure &iTS) const override
virtual Rate seasonalityCorrection(Rate r, const Date &d, const DayCounter &dc, const Date &curveBaseDate, bool isZeroRate) const
virtual void set(const Date &seasonalityBaseDate, Frequency frequency, const std::vector< Rate > &seasonalityFactors)
Definition: seasonality.cpp:97
virtual Frequency frequency() const
virtual Rate seasonalityFactor(const Date &d) const
The factor returned is NOT normalized relative to ANYTHING.
bool isConsistent(const InflationTermStructure &iTS) const override
Definition: seasonality.cpp:64
TimeUnit units() const
Definition: period.hpp:51
Integer length() const
Definition: period.hpp:50
virtual bool isConsistent(const InflationTermStructure &iTS) const
Definition: seasonality.cpp:29
virtual DayCounter dayCounter() const
the day counter used for date/time conversion
Frequency
Frequency of events.
Definition: frequency.hpp:37
@ Monthly
once a month
Definition: frequency.hpp:44
@ Biweekly
every second week
Definition: frequency.hpp:46
@ Weekly
once a week
Definition: frequency.hpp:47
@ Daily
once a day
Definition: frequency.hpp:48
@ Bimonthly
every second month
Definition: frequency.hpp:43
@ Quarterly
every third month
Definition: frequency.hpp:42
@ EveryFourthMonth
every fourth month
Definition: frequency.hpp:41
@ Semiannual
twice a year
Definition: frequency.hpp:40
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
std::pair< Date, Date > inflationPeriod(const Date &d, Frequency frequency)
utility function giving the inflation period for a given date