Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
dategrid.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include <boost/algorithm/string.hpp>
23#include <ql/settings.hpp>
24#include <ql/time/daycounters/actualactual.hpp>
25
26using namespace QuantLib;
27using namespace std;
28
29namespace ore {
30namespace data {
31
33 : dates_(1, Settings::instance().evaluationDate()), tenors_(1, 0 * Days), times_(1, 0.0),
34 timeGrid_(times_.begin(), times_.end()), isValuationDate_(1, true), isCloseOutDate_(1, false) {}
35
36DateGrid::DateGrid(const string& grid, const QuantLib::Calendar& gridCalendar, const QuantLib::DayCounter& dayCounter)
37 : calendar_(gridCalendar), dayCounter_(dayCounter) {
38
39 if (grid == "ALPHA") {
40 // ALPHA is
41 // quarterly up to 10Y,
42 // annual up to 30Y,
43 // quinquennial up to 100Y
44 for (Size i = 1; i < 40; i++) { // 3M up to 39*3M = 117M = 9Y9M
45 Period p(i * 3, Months);
46 p.normalize();
47 tenors_.push_back(p);
48 }
49 for (Size i = 10; i < 30; i++) // 10Y up to 29Y
50 tenors_.push_back(Period(i, Years));
51 for (Size i = 30; i < 105; i += 5) // 30Y up to 100Y
52 tenors_.push_back(Period(i, Years));
53 } else if (grid == "BETA") {
54 // BETA is
55 // monthly up to 10Y,
56 // quarterly up to 20Y,
57 // annually up to 50Y,
58 // quinquennial up to 100Y
59 for (Size i = 1; i < 119; i++) {
60 Period p = i * Months;
61 p.normalize();
62 tenors_.push_back(p);
63 }
64 for (Size i = 40; i < 80; i++) {
65 Period p = i * 3 * Months;
66 p.normalize();
67 tenors_.push_back(p);
68 }
69 for (Size i = 20; i < 50; i++)
70 tenors_.push_back(i * Years);
71 for (Size i = 50; i <= 100; i += 5)
72 tenors_.push_back(i * Years);
73 } else { // uniform grid of format "numPillars,spacing" (e.g. 40,1M)
74 vector<string> tokens;
75 boost::split(tokens, grid, boost::is_any_of(","));
76 if (tokens.size() <= 2) {
77 // uniform grid of format "numPillars,spacing" (e.g. 40,1M)
78 Period gridTenor = 1 * Years; // default
79 Size gridSize = atoi(tokens[0].c_str());
80 QL_REQUIRE(gridSize > 0, "Invalid DateGrid string " << grid);
81 if (tokens.size() == 2)
82 gridTenor = data::parsePeriod(tokens[1]);
83 if (gridTenor == Period(1, Days)) {
84 // we have a daily grid. Period and Calendar are not consistent with
85 // working & actual days, so we set the tenor grid
86 Date today = Settings::instance().evaluationDate();
87 Date d = today;
88 for (Size i = 0; i < gridSize; i++) {
89 d = gridCalendar.advance(d, Period(1, Days), Following); // next working day
90 Size n = d - today;
91 tenors_.push_back(Period(n, Days));
92 }
93 } else {
94 for (Size i = 0; i < gridSize; i++)
95 tenors_.push_back((i + 1) * gridTenor);
96 }
97 } else {
98 // New style : 1D,2D,1W,2W,3Y,5Y,....
99 for (Size i = 0; i < tokens.size(); i++)
100 tenors_.push_back(data::parsePeriod(tokens[i]));
101 }
102 }
103 buildDates(gridCalendar, dayCounter);
104}
105
106DateGrid::DateGrid(const vector<Period>& tenors, const QuantLib::Calendar& gridCalendar,
107 const QuantLib::DayCounter& dayCounter)
108 : calendar_(gridCalendar), dayCounter_(dayCounter), tenors_(tenors) {
109 QL_REQUIRE(!tenors_.empty(), "DateGrid requires a non-empty vector of tenors");
110 QL_REQUIRE(is_sorted(tenors_.begin(), tenors_.end()),
111 "Construction of DateGrid requires a sorted vector of unique tenors");
112 buildDates(gridCalendar, dayCounter);
113}
114
115DateGrid::DateGrid(const vector<Date>& dates, const QuantLib::Calendar& cal, const DayCounter& dayCounter)
116 : calendar_(cal), dayCounter_(dayCounter), dates_(dates) {
117 QL_REQUIRE(!dates_.empty(), "Construction of DateGrid requires a non-empty vector of dates");
118 QL_REQUIRE(is_sorted(dates_.begin(), dates_.end()),
119 "Construction of DateGrid requires a sorted vector of unique dates");
120 Date today = Settings::instance().evaluationDate();
121 QL_REQUIRE(today < dates_.front(),
122 "Construction of DateGrid requires first element to be strictly greater than today");
123
124 // Populate the tenors, times and timegrid
125 tenors_.resize(dates_.size());
126 times_.resize(dates_.size());
127 for (Size i = 0; i < dates_.size(); i++) {
128 tenors_[i] = (dates_[i] - today) * Days;
129 times_[i] = dayCounter.yearFraction(today, dates_[i]);
130 }
131 timeGrid_ = TimeGrid(times_.begin(), times_.end());
132 isValuationDate_ = std::vector<bool>(dates_.size(), true);
133 isCloseOutDate_ = std::vector<bool>(dates_.size(), false);
134
135 // Log the date grid
136 log();
137}
138
139void DateGrid::buildDates(const QuantLib::Calendar& cal, const QuantLib::DayCounter& dc) {
140 // build dates from tenors
141 // this is called by both constructors
142 dates_.resize(tenors_.size());
143 Date today = Settings::instance().evaluationDate();
144 for (Size i = 0; i < tenors_.size(); i++) {
145 if (tenors_[i].units() == Days)
146 dates_[i] = cal.adjust(today + tenors_[i]);
147 else
148 dates_[i] = cal.advance(today, tenors_[i], Following, false);
149 if (i > 0) {
150 QL_REQUIRE(dates_[i] >= dates_[i - 1], "DateGrid::buildDates(): tenors must be monotonic");
151 if (dates_[i] == dates_[i - 1]) {
152 dates_.erase(std::next(dates_.begin(), i));
153 tenors_.erase(std::next(tenors_.begin(), i));
154 --i;
155 }
156 }
157 }
158
159 // Build times
160 times_.resize(dates_.size());
161 for (Size i = 0; i < dates_.size(); i++)
162 times_[i] = dc.yearFraction(today, dates_[i]);
163
164 timeGrid_ = TimeGrid(times_.begin(), times_.end());
165 isValuationDate_ = std::vector<bool>(dates_.size(), true);
166 isCloseOutDate_ = std::vector<bool>(dates_.size(), false);
167
168 // Log the date grid
169 log();
170}
171
173 DLOG("DateGrid constructed, size = " << size());
174 for (Size i = 0; i < tenors_.size(); i++)
175 DLOG("[" << setw(2) << i << "] Tenor:" << tenors_[i] << ", Date:" << io::iso_date(dates_[i])
176 << ", Valuation:" << isValuationDate_[i] << ", CloseOut:" << isCloseOutDate_[i]);
177}
178
179void DateGrid::truncate(const Date& d, bool overrun) {
180 if (d >= dates_.back())
181 return; // no need for any truncation
182 DLOG("Truncating DateGrid beyond " << QuantLib::io::iso_date(d));
183 vector<Date>::iterator it = std::upper_bound(dates_.begin(), dates_.end(), d);
184 if (overrun)
185 ++it;
186 dates_.erase(it, dates_.end());
187 tenors_.resize(dates_.size());
188 times_.resize(dates_.size());
189 timeGrid_ = TimeGrid(times_.begin(), times_.end());
190 DLOG("DateGrid size now " << dates_.size());
191}
192
193void DateGrid::truncate(Size len) {
194 // Truncate grid up length len
195 if (dates_.size() > len) {
196 DLOG("Truncating DateGrid, removing elements " << dates_[len] << " to " << dates_.back());
197 dates_.resize(len);
198 tenors_.resize(len);
199 times_.resize(len);
200 timeGrid_ = TimeGrid(times_.begin(), times_.end());
201 isValuationDate_.resize(len);
202 isCloseOutDate_.resize(len);
203 DLOG("DateGrid size now " << dates_.size());
204 }
205}
206
207void DateGrid::addCloseOutDates(const QuantLib::Period& p) {
208 valuationCloseOutMap_.clear();
209 if (p == QuantLib::Period(0, QuantLib::Days)) {
210 for (Size i = 0; i < dates_.size(); ++i) {
211 if (i == 0) {
212 isCloseOutDate_.front() = false;
213 isValuationDate_.front() = true;
214 } else if (i == dates_.size() - 1) {
215 isCloseOutDate_.back() = true;
216 isValuationDate_.back() = false;
217 } else {
218 isCloseOutDate_[i] = true;
219 isValuationDate_[i] = true;
220 }
221 if (isCloseOutDate_[i] && i > 0)
223 }
224 } else {
225 std::set<QuantLib::Date> tmpCloseOutDates;
226 std::set<QuantLib::Date> tmpDates;
227 std::set<QuantLib::Date> tmpValueDates;
228 for (Size i = 0; i < dates_.size(); ++i) {
229 Date c;
230 if (p.units() == Days)
231 c = calendar_.adjust(dates_[i] + p);
232 else
233 c = calendar_.advance(dates_[i], p, Following, false);
234 tmpCloseOutDates.insert(c);
236 tmpDates.insert(dates_[i]);
237 tmpDates.insert(c);
238 tmpValueDates.insert(dates_[i]);
239 }
240 dates_.clear();
241 dates_.assign(tmpDates.begin(), tmpDates.end());
242 isCloseOutDate_ = std::vector<bool>(dates_.size(), false);
243 isValuationDate_ = std::vector<bool>(dates_.size(), true);
244 for(size_t i = 0; i < dates_.size(); ++i){
245 Date d = dates_[i];
246 if (tmpCloseOutDates.count(d) == 1) {
247 isCloseOutDate_[i] = true;
248 }
249 if(tmpValueDates.count(d) == 0){
250 isValuationDate_[i] = false;
251 }
252 }
253 // FIXME ... (is that needed anywhere ?)
254 tenors_ = std::vector<QuantLib::Period>(dates_.size(), 0 * Days);
255 times_.resize(dates_.size());
256 Date today = Settings::instance().evaluationDate();
257 for (Size i = 0; i < dates_.size(); i++)
258 times_[i] = dayCounter_.yearFraction(today, dates_[i]);
259 timeGrid_ = TimeGrid(times_.begin(), times_.end());
260 }
261 // Log Grid
262 DLOG("Added Close Out Dates to DateGrid , size = " << size());
263 log();
264}
265
266std::vector<QuantLib::Date> DateGrid::valuationDates() const {
267 std::vector<Date> res;
268 for (Size i = 0; i < dates_.size(); ++i) {
269 if (isValuationDate_[i])
270 res.push_back(dates_[i]);
271 }
272 return res;
273}
274
275std::vector<QuantLib::Date> DateGrid::closeOutDates() const {
276 std::vector<Date> res;
277 for (Size i = 0; i < dates_.size(); ++i) {
278 if (isCloseOutDate_[i])
279 res.push_back(dates_[i]);
280 }
281 return res;
282}
283
284QuantLib::TimeGrid DateGrid::valuationTimeGrid() const {
285 std::vector<Real> times;
286 Date today = Settings::instance().evaluationDate();
287 for (Size i = 0; i < dates_.size(); ++i) {
288 if (isValuationDate_[i])
289 times.push_back(dayCounter_.yearFraction(today, dates_[i]));
290 }
291 return TimeGrid(times.begin(), times.end());
292}
293
294QuantLib::TimeGrid DateGrid::closeOutTimeGrid() const {
295 std::vector<Real> times;
296 Date today = Settings::instance().evaluationDate();
297 for (Size i = 0; i < dates_.size(); ++i) {
298 if (isCloseOutDate_[i])
299 times.push_back(dayCounter_.yearFraction(today, dates_[i]));
300 }
301 return TimeGrid(times.begin(), times.end());
302}
303
304QuantLib::Date DateGrid::closeOutDateFromValuationDate(const QuantLib::Date& d) const {
305 auto it = valuationCloseOutMap_.find(d);
306 if(it == valuationCloseOutMap_.end()){
307 return Date();
308 }
309 return it->second;
310}
311
312QuantLib::ext::shared_ptr<DateGrid> generateShiftedDateGrid(const QuantLib::ext::shared_ptr<DateGrid>& dg,
313 const QuantLib::Period& shift) {
314 DLOG("Building shifted date grid with shift of " << shift);
315 vector<Date> defaultDates = dg->dates();
316 vector<Date> closeOutDates;
317 for (auto d : defaultDates) {
318 Date closeOut = dg->calendar().adjust(d + shift);
319 closeOutDates.push_back(closeOut);
320 }
321 QuantLib::ext::shared_ptr<DateGrid> newDg = QuantLib::ext::make_shared<DateGrid>(closeOutDates, dg->calendar(), dg->dayCounter());
322 return newDg;
323}
324
325QuantLib::ext::shared_ptr<DateGrid> combineDateGrids(const QuantLib::ext::shared_ptr<DateGrid>& dg1,
326 const QuantLib::ext::shared_ptr<DateGrid>& dg2) {
327 DLOG("Combining date grids");
328 vector<Date> combinedVec;
329 vector<Date> dates1 = dg1->dates();
330 vector<Date> dates2 = dg2->dates();
331 combinedVec.reserve(dates1.size() + dates2.size());
332 combinedVec.insert(combinedVec.end(), dates1.begin(), dates1.end());
333 combinedVec.insert(combinedVec.end(), dates2.begin(), dates2.end());
334 std::sort(combinedVec.begin(), combinedVec.end());
335 auto last = std::unique(combinedVec.begin(), combinedVec.end());
336 combinedVec.erase(last, combinedVec.end());
337 // FIXME: Check that grid calendars and day counters match?
338 QuantLib::ext::shared_ptr<DateGrid> newDg = QuantLib::ext::make_shared<DateGrid>(combinedVec, dg1->calendar(), dg1->dayCounter());
339 return newDg;
340}
341
342} // namespace data
343} // namespace ore
const TimeGrid & timeGrid_
void truncate(const QuantLib::Date &d, bool overrun=true)
Truncate the grid up to the given date.
std::map< QuantLib::Date, QuantLib::Date > valuationCloseOutMap_
Definition: dategrid.hpp:117
DateGrid()
Build a date grid with a single date equal to Settings::instance().evaluationDate()
Definition: dategrid.cpp:32
QuantLib::TimeGrid closeOutTimeGrid() const
Returns the time grid associated with the vector of close-out times (plus t=0)
Definition: dategrid.cpp:294
QuantLib::Size size() const
The size of the date grid.
Definition: dategrid.hpp:58
std::vector< QuantLib::Date > closeOutDates() const
Definition: dategrid.cpp:275
std::vector< QuantLib::Date > dates_
Definition: dategrid.hpp:116
std::vector< QuantLib::Date > valuationDates() const
Definition: dategrid.cpp:266
const std::vector< QuantLib::Time > & times() const
Returns the times from Settings::instance().evaluationDate to each Date using the day counter.
Definition: dategrid.hpp:90
std::vector< bool > isValuationDate_
Definition: dategrid.hpp:121
std::vector< QuantLib::Period > tenors_
Definition: dategrid.hpp:118
const QuantLib::DayCounter & dayCounter() const
Definition: dategrid.hpp:87
QuantLib::Date closeOutDateFromValuationDate(const QuantLib::Date &d) const
Definition: dategrid.cpp:304
QuantLib::Calendar calendar_
Definition: dategrid.hpp:114
QuantLib::TimeGrid valuationTimeGrid() const
Returns the time grid associated with the vector of valuation times (plus t=0)
Definition: dategrid.cpp:284
std::vector< QuantLib::Time > times_
Definition: dategrid.hpp:119
void addCloseOutDates(const QuantLib::Period &p=QuantLib::Period(2, QuantLib::Weeks))
Definition: dategrid.cpp:207
QuantLib::DayCounter dayCounter_
Definition: dategrid.hpp:115
std::vector< bool > isCloseOutDate_
Definition: dategrid.hpp:121
QuantLib::TimeGrid timeGrid_
Definition: dategrid.hpp:120
void buildDates(const QuantLib::Calendar &cal, const QuantLib::DayCounter &dc)
Definition: dategrid.cpp:139
The date grid class.
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
QuantLib::ext::shared_ptr< DateGrid > combineDateGrids(const QuantLib::ext::shared_ptr< DateGrid > &dg1, const QuantLib::ext::shared_ptr< DateGrid > &dg2)
Definition: dategrid.cpp:325
QuantLib::ext::shared_ptr< DateGrid > generateShiftedDateGrid(const QuantLib::ext::shared_ptr< DateGrid > &dg, const QuantLib::Period &shift)
Definition: dategrid.cpp:312
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.