QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
calendar.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
5 Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl
6 Copyright (C) 2004 Jeff Yu
7 Copyright (C) 2014 Paolo Mazzocchi
8 Copyright (C) 2020 Leonardo Arcari
9 Copyright (C) 2020 Kline s.r.l.
10
11 This file is part of QuantLib, a free-software/open-source library
12 for financial quantitative analysts and developers - http://quantlib.org/
13
14 QuantLib is free software: you can redistribute it and/or modify it
15 under the terms of the QuantLib license. You should have received a
16 copy of the license along with this program; if not, please email
17 <quantlib-dev@lists.sf.net>. The license is also available online at
18 <http://quantlib.org/license.shtml>.
19
20 This program is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. See the license for more details.
23*/
24
25#include <ql/time/calendar.hpp>
26#include <ql/errors.hpp>
27
28namespace QuantLib {
29
30 namespace {
31
32 // Requires: from < to.
33 Date::serial_type daysBetweenImpl(const Calendar& cal,
34 const Date& from, const Date& to,
35 bool includeFirst, bool includeLast) {
36 auto res = static_cast<Date::serial_type>(includeLast && cal.isBusinessDay(to));
37 for (Date d = includeFirst ? from : from + 1; d < to; ++d) {
38 res += static_cast<Date::serial_type>(cal.isBusinessDay(d));
39 }
40 return res;
41 }
42
43 }
44
45 void Calendar::addHoliday(const Date& d) {
46 QL_REQUIRE(impl_, "no calendar implementation provided");
47
48#ifdef QL_HIGH_RESOLUTION_DATE
49 const Date _d(d.dayOfMonth(), d.month(), d.year());
50#else
51 const Date& _d = d;
52#endif
53
54 // if d was a genuine holiday previously removed, revert the change
55 impl_->removedHolidays.erase(_d);
56 // if it's already a holiday, leave the calendar alone.
57 // Otherwise, add it.
58 if (impl_->isBusinessDay(_d))
59 impl_->addedHolidays.insert(_d);
60 }
61
63 QL_REQUIRE(impl_, "no calendar implementation provided");
64
65#ifdef QL_HIGH_RESOLUTION_DATE
66 const Date _d(d.dayOfMonth(), d.month(), d.year());
67#else
68 const Date& _d = d;
69#endif
70
71 // if d was an artificially-added holiday, revert the change
72 impl_->addedHolidays.erase(_d);
73 // if it's already a business day, leave the calendar alone.
74 // Otherwise, add it.
75 if (!impl_->isBusinessDay(_d))
76 impl_->removedHolidays.insert(_d);
77 }
78
80 impl_->addedHolidays.clear();
81 impl_->removedHolidays.clear();
82 }
83
85 BusinessDayConvention c) const {
86 QL_REQUIRE(d != Date(), "null date");
87
88 if (c == Unadjusted)
89 return d;
90
91 Date d1 = d;
92 if (c == Following || c == ModifiedFollowing
94 while (isHoliday(d1))
95 ++d1;
96 if (c == ModifiedFollowing
98 if (d1.month() != d.month()) {
99 return adjust(d, Preceding);
100 }
102 if (d.dayOfMonth() <= 15 && d1.dayOfMonth() > 15) {
103 return adjust(d, Preceding);
104 }
105 }
106 }
107 } else if (c == Preceding || c == ModifiedPreceding) {
108 while (isHoliday(d1))
109 --d1;
110 if (c == ModifiedPreceding && d1.month() != d.month()) {
111 return adjust(d,Following);
112 }
113 } else if (c == Nearest) {
114 Date d2 = d;
115 while (isHoliday(d1) && isHoliday(d2))
116 {
117 ++d1;
118 --d2;
119 }
120 if (isHoliday(d1))
121 return d2;
122 else
123 return d1;
124 } else {
125 QL_FAIL("unknown business-day convention");
126 }
127 return d1;
128 }
129
131 Integer n, TimeUnit unit,
133 bool endOfMonth) const {
134 QL_REQUIRE(d!=Date(), "null date");
135 if (n == 0) {
136 return adjust(d,c);
137 } else if (unit == Days) {
138 Date d1 = d;
139 if (n > 0) {
140 while (n > 0) {
141 ++d1;
142 while (isHoliday(d1))
143 ++d1;
144 --n;
145 }
146 } else {
147 while (n < 0) {
148 --d1;
149 while(isHoliday(d1))
150 --d1;
151 ++n;
152 }
153 }
154 return d1;
155 } else if (unit == Weeks) {
156 Date d1 = d + n*unit;
157 return adjust(d1,c);
158 } else {
159 Date d1 = d + n*unit;
160
161 // we are sure the unit is Months or Years
162 if (endOfMonth && isEndOfMonth(d))
163 return Calendar::endOfMonth(d1);
164
165 return adjust(d1, c);
166 }
167 }
168
170 const Period & p,
172 bool endOfMonth) const {
173 return advance(d, p.length(), p.units(), c, endOfMonth);
174 }
175
177 const Date& to,
178 bool includeFirst,
179 bool includeLast) const {
180 return (from < to) ? daysBetweenImpl(*this, from, to, includeFirst, includeLast) :
181 (from > to) ? -daysBetweenImpl(*this, to, from, includeLast, includeFirst) :
182 Date::serial_type(includeFirst && includeLast && isBusinessDay(from));
183 }
184
185
186
187 // Western calendars
188
190 return w == Saturday || w == Sunday;
191 }
192
194 static const Day EasterMonday[] = {
195 98, 90, 103, 95, 114, 106, 91, 111, 102, // 1901-1909
196 87, 107, 99, 83, 103, 95, 115, 99, 91, 111, // 1910-1919
197 96, 87, 107, 92, 112, 103, 95, 108, 100, 91, // 1920-1929
198 111, 96, 88, 107, 92, 112, 104, 88, 108, 100, // 1930-1939
199 85, 104, 96, 116, 101, 92, 112, 97, 89, 108, // 1940-1949
200 100, 85, 105, 96, 109, 101, 93, 112, 97, 89, // 1950-1959
201 109, 93, 113, 105, 90, 109, 101, 86, 106, 97, // 1960-1969
202 89, 102, 94, 113, 105, 90, 110, 101, 86, 106, // 1970-1979
203 98, 110, 102, 94, 114, 98, 90, 110, 95, 86, // 1980-1989
204 106, 91, 111, 102, 94, 107, 99, 90, 103, 95, // 1990-1999
205 115, 106, 91, 111, 103, 87, 107, 99, 84, 103, // 2000-2009
206 95, 115, 100, 91, 111, 96, 88, 107, 92, 112, // 2010-2019
207 104, 95, 108, 100, 92, 111, 96, 88, 108, 92, // 2020-2029
208 112, 104, 89, 108, 100, 85, 105, 96, 116, 101, // 2030-2039
209 93, 112, 97, 89, 109, 100, 85, 105, 97, 109, // 2040-2049
210 101, 93, 113, 97, 89, 109, 94, 113, 105, 90, // 2050-2059
211 110, 101, 86, 106, 98, 89, 102, 94, 114, 105, // 2060-2069
212 90, 110, 102, 86, 106, 98, 111, 102, 94, 114, // 2070-2079
213 99, 90, 110, 95, 87, 106, 91, 111, 103, 94, // 2080-2089
214 107, 99, 91, 103, 95, 115, 107, 91, 111, 103, // 2090-2099
215 88, 108, 100, 85, 105, 96, 109, 101, 93, 112, // 2100-2109
216 97, 89, 109, 93, 113, 105, 90, 109, 101, 86, // 2110-2119
217 106, 97, 89, 102, 94, 113, 105, 90, 110, 101, // 2120-2129
218 86, 106, 98, 110, 102, 94, 114, 98, 90, 110, // 2130-2139
219 95, 86, 106, 91, 111, 102, 94, 107, 99, 90, // 2140-2149
220 103, 95, 115, 106, 91, 111, 103, 87, 107, 99, // 2150-2159
221 84, 103, 95, 115, 100, 91, 111, 96, 88, 107, // 2160-2169
222 92, 112, 104, 95, 108, 100, 92, 111, 96, 88, // 2170-2179
223 108, 92, 112, 104, 89, 108, 100, 85, 105, 96, // 2180-2189
224 116, 101, 93, 112, 97, 89, 109, 100, 85, 105 // 2190-2199
225 };
226 return EasterMonday[y-1901];
227 }
228
229 // Orthodox calendars
230
232 return w == Saturday || w == Sunday;
233 }
234
236 static const Day EasterMonday[] = {
237 105, 118, 110, 102, 121, 106, 126, 118, 102, // 1901-1909
238 122, 114, 99, 118, 110, 95, 115, 106, 126, 111, // 1910-1919
239 103, 122, 107, 99, 119, 110, 123, 115, 107, 126, // 1920-1929
240 111, 103, 123, 107, 99, 119, 104, 123, 115, 100, // 1930-1939
241 120, 111, 96, 116, 108, 127, 112, 104, 124, 115, // 1940-1949
242 100, 120, 112, 96, 116, 108, 128, 112, 104, 124, // 1950-1959
243 109, 100, 120, 105, 125, 116, 101, 121, 113, 104, // 1960-1969
244 117, 109, 101, 120, 105, 125, 117, 101, 121, 113, // 1970-1979
245 98, 117, 109, 129, 114, 105, 125, 110, 102, 121, // 1980-1989
246 106, 98, 118, 109, 122, 114, 106, 118, 110, 102, // 1990-1999
247 122, 106, 126, 118, 103, 122, 114, 99, 119, 110, // 2000-2009
248 95, 115, 107, 126, 111, 103, 123, 107, 99, 119, // 2010-2019
249 111, 123, 115, 107, 127, 111, 103, 123, 108, 99, // 2020-2029
250 119, 104, 124, 115, 100, 120, 112, 96, 116, 108, // 2030-2039
251 128, 112, 104, 124, 116, 100, 120, 112, 97, 116, // 2040-2049
252 108, 128, 113, 104, 124, 109, 101, 120, 105, 125, // 2050-2059
253 117, 101, 121, 113, 105, 117, 109, 101, 121, 105, // 2060-2069
254 125, 110, 102, 121, 113, 98, 118, 109, 129, 114, // 2070-2079
255 106, 125, 110, 102, 122, 106, 98, 118, 110, 122, // 2080-2089
256 114, 99, 119, 110, 102, 115, 107, 126, 118, 103, // 2090-2099
257 123, 115, 100, 120, 112, 96, 116, 108, 128, 112, // 2100-2109
258 104, 124, 109, 100, 120, 105, 125, 116, 108, 121, // 2110-2119
259 113, 104, 124, 109, 101, 120, 105, 125, 117, 101, // 2120-2129
260 121, 113, 98, 117, 109, 129, 114, 105, 125, 110, // 2130-2139
261 102, 121, 113, 98, 118, 109, 129, 114, 106, 125, // 2140-2149
262 110, 102, 122, 106, 126, 118, 103, 122, 114, 99, // 2150-2159
263 119, 110, 102, 115, 107, 126, 111, 103, 123, 114, // 2160-2169
264 99, 119, 111, 130, 115, 107, 127, 111, 103, 123, // 2170-2179
265 108, 99, 119, 104, 124, 115, 100, 120, 112, 103, // 2180-2189
266 116, 108, 128, 119, 104, 124, 116, 100, 120, 112 // 2190-2199
267 };
268 return EasterMonday[y-1901];
269 }
270
271 std::vector<Date> Calendar::holidayList(
272 const Date& from, const Date& to, bool includeWeekEnds) const {
273
274 QL_REQUIRE(to>=from, "'from' date ("
275 << from << ") must be equal to or earlier than 'to' date ("
276 << to << ")");
277 std::vector<Date> result;
278 for (Date d = from; d <= to; ++d) {
279 if (isHoliday(d) && (includeWeekEnds || !isWeekend(d.weekday())))
280 result.push_back(d);
281 }
282 return result;
283 }
284
285 std::vector<Date> Calendar::businessDayList(
286 const Date& from, const Date& to) const {
287
288 QL_REQUIRE(to>=from, "'from' date ("
289 << from << ") must be equal to or earlier than 'to' date ("
290 << to << ")");
291 std::vector<Date> result;
292 for (Date d = from; d <= to; ++d) {
293 if (isBusinessDay(d))
294 result.push_back(d);
295 }
296 return result;
297 }
298}
static Day easterMonday(Year)
expressed relative to first day of year
Definition: calendar.cpp:235
bool isWeekend(Weekday) const override
Definition: calendar.cpp:231
static Day easterMonday(Year)
expressed relative to first day of year
Definition: calendar.cpp:193
bool isWeekend(Weekday) const override
Definition: calendar.cpp:189
bool isWeekend(Weekday w) const
Definition: calendar.hpp:255
Date::serial_type businessDaysBetween(const Date &from, const Date &to, bool includeFirst=true, bool includeLast=false) const
Definition: calendar.cpp:176
void removeHoliday(const Date &)
Definition: calendar.cpp:62
bool isEndOfMonth(const Date &d) const
Definition: calendar.hpp:243
bool isBusinessDay(const Date &d) const
Definition: calendar.hpp:223
void addHoliday(const Date &)
Definition: calendar.cpp:45
Date adjust(const Date &, BusinessDayConvention convention=Following) const
Definition: calendar.cpp:84
std::vector< Date > holidayList(const Date &from, const Date &to, bool includeWeekEnds=false) const
Definition: calendar.cpp:271
bool isHoliday(const Date &d) const
Definition: calendar.hpp:251
Date advance(const Date &, Integer n, TimeUnit unit, BusinessDayConvention convention=Following, bool endOfMonth=false) const
Definition: calendar.cpp:130
ext::shared_ptr< Impl > impl_
Definition: calendar.hpp:72
void resetAddedAndRemovedHolidays()
Definition: calendar.cpp:79
std::vector< Date > businessDayList(const Date &from, const Date &to) const
Definition: calendar.cpp:285
Date endOfMonth(const Date &d) const
last business day of the month to which the given date belongs
Definition: calendar.hpp:247
Concrete date class.
Definition: date.hpp:125
Month month() const
Definition: date.cpp:82
Day dayOfMonth() const
Definition: date.hpp:400
std::int_fast32_t serial_type
serial number type
Definition: date.hpp:128
TimeUnit units() const
Definition: period.hpp:51
Integer length() const
Definition: period.hpp:50
Integer Year
Year number.
Definition: date.hpp:87
Integer Day
Day number.
Definition: date.hpp:53
TimeUnit
Units used to describe time periods.
Definition: timeunit.hpp:37
BusinessDayConvention
Business Day conventions.
@ Sunday
Definition: weekday.hpp:41
@ Saturday
Definition: weekday.hpp:47
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Definition: any.hpp:35