Skip to content

Commit baa2815

Browse files
author
Ferdinando Ametrano
committed
added ECB "codes" handling
1 parent 539891c commit baa2815

File tree

2 files changed

+220
-4
lines changed

2 files changed

+220
-4
lines changed

ql/time/ecb.cpp

+177-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,14 @@
1919

2020
#include <ql/time/ecb.hpp>
2121
#include <ql/settings.hpp>
22+
#include <ql/utilities/dataparsers.hpp>
2223
#include <algorithm>
2324

25+
#include <boost/algorithm/string/case_conv.hpp>
26+
27+
using boost::algorithm::to_upper_copy;
28+
using std::string;
29+
2430
namespace QuantLib {
2531

2632
static std::set<Date> knownDateSet;
@@ -56,6 +62,105 @@ namespace QuantLib {
5662
knownDateSet.erase(d);
5763
}
5864

65+
Date ECB::date(const string& ecbCode,
66+
const Date& refDate) {
67+
68+
QL_REQUIRE(isECBcode(ecbCode),
69+
ecbCode << " is not a valid ECB code");
70+
71+
string code = to_upper_copy(ecbCode);
72+
string monthString = code.substr(0, 3);
73+
QuantLib::Month m;
74+
if (monthString=="JAN") m = January;
75+
else if (monthString=="FEB") m = February;
76+
else if (monthString=="MAR") m = March;
77+
else if (monthString=="APR") m = April;
78+
else if (monthString=="MAY") m = May;
79+
else if (monthString=="JUN") m = June;
80+
else if (monthString=="JUL") m = July;
81+
else if (monthString=="AUG") m = August;
82+
else if (monthString=="SEP") m = September;
83+
else if (monthString=="OCT") m = October;
84+
else if (monthString=="NOV") m = November;
85+
else if (monthString=="DEC") m = December;
86+
else QL_FAIL("not an ECB month (and it should have been)");
87+
88+
// lexical_cast causes compilation errors with x64
89+
//Year y = boost::lexical_cast<Year>(code.substr(3, 2));
90+
91+
Year y = io::to_integer(code.substr(3, 2));
92+
Date referenceDate = (refDate != Date() ?
93+
refDate :
94+
Date(Settings::instance().evaluationDate()));
95+
Year referenceYear = (referenceDate.year() % 100);
96+
y += referenceDate.year() - referenceYear;
97+
if (y<Date::minDate().year())
98+
return ECB::nextDate(Date::minDate());
99+
100+
return ECB::nextDate(Date(1, m, y));
101+
}
102+
103+
string ECB::code(const Date& ecbDate) {
104+
105+
QL_REQUIRE(isECBdate(ecbDate),
106+
ecbDate << " is not a valid ECB date");
107+
108+
std::ostringstream ECBcode;
109+
unsigned int y = ecbDate.year() % 100;
110+
string padding;
111+
if (y < 10)
112+
padding = "0";
113+
switch(ecbDate.month()) {
114+
case January:
115+
ECBcode << "JAN" << padding << y;
116+
break;
117+
case February:
118+
ECBcode << "FEB" << padding << y;
119+
break;
120+
case March:
121+
ECBcode << "MAR" << padding << y;
122+
break;
123+
case April:
124+
ECBcode << "APR" << padding << y;
125+
break;
126+
case May:
127+
ECBcode << "MAY" << padding << y;
128+
break;
129+
case June:
130+
ECBcode << "JUN" << padding << y;
131+
break;
132+
case July:
133+
ECBcode << "JUL" << padding << y;
134+
break;
135+
case August:
136+
ECBcode << "AUG" << padding << y;
137+
break;
138+
case September:
139+
ECBcode << "SEP" << padding << y;
140+
break;
141+
case October:
142+
ECBcode << "OCT" << padding << y;
143+
break;
144+
case November:
145+
ECBcode << "NOV" << padding << y;
146+
break;
147+
case December:
148+
ECBcode << "DEC" << padding << y;
149+
break;
150+
default:
151+
QL_FAIL("not an ECB month (and it should have been)");
152+
}
153+
154+
#if defined(QL_EXTRA_SAFETY_CHECKS)
155+
QL_ENSURE(isECBcode(ECBcode.str()),
156+
"the result " << ECBcode.str() <<
157+
" is an invalid ECB code");
158+
#endif
159+
return ECBcode.str();
160+
}
161+
162+
163+
59164
Date ECB::nextDate(const Date& date) {
60165
Date d = (date == Date() ?
61166
Settings::instance().evaluationDate() :
@@ -65,7 +170,7 @@ namespace QuantLib {
65170
std::upper_bound(knownDates().begin(), knownDates().end(), d);
66171

67172
QL_REQUIRE(i!=knownDates().end(),
68-
"ECB dates after " << *knownDates().end() << " are unknown");
173+
"ECB dates after " << *(--knownDates().end()) << " are unknown");
69174
return Date(*i);
70175
}
71176

@@ -82,4 +187,75 @@ namespace QuantLib {
82187
return std::vector<Date>(i, knownDates().end());
83188
}
84189

190+
191+
bool ECB::isECBcode(const std::string& ecbCode) {
192+
193+
if (ecbCode.length() != 5)
194+
return false;
195+
196+
string code = to_upper_copy(ecbCode);
197+
198+
string str1("0123456789");
199+
string::size_type loc = str1.find(code.substr(3, 1), 0);
200+
if (loc == string::npos)
201+
return false;
202+
loc = str1.find(code.substr(4, 1), 0);
203+
if (loc == string::npos)
204+
return false;
205+
206+
string monthString = code.substr(0, 3);
207+
if (monthString=="JAN") return true;
208+
else if (monthString=="FEB") return true;
209+
else if (monthString=="MAR") return true;
210+
else if (monthString=="APR") return true;
211+
else if (monthString=="MAY") return true;
212+
else if (monthString=="JUN") return true;
213+
else if (monthString=="JUL") return true;
214+
else if (monthString=="AUG") return true;
215+
else if (monthString=="SEP") return true;
216+
else if (monthString=="OCT") return true;
217+
else if (monthString=="NOV") return true;
218+
else if (monthString=="DEC") return true;
219+
else return false;
220+
}
221+
222+
string ECB::nextCode(const std::string& ecbCode) {
223+
QL_REQUIRE(isECBcode(ecbCode),
224+
ecbCode << " is not a valid ECB code");
225+
226+
string code = to_upper_copy(ecbCode);
227+
std::ostringstream result;
228+
229+
string monthString = code.substr(0, 3);
230+
if (monthString=="JAN") result << "FEB" << code.substr(3, 2);
231+
else if (monthString=="FEB") result << "MAR" << code.substr(3, 2);
232+
else if (monthString=="MAR") result << "APR" << code.substr(3, 2);
233+
else if (monthString=="APR") result << "MAY" << code.substr(3, 2);
234+
else if (monthString=="MAY") result << "JUN" << code.substr(3, 2);
235+
else if (monthString=="JUN") result << "JUL" << code.substr(3, 2);
236+
else if (monthString=="JUL") result << "AUG" << code.substr(3, 2);
237+
else if (monthString=="AUG") result << "SEP" << code.substr(3, 2);
238+
else if (monthString=="SEP") result << "OCT" << code.substr(3, 2);
239+
else if (monthString=="OCT") result << "NOV" << code.substr(3, 2);
240+
else if (monthString=="NOV") result << "DEC" << code.substr(3, 2);
241+
else if (monthString=="DEC") {
242+
// lexical_cast causes compilation errors with x64
243+
//Year y = boost::lexical_cast<Year>(code.substr(3, 2));
244+
unsigned int y = (io::to_integer(code.substr(3, 2)) + 1) % 100;
245+
string padding;
246+
if (y < 10)
247+
padding = "0";
248+
249+
result << "JAN" << padding << y;
250+
} else QL_FAIL("not an ECB month (and it should have been)");
251+
252+
253+
#if defined(QL_EXTRA_SAFETY_CHECKS)
254+
QL_ENSURE(isECBcode(result.str()),
255+
"the result " << result.str() <<
256+
" is an invalid ECB code");
257+
#endif
258+
return result.str();
259+
}
260+
85261
}

ql/time/ecb.hpp

+43-3
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,62 @@ namespace QuantLib {
3737
static void addDate(const Date& d);
3838
static void removeDate(const Date& d);
3939

40+
//! maintenance period start date in the given month/year
41+
static Date date(Month m,
42+
Year y) { return nextDate(Date(1, m, y) - 1); }
43+
44+
/*! returns the ECB date for the given ECB code
45+
(e.g. March xxth, 2013 for MAR10).
46+
47+
\warning It raises an exception if the input
48+
string is not an ECB code
49+
*/
50+
static Date date(const std::string& ecbCode,
51+
const Date& referenceDate = Date());
52+
53+
/*! returns the ECB code for the given date
54+
(e.g. MAR10 for March xxth, 2010).
55+
56+
\warning It raises an exception if the input
57+
date is not an ECB date
58+
*/
59+
static std::string code(const Date& ecbDate);
60+
4061
//! next maintenance period start date following the given date
4162
static Date nextDate(const Date& d = Date());
4263

64+
//! next maintenance period start date following the given ECB code
65+
static Date nextDate(const std::string& ecbCode,
66+
const Date& referenceDate = Date()) {
67+
return nextDate(date(ecbCode, referenceDate));
68+
}
69+
4370
//! next maintenance period start dates following the given date
4471
static std::vector<Date> nextDates(const Date& d = Date());
4572

73+
//! next maintenance period start dates following the given code
74+
static std::vector<Date> nextDates(const std::string& ecbCode,
75+
const Date& referenceDate = Date()) {
76+
return nextDates(date(ecbCode, referenceDate));
77+
}
78+
4679
/*! returns whether or not the given date is
4780
a maintenance period start date */
4881
static bool isECBdate(const Date& d) {
4982
Date date = nextDate(d-1);
5083
return d==date;
5184
}
5285

53-
//! maintenance period start date in the given month/year
54-
static Date date(Month m,
55-
Year y) { return nextDate(Date(1, m, y) - 1); }
86+
//! returns whether or not the given string is an ECB code
87+
static bool isECBcode(const std::string& in);
88+
89+
//! next ECB code following the given date
90+
static std::string nextCode(const Date& d = Date()) {
91+
return code(nextDate(d));
92+
}
93+
94+
//! next ECB code following the given code
95+
static std::string nextCode(const std::string& ecbCode);
5696

5797
};
5898

0 commit comments

Comments
 (0)