QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
ecb.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2009, 2011 Ferdinando Ametrano
5 Copyright (C) 2015 Paolo Mazzocchi
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/time/ecb.hpp>
22#include <ql/settings.hpp>
24#include <boost/utility/string_view.hpp>
25#include <boost/bimap/bimap.hpp>
26#include <boost/bimap/set_of.hpp>
27#include <algorithm>
28#include <string>
29#include <cstdio>
30#include <cctype>
31
32using std::string;
33
34namespace QuantLib {
35
36 namespace {
37 // case-insensitive comparison. answers: lhs < rhs.
38 struct is_iless {
39 bool operator()(const boost::string_view lhs,
40 const boost::string_view rhs) const {
41 char lhsUpper[3];
42 char rhsUpper[3];
43 for (int i = 0; i < 3; ++i) {
44 lhsUpper[i] = std::toupper(lhs[i]);
45 rhsUpper[i] = std::toupper(rhs[i]);
46 }
47 return boost::string_view(lhsUpper, 3) <
48 boost::string_view(rhsUpper, 3);
49 }
50 };
51
52 using MonthBimap_t = boost::bimaps::bimap<
53 boost::bimaps::set_of<boost::string_view, is_iless>, Month>;
54
55 // bimap: generalization of map. can be queried by string_view or Month.
56 const MonthBimap_t MONTHS = []() {
57 MonthBimap_t months;
58 months.insert({"JAN", January});
59 months.insert({"FEB", February});
60 months.insert({"MAR", March});
61 months.insert({"APR", April});
62 months.insert({"MAY", May});
63 months.insert({"JUN", June});
64 months.insert({"JUL", July});
65 months.insert({"AUG", August});
66 months.insert({"SEP", September});
67 months.insert({"OCT", October});
68 months.insert({"NOV", November});
69 months.insert({"DEC", December});
70 return months;
71 }();
72
73 //clang-format off
74 // Start of maintenance period
75 // source: https://web.archive.org/web/20230610050642/https://www.ecb.europa.eu/press/calendars/reserve/html/index.en.html
76 std::set<Date> ecbKnownDateSet = {
77 // 2005
78 Date(38371), Date(38391), Date(38420), Date(38455), Date(38483), Date(38511),
79 Date(38546), Date(38574), Date(38602), Date(38637), Date(38665), Date(38692),
80
81 // 2006
82 Date(38735), Date(38756), Date(38784), Date(38819), Date(38847), Date(38883),
83 Date(38910), Date(38938), Date(38966), Date(39001), Date(39029), Date(39064),
84
85 // 2007
86 Date(39099), Date(39127), Date(39155), Date(39190), Date(39217), Date(39246),
87 Date(39274), Date(39302), Date(39337), Date(39365), Date(39400), Date(39428),
88
89 // 2008
90 Date(39463), Date(39491), Date(39519), Date(39554), Date(39582), Date(39610),
91 Date(39638), Date(39673), Date(39701), Date(39729), Date(39764), Date(39792),
92
93 // 2009
94 Date(39834), Date(39855), Date(39883), Date(39911), Date(39946), Date(39974),
95 Date(40002), Date(40037), Date(40065), Date(40100), Date(40128), Date(40155),
96
97 // 2010
98 Date(40198), Date(40219), Date(40247), Date(40282), Date(40310), Date(40345),
99 Date(40373), Date(40401), Date(40429), Date(40464), Date(40492), Date(40520),
100
101 // 2011
102 Date(40562), Date(40583), Date(40611), Date(40646), Date(40674), Date(40709),
103 Date(40737), Date(40765), Date(40800), Date(40828), Date(40856), Date(40891),
104
105 // 2012
106 Date(40926), Date(40954), Date(40982), Date(41010), Date(41038), Date(41073),
107 Date(41101), Date(41129), Date(41164), Date(41192), Date(41227), Date(41255),
108
109 // 2013
110 Date(41290), Date(41318), Date(41346), Date(41374), Date(41402), Date(41437),
111 Date(41465), Date(41493), Date(41528), Date(41556), Date(41591), Date(41619),
112
113 // 2014
114 Date(41654), Date(41682), Date(41710), Date(41738), Date(41773), Date(41801),
115 Date(41829), Date(41864), Date(41892), Date(41920), Date(41955), Date(41983),
116
117 // 2015
118 Date(42032), Date(42074), Date(42116), Date(42165), Date(42207), Date(42256),
119 Date(42305), Date(42347),
120
121 // 2016
122 Date(42396), Date(42445), Date(42487), Date(42529), Date(42578), Date(42627),
123 Date(42669), Date(42718),
124
125 // 2017
126 Date(42760), Date(42809), Date(42858), Date(42900), Date(42942), Date(42991),
127 Date(43040), Date(43089),
128
129 // 2018
130 Date(43131), Date(43167), Date(43216), Date(43265), Date(43307), Date(43356),
131 Date(43398), Date(43447),
132
133 // 2019
134 Date(43495), Date(43537), Date(43572), Date(43628), Date(43677), Date(43726),
135 Date(43768), Date(43817),
136
137 // 2020
138 Date(43859), Date(43908), Date(43957), Date(43992), Date(44034), Date(44090),
139 Date(44139), Date(44181),
140
141 // 2021
142 Date(44223), Date(44272), Date(44314), Date(44363), Date(44405), Date(44454),
143 Date(44503), Date(44552),
144
145 // 2022
146 Date(44601), Date(44636), Date(44671), Date(44727), Date(44769), Date(44818),
147 Date(44867), Date(44916),
148
149 // 2023
150 Date(44965), Date(45007), Date(45056), Date(45098), Date(45140), Date(45189),
151 Date(45231), Date(45280),
152
153 // 2024
154 Date(45322), Date(45364), Date(45399), Date(45455), Date(45497), Date(45553),
155 Date(45588), Date(45644)
156 };
157 //clang-format on
158 }
159
160 const std::set<Date>& ECB::knownDates() {
161 return ecbKnownDateSet;
162 }
163
164 void ECB::addDate(const Date& d) {
165 ecbKnownDateSet.insert(d);
166 }
167
168 void ECB::removeDate(const Date& d) {
169 ecbKnownDateSet.erase(d);
170 }
171
172 namespace {
173 int ToInteger(const char c) {
174 const int i = static_cast<int>(c) - static_cast<int>('0');
175 QL_ASSERT((i >= 0) && (i <= 9), "Character does not represent a digit. char: " << c);
176 return i;
177 }
178 }
179
180 Date ECB::date(const string& ecbCode,
181 const Date& refDate) {
182
183 QL_REQUIRE(isECBcode(ecbCode),
184 ecbCode << " is not a valid ECB code");
185
186 // convert first 3 characters to `Month m`
187 const boost::string_view monthCode(ecbCode.data(), 3);
188 const Month m = MONTHS.left.at(monthCode);
189
190 // convert 4th, 5th characters to `Year y`
191 Year y = ToInteger(ecbCode[3])*10 + ToInteger(ecbCode[4]);
192 Date referenceDate = (refDate != Date() ?
193 refDate :
194 Date(Settings::instance().evaluationDate()));
195 Year referenceYear = (referenceDate.year() % 100);
196 y += referenceDate.year() - referenceYear;
197 if (y<Date::minDate().year())
199
200 return ECB::nextDate(Date(1, m, y) - 1);
201 }
202
203 string ECB::code(const Date& ecbDate) {
204
205 QL_REQUIRE(isECBdate(ecbDate),
206 ecbDate << " is not a valid ECB date");
207
208 // 3 characters for the month
209 const boost::string_view month = MONTHS.right.at(ecbDate.month());
210
211 // last two digits of the year
212 const unsigned int y = ecbDate.year() % 100;
213
214 // c-style string. length: 6 == (3 for month + 2 for year + 1 for terminating null)
215 char ECBcode[6];
216 std::snprintf(ECBcode, 6, "%3s%02u", month.data(), y);
217
218 #if defined(QL_EXTRA_SAFETY_CHECKS)
219 QL_ENSURE(isECBcode(ECBcode),
220 "the result " << ECBcode <<
221 " is an invalid ECB code");
222 #endif
223 return ECBcode;
224 }
225
226 Date ECB::nextDate(const Date& date) {
227 Date d = (date == Date() ?
229 date);
230
231 auto i = std::upper_bound(knownDates().begin(), knownDates().end(), d);
232
233 QL_REQUIRE(i != knownDates().end(),
234 "ECB dates after " << *knownDates().rbegin() << " are unknown");
235 return *i;
236 }
237
238 std::vector<Date> ECB::nextDates(const Date& date) {
239 Date d = (date == Date() ?
241 date);
242
243 auto i = std::upper_bound(knownDates().begin(), knownDates().end(), d);
244
245 QL_REQUIRE(i != knownDates().end(),
246 "ECB dates after " << *knownDates().rbegin() << " are unknown");
247 return std::vector<Date>(i, knownDates().end());
248 }
249
250
251 bool ECB::isECBcode(const std::string& ecbCode) {
252
253 if (ecbCode.length() != 5)
254 return false;
255
256 // first 3 characters need to represent month, case insensitive
257 {
258 const boost::string_view month(ecbCode.data(), 3);
259 if (MONTHS.left.find(month) == MONTHS.left.end())
260 return false;
261 }
262
263 // 4th, 5th characters need to be digit
264 return (std::isdigit(static_cast<unsigned char>(ecbCode[3])) != 0)
265 && (std::isdigit(static_cast<unsigned char>(ecbCode[4])) != 0);
266 }
267
268 string ECB::nextCode(const std::string& ecbCode) {
269 QL_REQUIRE(isECBcode(ecbCode),
270 ecbCode << " is not a valid ECB code");
271
272 const boost::string_view month(ecbCode.data(), 3);
273 const Month monthEnum = MONTHS.left.at(month);
274
275 string nextCodeStr;
276 nextCodeStr.reserve(5);
277 if (monthEnum != December) {
278 // use next month
279 const auto nextMonthEnum = static_cast<Month>(monthEnum + 1);
280 const boost::string_view nextMonth = MONTHS.right.at(nextMonthEnum);
281 nextCodeStr.append(nextMonth.data(), 3);
282
283 // copy year
284 nextCodeStr += {ecbCode[3], ecbCode[4]};
285 } else {
286 // previous month was DEC
287 nextCodeStr.append("JAN");
288
289 // init with previous year
290 nextCodeStr += { ecbCode[3], ecbCode[4] };
291
292 // increment year's last digit (e.g. '22' -> '23').
293 // if overflow (e.g. '29' -> '20'), then also increment 2nd digit (e.g. '20' -> '30').
294 const auto incrementAndCheckForOverlow = [](char& dig) -> bool {
295 if (dig == '9') {
296 dig = '0';
297 return true;
298 } else {
299 ++dig;
300 return false;
301 }
302 };
303 if (incrementAndCheckForOverlow(nextCodeStr[4]))
304 incrementAndCheckForOverlow(nextCodeStr[3]);
305 }
306 return nextCodeStr;
307
308 #if defined(QL_EXTRA_SAFETY_CHECKS)
309 QL_ENSURE(isECBcode(nextCodeStr),
310 "the result " << nextCodeStr <<
311 " is an invalid ECB code");
312 #endif
313 return nextCodeStr;
314 }
315
316}
Concrete date class.
Definition: date.hpp:125
static Date minDate()
earliest allowed date
Definition: date.cpp:766
Month month() const
Definition: date.cpp:82
Year year() const
Definition: date.cpp:93
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
Classes used to parse data for input.
European Central Bank reserve maintenance date functions.
#define QL_ENSURE(condition, message)
throw an error if the given post-condition is not verified
Definition: errors.hpp:130
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_ASSERT(condition, message)
throw an error if the given condition is not verified
Definition: errors.hpp:104
Date d
Integer Year
Year number.
Definition: date.hpp:87
Month
Month names.
Definition: date.hpp:57
@ December
Definition: date.hpp:68
@ August
Definition: date.hpp:64
@ January
Definition: date.hpp:57
@ July
Definition: date.hpp:63
@ May
Definition: date.hpp:61
@ March
Definition: date.hpp:59
@ February
Definition: date.hpp:58
@ April
Definition: date.hpp:60
@ November
Definition: date.hpp:67
@ October
Definition: date.hpp:66
@ June
Definition: date.hpp:62
@ September
Definition: date.hpp:65
Definition: any.hpp:35
Real months(const Period &p)
Definition: period.cpp:296
global repository for run-time library settings
static void removeDate(const Date &d)
Definition: ecb.cpp:168
static std::vector< Date > nextDates(const Date &d=Date())
next maintenance period start dates following the given date
Definition: ecb.cpp:238
static void addDate(const Date &d)
Definition: ecb.cpp:164
static std::string nextCode(const Date &d=Date())
next ECB code following the given date
Definition: ecb.hpp:90
static const std::set< Date > & knownDates()
Definition: ecb.cpp:160
static bool isECBcode(const std::string &in)
returns whether or not the given string is an ECB code
Definition: ecb.cpp:251
static Date date(Month m, Year y)
maintenance period start date in the given month/year
Definition: ecb.hpp:41
static std::string code(const Date &ecbDate)
Definition: ecb.cpp:203
static Date nextDate(const Date &d=Date())
next maintenance period start date following the given date
Definition: ecb.cpp:226
static bool isECBdate(const Date &d)
Definition: ecb.hpp:81