/src/quantlib/ql/time/calendar.hpp
Line | Count | Source (jump to first uncovered line) |
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) 2006 Piter Dias |
7 | | Copyright (C) 2020 Leonardo Arcari |
8 | | Copyright (C) 2020 Kline s.r.l. |
9 | | |
10 | | This file is part of QuantLib, a free-software/open-source library |
11 | | for financial quantitative analysts and developers - http://quantlib.org/ |
12 | | |
13 | | QuantLib is free software: you can redistribute it and/or modify it |
14 | | under the terms of the QuantLib license. You should have received a |
15 | | copy of the license along with this program; if not, please email |
16 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
17 | | <http://quantlib.org/license.shtml>. |
18 | | |
19 | | This program is distributed in the hope that it will be useful, but WITHOUT |
20 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
21 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
22 | | */ |
23 | | |
24 | | /*! \file calendar.hpp |
25 | | \brief %calendar class |
26 | | */ |
27 | | |
28 | | #ifndef quantlib_calendar_hpp |
29 | | #define quantlib_calendar_hpp |
30 | | |
31 | | #include <ql/errors.hpp> |
32 | | #include <ql/time/date.hpp> |
33 | | #include <ql/time/businessdayconvention.hpp> |
34 | | #include <ql/shared_ptr.hpp> |
35 | | #include <set> |
36 | | #include <vector> |
37 | | #include <string> |
38 | | |
39 | | namespace QuantLib { |
40 | | |
41 | | class Period; |
42 | | |
43 | | //! %calendar class |
44 | | /*! This class provides methods for determining whether a date is a |
45 | | business day or a holiday for a given market, and for |
46 | | incrementing/decrementing a date of a given number of business days. |
47 | | |
48 | | The Bridge pattern is used to provide the base behavior of the |
49 | | calendar, namely, to determine whether a date is a business day. |
50 | | |
51 | | A calendar should be defined for specific exchange holiday schedule |
52 | | or for general country holiday schedule. Legacy city holiday schedule |
53 | | calendars will be moved to the exchange/country convention. |
54 | | |
55 | | \ingroup datetime |
56 | | |
57 | | \test the methods for adding and removing holidays are tested |
58 | | by inspecting the calendar before and after their |
59 | | invocation. |
60 | | */ |
61 | | class Calendar { |
62 | | protected: |
63 | | //! abstract base class for calendar implementations |
64 | | class Impl { |
65 | | public: |
66 | 161k | virtual ~Impl() = default; |
67 | | virtual std::string name() const = 0; |
68 | | virtual bool isBusinessDay(const Date&) const = 0; |
69 | | virtual bool isWeekend(Weekday) const = 0; |
70 | | std::set<Date> addedHolidays, removedHolidays; |
71 | | }; |
72 | | ext::shared_ptr<Impl> impl_; |
73 | | public: |
74 | | /*! The default constructor returns a calendar with a null |
75 | | implementation, which is therefore unusable except as a |
76 | | placeholder. |
77 | | */ |
78 | 402k | Calendar() = default; |
79 | | //! \name Calendar interface |
80 | | //@{ |
81 | | //! Returns whether or not the calendar is initialized |
82 | | bool empty() const; |
83 | | //! Returns the name of the calendar. |
84 | | /*! \warning This method is used for output and comparison between |
85 | | calendars. It is <b>not</b> meant to be used for writing |
86 | | switch-on-type code. |
87 | | */ |
88 | | std::string name() const; |
89 | | /*! Returns <tt>true</tt> iff the date is a business day for the |
90 | | given market. |
91 | | */ |
92 | | |
93 | | /*! Returns the set of added holidays for the given calendar */ |
94 | | const std::set<Date>& addedHolidays() const; |
95 | | |
96 | | /*! Returns the set of removed holidays for the given calendar */ |
97 | | const std::set<Date>& removedHolidays() const; |
98 | | |
99 | | /*! Clear the set of added and removed holidays */ |
100 | | void resetAddedAndRemovedHolidays(); |
101 | | |
102 | | bool isBusinessDay(const Date& d) const; |
103 | | /*! Returns <tt>true</tt> iff the date is a holiday for the given |
104 | | market. |
105 | | */ |
106 | | bool isHoliday(const Date& d) const; |
107 | | /*! Returns <tt>true</tt> iff the weekday is part of the |
108 | | weekend for the given market. |
109 | | */ |
110 | | bool isWeekend(Weekday w) const; |
111 | | /*! Returns <tt>true</tt> iff in the given market, the date is on |
112 | | or before the first business day for that month. |
113 | | */ |
114 | | bool isStartOfMonth(const Date& d) const; |
115 | | //! first business day of the month to which the given date belongs |
116 | | Date startOfMonth(const Date& d) const; |
117 | | /*! Returns <tt>true</tt> iff in the given market, the date is on |
118 | | or after the last business day for that month. |
119 | | */ |
120 | | bool isEndOfMonth(const Date& d) const; |
121 | | //! last business day of the month to which the given date belongs |
122 | | Date endOfMonth(const Date& d) const; |
123 | | |
124 | | /*! Adds a date to the set of holidays for the given calendar. */ |
125 | | void addHoliday(const Date&); |
126 | | /*! Removes a date from the set of holidays for the given calendar. */ |
127 | | void removeHoliday(const Date&); |
128 | | |
129 | | /*! Returns the holidays between two dates. */ |
130 | | std::vector<Date> holidayList(const Date& from, |
131 | | const Date& to, |
132 | | bool includeWeekEnds = false) const; |
133 | | /*! Returns the business days between two dates. */ |
134 | | std::vector<Date> businessDayList(const Date& from, |
135 | | const Date& to) const; |
136 | | |
137 | | /*! Adjusts a non-business day to the appropriate near business day |
138 | | with respect to the given convention. |
139 | | */ |
140 | | Date adjust(const Date&, |
141 | | BusinessDayConvention convention = Following) const; |
142 | | /*! Advances the given date of the given number of business days and |
143 | | returns the result. |
144 | | \note The input date is not modified. |
145 | | */ |
146 | | Date advance(const Date&, |
147 | | Integer n, |
148 | | TimeUnit unit, |
149 | | BusinessDayConvention convention = Following, |
150 | | bool endOfMonth = false) const; |
151 | | /*! Advances the given date as specified by the given period and |
152 | | returns the result. |
153 | | \note The input date is not modified. |
154 | | */ |
155 | | Date advance(const Date& date, |
156 | | const Period& period, |
157 | | BusinessDayConvention convention = Following, |
158 | | bool endOfMonth = false) const; |
159 | | /*! Calculates the number of business days between two given |
160 | | dates and returns the result. |
161 | | */ |
162 | | Date::serial_type businessDaysBetween(const Date& from, |
163 | | const Date& to, |
164 | | bool includeFirst = true, |
165 | | bool includeLast = false) const; |
166 | | //@} |
167 | | |
168 | | protected: |
169 | | //! partial calendar implementation |
170 | | /*! This class provides the means of determining the Easter |
171 | | Monday for a given year, as well as specifying Saturdays |
172 | | and Sundays as weekend days. |
173 | | */ |
174 | | class WesternImpl : public Impl { |
175 | | public: |
176 | | bool isWeekend(Weekday) const override; |
177 | | //! expressed relative to first day of year |
178 | | static Day easterMonday(Year); |
179 | | }; |
180 | | //! partial calendar implementation |
181 | | /*! This class provides the means of determining the Orthodox |
182 | | Easter Monday for a given year, as well as specifying |
183 | | Saturdays and Sundays as weekend days. |
184 | | */ |
185 | | class OrthodoxImpl : public Impl { |
186 | | public: |
187 | | bool isWeekend(Weekday) const override; |
188 | | //! expressed relative to first day of year |
189 | | static Day easterMonday(Year); |
190 | | }; |
191 | | }; |
192 | | |
193 | | /*! Returns <tt>true</tt> iff the two calendars belong to the same |
194 | | derived class. |
195 | | \relates Calendar |
196 | | */ |
197 | | bool operator==(const Calendar&, const Calendar&); |
198 | | |
199 | | /*! \relates Calendar */ |
200 | | bool operator!=(const Calendar&, const Calendar&); |
201 | | |
202 | | /*! \relates Calendar */ |
203 | | std::ostream& operator<<(std::ostream&, const Calendar&); |
204 | | |
205 | | |
206 | | // inline definitions |
207 | | |
208 | 0 | inline bool Calendar::empty() const { |
209 | 0 | return !impl_; |
210 | 0 | } |
211 | | |
212 | 0 | inline std::string Calendar::name() const { |
213 | 0 | QL_REQUIRE(impl_, "no calendar implementation provided"); |
214 | 0 | return impl_->name(); |
215 | 0 | } Unexecuted instantiation: QuantLib::Calendar::name() const Unexecuted instantiation: QuantLib::Calendar::name() const |
216 | | |
217 | 0 | inline const std::set<Date>& Calendar::addedHolidays() const { |
218 | 0 | QL_REQUIRE(impl_, "no calendar implementation provided"); |
219 | 0 |
|
220 | 0 | return impl_->addedHolidays; |
221 | 0 | } |
222 | | |
223 | 0 | inline const std::set<Date>& Calendar::removedHolidays() const { |
224 | 0 | QL_REQUIRE(impl_, "no calendar implementation provided"); |
225 | 0 |
|
226 | 0 | return impl_->removedHolidays; |
227 | 0 | } |
228 | | |
229 | 28.8M | inline bool Calendar::isBusinessDay(const Date& d) const { |
230 | 28.8M | QL_REQUIRE(impl_, "no calendar implementation provided"); |
231 | | |
232 | | #ifdef QL_HIGH_RESOLUTION_DATE |
233 | | const Date _d(d.dayOfMonth(), d.month(), d.year()); |
234 | | #else |
235 | 28.8M | const Date& _d = d; |
236 | 28.8M | #endif |
237 | | |
238 | 28.8M | if (!impl_->addedHolidays.empty() && |
239 | 28.8M | impl_->addedHolidays.find(_d) != impl_->addedHolidays.end()) |
240 | 0 | return false; |
241 | | |
242 | 28.8M | if (!impl_->removedHolidays.empty() && |
243 | 28.8M | impl_->removedHolidays.find(_d) != impl_->removedHolidays.end()) |
244 | 0 | return true; |
245 | | |
246 | 28.8M | return impl_->isBusinessDay(_d); |
247 | 28.8M | } Unexecuted instantiation: QuantLib::Calendar::isBusinessDay(QuantLib::Date const&) const QuantLib::Calendar::isBusinessDay(QuantLib::Date const&) const Line | Count | Source | 229 | 28.8M | inline bool Calendar::isBusinessDay(const Date& d) const { | 230 | 28.8M | QL_REQUIRE(impl_, "no calendar implementation provided"); | 231 | | | 232 | | #ifdef QL_HIGH_RESOLUTION_DATE | 233 | | const Date _d(d.dayOfMonth(), d.month(), d.year()); | 234 | | #else | 235 | 28.8M | const Date& _d = d; | 236 | 28.8M | #endif | 237 | | | 238 | 28.8M | if (!impl_->addedHolidays.empty() && | 239 | 28.8M | impl_->addedHolidays.find(_d) != impl_->addedHolidays.end()) | 240 | 0 | return false; | 241 | | | 242 | 28.8M | if (!impl_->removedHolidays.empty() && | 243 | 28.8M | impl_->removedHolidays.find(_d) != impl_->removedHolidays.end()) | 244 | 0 | return true; | 245 | | | 246 | 28.8M | return impl_->isBusinessDay(_d); | 247 | 28.8M | } |
|
248 | | |
249 | 0 | inline bool Calendar::isStartOfMonth(const Date& d) const { |
250 | 0 | return d <= startOfMonth(d); |
251 | 0 | } |
252 | | |
253 | 0 | inline Date Calendar::startOfMonth(const Date& d) const { |
254 | 0 | return adjust(Date::startOfMonth(d), Following); |
255 | 0 | } |
256 | | |
257 | 0 | inline bool Calendar::isEndOfMonth(const Date& d) const { |
258 | 0 | return d >= endOfMonth(d); |
259 | 0 | } |
260 | | |
261 | 0 | inline Date Calendar::endOfMonth(const Date& d) const { |
262 | 0 | return adjust(Date::endOfMonth(d), Preceding); |
263 | 0 | } |
264 | | |
265 | 28.8M | inline bool Calendar::isHoliday(const Date& d) const { |
266 | 28.8M | return !isBusinessDay(d); |
267 | 28.8M | } |
268 | | |
269 | 0 | inline bool Calendar::isWeekend(Weekday w) const { |
270 | 0 | QL_REQUIRE(impl_, "no calendar implementation provided"); |
271 | 0 | return impl_->isWeekend(w); |
272 | 0 | } Unexecuted instantiation: QuantLib::Calendar::isWeekend(QuantLib::Weekday) const Unexecuted instantiation: QuantLib::Calendar::isWeekend(QuantLib::Weekday) const |
273 | | |
274 | 0 | inline bool operator==(const Calendar& c1, const Calendar& c2) { |
275 | 0 | return (c1.empty() && c2.empty()) |
276 | 0 | || (!c1.empty() && !c2.empty() && c1.name() == c2.name()); |
277 | 0 | } |
278 | | |
279 | 0 | inline bool operator!=(const Calendar& c1, const Calendar& c2) { |
280 | 0 | return !(c1 == c2); |
281 | 0 | } |
282 | | |
283 | 0 | inline std::ostream& operator<<(std::ostream& out, const Calendar &c) { |
284 | 0 | return out << c.name(); |
285 | 0 | } |
286 | | |
287 | | } |
288 | | |
289 | | #endif |