Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
schedule.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
23#include <set>
24
25using namespace QuantLib;
26
27namespace ore {
28namespace data {
29
30namespace {
31std::vector<Date> everyWeekDayDates(const Date& startDate, const Date& endDate, const Date& firstDate, const QuantLib::Weekday weekday) {
32 std::vector<Date> result;
33 if (firstDate != Date())
34 result.push_back(firstDate);
35 Date d = startDate;
36 while (d <= endDate && (d.weekday() != weekday || d < firstDate)) {
37 ++d;
38 }
39 if (d.weekday() == weekday && (result.empty() || result.back() != d))
40 result.push_back(d);
41 while (d + 7 <= endDate) {
42 d += 7;
43 result.push_back(d);
44 }
45 return result;
46}
47
48std::vector<Date> weeklyDates(const Date& startDate, const Date& endDate, const Date& firstDate,
49 bool includeWeekend = false) {
50 QuantLib::Weekday weekday = includeWeekend ? QuantLib::Sunday : QuantLib::Friday;
51 // We want the first period to span from
52 // [startDate, first Friday/SunDay following startDate]
53 // or
54 // [firstDate, first Friday/SunDay following firstDate]
55 Date effectiveFirstDate = firstDate == Date() ? startDate : firstDate;
56 auto dates = everyWeekDayDates(startDate, endDate, effectiveFirstDate, weekday);
57 // Handle broken period
58 if (!dates.empty()) {
59 // If startDate/first Date falls on end of week,
60 // the first period is consist of only one day, so first periods should be
61 // [startDate, startDate], [startDate+1, next end of the week], ...
62 if (effectiveFirstDate.weekday() == weekday) {
63 dates.insert(dates.begin(), effectiveFirstDate);
64 }
65 // add the enddate if the enddate doesnt fall on friday, last broken period
66 if (dates.back() < endDate) {
67 dates.push_back(endDate);
68 }
69 }
70 return dates;
71}
72
73} // namespace
74
76 XMLUtils::checkNode(node, "Rules");
77 startDate_ = XMLUtils::getChildValue(node, "StartDate");
78 endDate_ = XMLUtils::getChildValue(node, "EndDate", false);
79 adjustEndDateToPreviousMonthEnd_ = XMLUtils::getChildValueAsBool(node, "AdjustEndDateToPreviousMonthEnd", false, false);
81 auto ed = parseDate(endDate_);
82 while(!Date::isEndOfMonth(ed))ed--;
83 endDate_ = to_string(ed);
84 }
85 tenor_ = XMLUtils::getChildValue(node, "Tenor") == "1T" ? "0D" : XMLUtils::getChildValue(node, "Tenor");
86 was1T_ = XMLUtils::getChildValue(node, "Tenor") == "1T" ? true : false;
87 calendar_ = XMLUtils::getChildValue(node, "Calendar");
88 convention_ = XMLUtils::getChildValue(node, "Convention");
89 termConvention_ = XMLUtils::getChildValue(node, "TermConvention", false);
90 if (termConvention_.empty()) {
92 }
93 rule_ = XMLUtils::getChildValue(node, "Rule");
94 endOfMonth_ = XMLUtils::getChildValue(node, "EndOfMonth");
95 endOfMonthConvention_ = XMLUtils::getChildValue(node, "EndOfMonthConvention");
96 firstDate_ = XMLUtils::getChildValue(node, "FirstDate");
97 lastDate_ = XMLUtils::getChildValue(node, "LastDate");
98 removeFirstDate_ = XMLUtils::getChildValueAsBool(node, "RemoveFirstDate", false, false);
99 removeLastDate_ = XMLUtils::getChildValueAsBool(node, "RemoveLastDate", false, false);
100}
101
103 XMLNode* rules = doc.allocNode("Rules");
104 XMLUtils::addChild(doc, rules, "StartDate", startDate_);
105 if (!endDate_.empty())
106 XMLUtils::addChild(doc, rules, "EndDate", endDate_);
107 XMLUtils::addChild(doc, rules, "Tenor", was1T_ ? "1T" : tenor_);
108 XMLUtils::addChild(doc, rules, "Calendar", calendar_);
109 XMLUtils::addChild(doc, rules, "Convention", convention_);
110 XMLUtils::addChild(doc, rules, "TermConvention", termConvention_);
111 XMLUtils::addChild(doc, rules, "Rule", rule_);
112 XMLUtils::addChild(doc, rules, "EndOfMonth", endOfMonth_);
113 if (!endOfMonthConvention_.empty())
114 XMLUtils::addChild(doc, rules, "EndOfMonthConvention", endOfMonthConvention_);
115 XMLUtils::addChild(doc, rules, "FirstDate", firstDate_);
116 XMLUtils::addChild(doc, rules, "LastDate", lastDate_);
118 XMLUtils::addChild(doc,rules,"RemoveFirstDate", removeFirstDate_);
120 XMLUtils::addChild(doc,rules,"RemoveLastDate", removeLastDate_);
121 return rules;
122}
123
125 XMLUtils::checkNode(node, "Dates");
126 calendar_ = XMLUtils::getChildValue(node, "Calendar");
127 convention_ = XMLUtils::getChildValue(node, "Convention");
128 tenor_ = XMLUtils::getChildValue(node, "Tenor") == "1T" ? "0D" : XMLUtils::getChildValue(node, "Tenor");
129 was1T_ = XMLUtils::getChildValue(node, "Tenor") == "1T" ? true : false;
130 endOfMonth_ = XMLUtils::getChildValue(node, "EndOfMonth");
131 dates_ = XMLUtils::getChildrenValues(node, "Dates", "Date");
132}
133
135 XMLNode* node = doc.allocNode("Dates");
136 XMLUtils::addChild(doc, node, "Calendar", calendar_);
137 if (!convention_.empty())
138 XMLUtils::addChild(doc, node, "Convention", convention_);
139 XMLUtils::addChild(doc, node, "Tenor", was1T_ ? "1T" : tenor_);
140 if (!endOfMonth_.empty())
141 XMLUtils::addChild(doc, node, "EndOfMonth", endOfMonth_);
142 XMLUtils::addChildren(doc, node, "Dates", "Date", dates_);
143 return node;
144}
145
147 XMLUtils::checkNode(node, "Derived");
148 baseSchedule_ = XMLUtils::getChildValue(node, "BaseSchedule");
149 shift_ = XMLUtils::getChildValue(node, "Shift", false);
150 calendar_ = XMLUtils::getChildValue(node, "Calendar", false);
151 convention_ = XMLUtils::getChildValue(node, "Convention", false);
152 removeFirstDate_ = XMLUtils::getChildValueAsBool(node, "RemoveFirstDate", false, false);
153 removeLastDate_ = XMLUtils::getChildValueAsBool(node, "RemoveLastDate", false, false);
154}
155
157 XMLNode* node = doc.allocNode("Derived");
158 XMLUtils::addChild(doc, node, "BaseSchedule", baseSchedule_);
159 if (!shift_.empty())
160 XMLUtils::addChild(doc, node, "Shift", shift_);
161 if (!calendar_.empty())
162 XMLUtils::addChild(doc, node, "Calendar", calendar_);
163 if (!convention_.empty())
164 XMLUtils::addChild(doc, node, "Convention", convention_);
166 XMLUtils::addChild(doc, node, "RemoveFirstDate", removeFirstDate_);
168 XMLUtils::addChild(doc, node, "RemoveLastDate", removeLastDate_);
169 return node;
170}
171
173 vector<string> baseScheduleNames;
174 for (auto& dv : derived_)
175 baseScheduleNames.push_back(dv.baseSchedule());
176 return baseScheduleNames;
177}
178
180 QL_REQUIRE(node, "ScheduleData::fromXML(): no node given");
182 for (auto& r : XMLUtils::getChildrenNodes(node, "Rules")) {
183 rules_.emplace_back();
184 rules_.back().fromXML(r);
185 }
186 for (auto& d : XMLUtils::getChildrenNodes(node, "Dates")) {
187 dates_.emplace_back();
188 dates_.back().fromXML(d);
189 }
190 for (auto& dv : XMLUtils::getChildrenNodes(node, "Derived")) {
191 derived_.emplace_back();
192 derived_.back().fromXML(dv);
193 if (!hasDerived_)
194 hasDerived_ = true;
195 }
196}
197
199 XMLNode* node = doc.allocNode("ScheduleData");
200 for (auto& r : rules_)
201 XMLUtils::appendNode(node, r.toXML(doc));
202 for (auto& d : dates_)
203 XMLUtils::appendNode(node, d.toXML(doc));
204 for (auto& dv : derived_)
205 XMLUtils::appendNode(node, dv.toXML(doc));
206 return node;
207}
208
209void ScheduleBuilder::add(Schedule& schedule, const ScheduleData& data) {
210 string name = data.name();
211 schedules_.insert(pair<string, pair<ScheduleData, Schedule&>>({name, {data, schedule}}));
212}
213
214void ScheduleBuilder::makeSchedules(const Date& openEndDateReplacement) {
215 map<string, Schedule> builtSchedules;
216 map<string, ScheduleData> derivedSchedules;
217
218 // First, we build all the rules-based and dates-based schedules
219 for (auto& s : schedules_) {
220 string schName = s.first;
221 ScheduleData& schData = s.second.first;
222 Schedule& sch = s.second.second;
223
224 if (!schData.hasDerived()) {
225 sch = makeSchedule(schData, openEndDateReplacement);
226 builtSchedules[schName] = sch;
227 } else {
228 derivedSchedules[schName] = schData;
229 }
230 }
231
232 // We then keep looping through the list of derived schedules and building these from the list of built schedules.
233 bool calculated;
234 while (derivedSchedules.size() > 0) {
235 calculated = false;
236 for (auto& ds : derivedSchedules) {
237 string dsName = ds.first;
238 ScheduleData& dsSchedData = ds.second;
239 vector<string> baseNames = dsSchedData.baseScheduleNames();
240 for (string& bn : baseNames) {
241 QL_REQUIRE(builtSchedules.find(bn) != builtSchedules.end(), "Could not find base schedule \" " << bn << "\" for derived schedule \" " << dsName << "\"");
242 }
243 Schedule schedule;
244 schedule = makeSchedule(dsSchedData, openEndDateReplacement, builtSchedules);
245 schedules_.find(dsName)->second.second = schedule;
246 builtSchedules[dsName] = schedule;
247 derivedSchedules.erase(dsName);
248 calculated = true;
249 break;
250 }
251
252 // If we go through the whole list without having built a schedule, then assume that we cannot build them
253 // anymore.
254 if (!calculated) {
255 for (auto& ds : derivedSchedules)
256 ALOG("makeSchedules(): could not find base schedule \"" << ds.first << "\"");
257 QL_FAIL("makeSchedules(): failed to build at least one derived schedule");
258 break;
259 }
260 }
261}
262
263Schedule makeSchedule(const ScheduleDates& data) {
264 QL_REQUIRE(data.dates().size() > 0, "Must provide at least 1 date for Schedule");
265 Calendar calendar = parseCalendar(data.calendar());
266 BusinessDayConvention convention = ModifiedFollowing;
267 if (!data.convention().empty())
268 convention = parseBusinessDayConvention(data.convention());
269 // Avoid compiler warning on gcc
270 // https://www.boost.org/doc/libs/1_74_0/libs/optional/doc/html/boost_optional/tutorial/
271 // gotchas/false_positive_with__wmaybe_uninitialized.html
272 auto tenor = boost::make_optional(false, Period());
273 if (!data.tenor().empty())
274 tenor = parsePeriod(data.tenor());
275 bool endOfMonth = false;
276 if (!data.endOfMonth().empty())
277 endOfMonth = parseBool(data.endOfMonth());
278 ext::optional<BusinessDayConvention> endOfMonthConvention = boost::none;
279 if (!data.endOfMonthConvention().empty())
280 endOfMonthConvention = parseBusinessDayConvention(data.endOfMonthConvention());
281
282 // Ensure that Schedule ctor is passed a vector of unique ordered dates.
283 std::set<Date> uniqueDates;
284 for (const string& d : data.dates())
285 uniqueDates.insert(calendar.adjust(parseDate(d), convention));
286
287 return QuantLib::Schedule(vector<Date>(uniqueDates.begin(), uniqueDates.end()), calendar, convention, boost::none,
288 tenor, boost::none, endOfMonth, vector<bool>(0), false, false, endOfMonthConvention);
289}
290
291Schedule makeSchedule(const ScheduleDerived& data, const Schedule& baseSchedule) {
292
293 string strCalendar = data.calendar();
294 Calendar calendar;
295 if (strCalendar.empty()) {
296 calendar = NullCalendar();
297 WLOG("No calendar provided in Schedule, attempting to use a null calendar.");
298 }
299 else
300 calendar = parseCalendar(strCalendar);
301
302 BusinessDayConvention convention;
303 string strConvention = data.convention();
304 if (strConvention.empty())
305 convention = BusinessDayConvention::Unadjusted;
306 else
307 convention = parseBusinessDayConvention(strConvention);
308
309 string strShift = data.shift();
310 Period shift;
311 if (strShift.empty())
312 shift = 0 * Days;
313 else
314 shift = parsePeriod(data.shift());
315
316 const std::vector<QuantLib::Date>& baseDates = baseSchedule.dates();
317 std::vector<QuantLib::Date> derivedDates;
318 QuantLib::Date derivedDate;
319 for (const Date& d : baseDates) {
320 derivedDate = calendar.advance(d, shift, convention);
321 derivedDates.push_back(derivedDate);
322 }
323 ext::optional<BusinessDayConvention> endOfMonthConvention = boost::none;
324 if (baseSchedule.hasEndOfMonthBusinessDayConvention())
325 endOfMonthConvention = baseSchedule.endOfMonthBusinessDayConvention();
326
327 return QuantLib::Schedule(vector<Date>(derivedDates.begin(), derivedDates.end()), calendar, convention, boost::none,
328 baseSchedule.tenor(), boost::none, baseSchedule.endOfMonth(), std::vector<bool>(0),
329 data.removeFirstDate(), data.removeLastDate(),
330 endOfMonthConvention);
331}
332
333Schedule makeSchedule(const ScheduleRules& data, const Date& openEndDateReplacement) {
334 QL_REQUIRE(!data.endDate().empty() || openEndDateReplacement != Null<Date>(),
335 "makeSchedule(): Schedule does not have an end date, this is not supported in this context / for this "
336 "trade type. Please provide an end date.");
337 QL_REQUIRE(!data.endDate().empty() || data.lastDate().empty(),
338 "makeSchedule(): If no end date is given, a last date is not allowed either. Please remove the last "
339 "date from the schedule.");
340 Calendar calendar = parseCalendar(data.calendar());
341 if (calendar == NullCalendar())
342 WLOG("No calendar provided in Schedule, attempting to use a null calendar.");
343 Date startDate = parseDate(data.startDate());
344 Date endDate = data.endDate().empty() ? openEndDateReplacement : parseDate(data.endDate());
345 // Handle trivial case here
346 if (startDate == endDate)
347 return Schedule(vector<Date>(1, startDate), calendar);
348
349 QL_REQUIRE(startDate < endDate, "StartDate " << startDate << " is ahead of EndDate " << endDate);
350
351 Date firstDate = parseDate(data.firstDate());
352 Date lastDate = parseDate(data.lastDate());
353 if (firstDate != Date() && lastDate != Date())
354 QL_REQUIRE(firstDate <= lastDate, "Schedule::makeSchedule firstDate must be before lastDate");
355
356 Period tenor = parsePeriod(data.tenor());
357
358 // defaults
359 BusinessDayConvention bdc = ModifiedFollowing;
360 BusinessDayConvention bdcEnd = ModifiedFollowing;
361 DateGeneration::Rule rule = DateGeneration::Forward;
362 bool endOfMonth = false;
363 ext::optional<BusinessDayConvention> endOfMonthConvention = boost::none;
364
365 // now check the strings, if they are empty we take defaults
366 if (!data.convention().empty())
367 bdc = parseBusinessDayConvention(data.convention());
368 if (!data.termConvention().empty())
369 bdcEnd = parseBusinessDayConvention(data.termConvention());
370 else
371 bdcEnd = bdc; // except here
372
373 if (!data.endOfMonth().empty())
374 endOfMonth = parseBool(data.endOfMonth());
375 if (!data.endOfMonthConvention().empty())
376 endOfMonthConvention = parseBusinessDayConvention(data.endOfMonthConvention());
377
378 if (!data.rule().empty()) {
379
380 // handle special rules outside the QuantLib date generation rules
381
382 if (data.rule() == "EveryThursday") {
383 auto dates = everyWeekDayDates(startDate, endDate, firstDate, QuantLib::Thursday);
384 for (auto& d : dates)
385 d = calendar.adjust(d, bdc);
386 return QuantLib::Schedule(dates, calendar, bdc, bdcEnd, tenor, rule, endOfMonth, std::vector<bool>(0), false, false, endOfMonthConvention);
387 } else if (data.rule() == "BusinessWeek" || data.rule() == "CalendarWeek") {
388 auto dates = weeklyDates(startDate, endDate, firstDate, data.rule() == "CalendarWeek");
389 for (auto& d : dates)
390 d = calendar.adjust(d, bdc);
391 return QuantLib::Schedule(dates, calendar, bdc, bdcEnd, tenor, rule, endOfMonth, std::vector<bool>(0), data.removeFirstDate(), data.removeLastDate(), endOfMonthConvention);
392 }
393
394 // parse rule for further processing below
395
396 rule = parseDateGenerationRule(data.rule());
397 }
398
399 // handling of date generation rules that require special adjustments
400
401 if ((rule == DateGeneration::CDS || rule == DateGeneration::CDS2015) &&
402 (firstDate != Null<Date>() || lastDate != Null<Date>())) {
403 // Special handling of first date and last date in combination with CDS and CDS2015 rules:
404 // To be able to construct CDS schedules with front or back stub periods, we overwrite the
405 // first (last) date of the schedule built in QL with a given first (last) date
406 // The schedule builder in QL itself is not capable of doing this, it just throws an exception
407 // if a first (last) date is given in combination with a CDS / CDS2015 date generation rule.
408 std::vector<Date> dates = QuantLib::Schedule(startDate, endDate, tenor, calendar, bdc, bdcEnd, rule, endOfMonth,
409 Date(), Date(), false, false, endOfMonthConvention)
410 .dates();
411 QL_REQUIRE(!dates.empty(),
412 "got empty CDS or CDS2015 schedule, startDate = " << startDate << ", endDate = " << endDate);
413 if (firstDate != Date())
414 dates.front() = firstDate;
415 if (lastDate != Date())
416 dates.back() = lastDate;
417 return QuantLib::Schedule(dates, calendar, bdc, bdcEnd, tenor, rule, endOfMonth, std::vector<bool>(0),
418 data.removeFirstDate(), data.removeLastDate(), endOfMonthConvention);
419 }
420
421 // default handling (QuantLib scheduler)
422
423 return QuantLib::Schedule(startDate, endDate, tenor, calendar, bdc, bdcEnd, rule, endOfMonth, firstDate, lastDate,
424 data.removeFirstDate(), data.removeLastDate(), endOfMonthConvention);
425}
426
427namespace {
428// helper function used in makeSchedule below
429template <class T>
430void updateData(const std::string& s, T& t, bool& hasT, bool& hasConsistentT, const std::function<T(string)>& parser) {
431 if (s != "") {
432 T tmp = parser(s);
433 if (hasT) {
434 hasConsistentT = hasConsistentT && (tmp == t);
435 } else {
436 t = tmp;
437 hasT = true;
438 }
439 }
440}
441// local wrapper function to get around optional parameter in parseCalendar
442Calendar parseCalendarTemp(const string& s) { return parseCalendar(s); }
443} // namespace
444
445Schedule makeSchedule(const ScheduleData& data, const Date& openEndDateReplacement, const map<string, QuantLib::Schedule>& baseSchedules) {
446 if(!data.hasData())
447 return Schedule();
448 // only the last rule-based schedule is allowed to have an open end date, check this
449 for (Size i = 1; i < data.rules().size(); ++i) {
450 QL_REQUIRE(!data.rules()[i - 1].endDate().empty(),
451 "makeSchedule(): only last schedule is allowed to have an open end date");
452 }
453 // build all the date and rule based sub-schedules we have
454 vector<Schedule> schedules;
455 for (auto& d : data.dates())
456 schedules.push_back(makeSchedule(d));
457 for (auto& r : data.rules())
458 schedules.push_back(makeSchedule(r, openEndDateReplacement));
459 if (!baseSchedules.empty())
460 for (auto& dv : data.derived()) {
461 auto baseSchedule = baseSchedules.find(dv.baseSchedule());
462 QL_REQUIRE(baseSchedule != baseSchedules.end(), "makeSchedule(): could not find base schedule \"" << dv.baseSchedule() << "\"");
463 schedules.push_back(makeSchedule(dv, baseSchedule->second));
464 }
465 QL_REQUIRE(!schedules.empty(), "No dates or rules to build Schedule from");
466 if (schedules.size() == 1)
467 // if we have just one, use that (most common case)
468 return schedules.front();
469 else {
470 // if we have multiple, combine them
471
472 // 1) sort by start date
473 std::sort(schedules.begin(), schedules.end(),
474 [](const Schedule& lhs, const Schedule& rhs) -> bool { return lhs.startDate() < rhs.startDate(); });
475
476 // 2) check if meta data is present, and if yes if it is consistent across schedules;
477 // the only exception is the term date convention, this is taken from the last schedule always
478 BusinessDayConvention convention = Null<BusinessDayConvention>(),
479 termConvention = Unadjusted; // initialization prevents gcc warning
480 Calendar calendar;
481 Period tenor;
482 DateGeneration::Rule rule = DateGeneration::Zero; // initialization prevents gcc warning
483 bool endOfMonth = false; // initialization prevents gcc warning
484 BusinessDayConvention endOfMonthConvention = Null<BusinessDayConvention>();
485 bool hasCalendar = false, hasConvention = false, hasTermConvention = false, hasTenor = false, hasRule = false,
486 hasEndOfMonth = false, hasEndOfMonthConvention = false, hasConsistentCalendar = true,
487 hasConsistentConvention = true, hasConsistentTenor = true, hasConsistentRule = true,
488 hasConsistentEndOfMonth = true, hasConsistentEndOfMonthConvention = true;
489 for (auto& d : data.dates()) {
490 updateData<Calendar>(d.calendar(), calendar, hasCalendar, hasConsistentCalendar, parseCalendarTemp);
491 updateData<BusinessDayConvention>(d.convention(), convention, hasConvention, hasConsistentConvention,
493 updateData<Period>(d.tenor(), tenor, hasTenor, hasConsistentTenor, parsePeriod);
494 }
495 for (auto& d : data.rules()) {
496 updateData<Calendar>(d.calendar(), calendar, hasCalendar, hasConsistentCalendar, parseCalendarTemp);
497 updateData<BusinessDayConvention>(d.convention(), convention, hasConvention, hasConsistentConvention,
499 updateData<Period>(d.tenor(), tenor, hasTenor, hasConsistentTenor, parsePeriod);
500 updateData<bool>(d.endOfMonth(), endOfMonth, hasEndOfMonth, hasConsistentEndOfMonth, parseBool);
501 updateData<BusinessDayConvention>(d.endOfMonthConvention(), endOfMonthConvention, hasEndOfMonthConvention,
502 hasConsistentEndOfMonthConvention, parseBusinessDayConvention);
503 updateData<DateGeneration::Rule>(d.rule(), rule, hasRule, hasConsistentRule, parseDateGenerationRule);
504 if (d.termConvention() != "") {
505 hasTermConvention = true;
506 termConvention = parseBusinessDayConvention(d.termConvention());
507 }
508 }
509
510 // 3) combine dates and fill isRegular flag
511 const Schedule& s0 = schedules.front();
512 vector<Date> dates = s0.dates();
513 std::vector<bool> isRegular(s0.dates().size() - 1, false);
514 if (s0.hasIsRegular())
515 isRegular = s0.isRegular();
516 // will be removed, if next schedule's front date is matching the last date of current schedule
517 isRegular.push_back(false);
518 for (Size i = 1; i < schedules.size(); ++i) {
519 const Schedule& s = schedules[i];
520 QL_REQUIRE(dates.back() <= s.dates().front(), "Dates mismatch");
521 // if the end points match up, skip one to avoid duplicates, otherwise take both
522 Size offset = dates.back() == s.dates().front() ? 1 : 0;
523 isRegular.erase(isRegular.end() - offset,
524 isRegular.end()); // correct for superfluous flags from previous schedule
525 // add isRegular information, if available, otherwise assume irregular periods
526 if (s.hasIsRegular()) {
527 isRegular.insert(isRegular.end(), s.isRegular().begin(), s.isRegular().end());
528 } else {
529 for (Size ii = 0; ii < s.dates().size() - 1; ++ii)
530 isRegular.push_back(false);
531 }
532 if (i < schedules.size() - 1) {
533 // will be removed if next schedule's front date is matching last date of current schedule
534 isRegular.push_back(false);
535 }
536 // add the dates
537 dates.insert(dates.end(), s.dates().begin() + offset, s.dates().end());
538 }
539
540 // 4) Build schedule
541 return QuantLib::Schedule(
542 dates, hasCalendar && hasConsistentCalendar ? calendar : NullCalendar(),
543 hasConvention && hasConsistentConvention ? convention : Unadjusted,
544 hasTermConvention ? ext::optional<BusinessDayConvention>(termConvention) : boost::none,
545 hasTenor && hasConsistentTenor ? ext::optional<Period>(tenor) : boost::none,
546 hasRule && hasConsistentRule ? ext::optional<DateGeneration::Rule>(rule) : boost::none,
547 hasEndOfMonth && hasConsistentEndOfMonth ? ext::optional<bool>(endOfMonth) : boost::none, isRegular,
548 false, false,
549 hasEndOfMonthConvention && hasConsistentEndOfMonthConvention
550 ? ext::optional<BusinessDayConvention>(endOfMonthConvention)
551 : boost::none);
552 }
553}
554} // namespace data
555} // namespace ore
void makeSchedules(const QuantLib::Date &openEndDateReplacement=QuantLib::Null< QuantLib::Date >())
Definition: schedule.cpp:214
map< string, pair< ScheduleData, QuantLib::Schedule & > > schedules_
Definition: schedule.hpp:274
void add(QuantLib::Schedule &schedule, const ScheduleData &scheduleData)
Definition: schedule.cpp:209
Serializable schedule data.
Definition: schedule.hpp:202
vector< ScheduleDates > dates_
Definition: schedule.hpp:248
vector< ScheduleDerived > derived_
Definition: schedule.hpp:250
vector< string > baseScheduleNames()
Definition: schedule.cpp:172
virtual void fromXML(XMLNode *node) override
Definition: schedule.cpp:179
vector< ScheduleRules > rules_
Definition: schedule.hpp:249
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: schedule.cpp:198
const bool & hasDerived() const
Definition: schedule.hpp:232
Serializable object holding schedule Dates data.
Definition: schedule.hpp:110
vector< string > dates_
Definition: schedule.hpp:149
virtual void fromXML(XMLNode *node) override
Definition: schedule.cpp:124
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: schedule.cpp:134
Serializable object holding Derived schedule data.
Definition: schedule.hpp:157
virtual void fromXML(XMLNode *node) override
Definition: schedule.cpp:146
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: schedule.cpp:156
Serializable object holding schedule Rules data.
Definition: schedule.hpp:37
virtual void fromXML(XMLNode *node) override
Definition: schedule.cpp:75
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: schedule.cpp:102
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
static void addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
Definition: xmlutils.cpp:502
static void checkNode(XMLNode *n, const string &expectedName)
Definition: xmlutils.cpp:175
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
static string getNodeName(XMLNode *n)
Get and set a node's name.
Definition: xmlutils.cpp:473
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
Definition: xmlutils.cpp:277
static bool getChildValueAsBool(XMLNode *node, const string &name, bool mandatory=false, bool defaultValue=true)
Definition: xmlutils.cpp:296
static vector< string > getChildrenValues(XMLNode *node, const string &names, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:306
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
Definition: xmlutils.cpp:181
static void appendNode(XMLNode *parent, XMLNode *child)
Definition: xmlutils.cpp:406
DateGeneration::Rule parseDateGenerationRule(const string &s)
Convert text to QuantLib::DateGeneration::Rule.
Definition: parsers.cpp:328
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Definition: parsers.cpp:173
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
bool parseBool(const string &s)
Convert text to bool.
Definition: parsers.cpp:144
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define ALOG(text)
Logging Macro (Level = Alert)
Definition: log.hpp:544
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
Calendar calendar
Definition: utilities.cpp:441
Size size(const ValueType &v)
Definition: value.cpp:145
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Schedule makeSchedule(const ScheduleDates &data)
Definition: schedule.cpp:263
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
trade schedule data model and serialization
string conversion utilities
string name