QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
schedule.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2006, 2007, 2008, 2010, 2011, 2015 Ferdinando Ametrano
5 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
6 Copyright (C) 2009, 2012 StatPro Italia srl
7
8 This file is part of QuantLib, a free-software/open-source library
9 for financial quantitative analysts and developers - http://quantlib.org/
10
11 QuantLib is free software: you can redistribute it and/or modify it
12 under the terms of the QuantLib license. You should have received a
13 copy of the license along with this program; if not, please email
14 <quantlib-dev@lists.sf.net>. The license is also available online at
15 <http://quantlib.org/license.shtml>.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the license for more details.
20*/
21
22#include <ql/optional.hpp>
23#include <ql/settings.hpp>
24#include <ql/time/imm.hpp>
25#include <ql/time/schedule.hpp>
26#include <utility>
27
28namespace QuantLib {
29
30 namespace {
31
32 Date nextTwentieth(const Date& d, DateGeneration::Rule rule) {
33 Date result = Date(20, d.month(), d.year());
34 if (result < d)
35 result += 1*Months;
36 if (rule == DateGeneration::TwentiethIMM ||
37 rule == DateGeneration::OldCDS ||
38 rule == DateGeneration::CDS ||
40 Month m = result.month();
41 if (m % 3 != 0) { // not a main IMM nmonth
42 Integer skip = 3 - m%3;
43 result += skip*Months;
44 }
45 }
46 return result;
47 }
48
49 bool allowsEndOfMonth(const Period& tenor) {
50 return (tenor.units() == Months || tenor.units() == Years)
51 && tenor >= 1*Months;
52 }
53
54 }
55
56
57 Schedule::Schedule(const std::vector<Date>& dates,
58 Calendar calendar,
59 BusinessDayConvention convention,
60 const ext::optional<BusinessDayConvention>& terminationDateConvention,
61 const ext::optional<Period>& tenor,
62 const ext::optional<DateGeneration::Rule>& rule,
63 const ext::optional<bool>& endOfMonth,
64 std::vector<bool> isRegular)
65 : tenor_(tenor), calendar_(std::move(calendar)), convention_(convention),
66 terminationDateConvention_(terminationDateConvention), rule_(rule), dates_(dates),
67 isRegular_(std::move(isRegular)) {
68
69 if (tenor && !allowsEndOfMonth(*tenor))
70 endOfMonth_ = false;
71 else
73
74 QL_REQUIRE(isRegular_.empty() || isRegular_.size() == dates.size() - 1,
75 "isRegular size (" << isRegular_.size()
76 << ") must be zero or equal to the number of dates minus 1 ("
77 << dates.size() - 1 << ")");
78 }
79
80 Schedule::Schedule(Date effectiveDate,
81 const Date& terminationDate,
82 const Period& tenor,
83 Calendar cal,
84 BusinessDayConvention convention,
85 BusinessDayConvention terminationDateConvention,
87 bool endOfMonth,
88 const Date& first,
89 const Date& nextToLast)
90 : tenor_(tenor), calendar_(std::move(cal)), convention_(convention),
91 terminationDateConvention_(terminationDateConvention), rule_(rule),
92 endOfMonth_(allowsEndOfMonth(tenor) ? endOfMonth : false),
93 firstDate_(first == effectiveDate ? Date() : first),
94 nextToLastDate_(nextToLast == terminationDate ? Date() : nextToLast) {
95 // sanity checks
96 QL_REQUIRE(terminationDate != Date(), "null termination date");
97
98 // in many cases (e.g. non-expired bonds) the effective date is not
99 // really necessary. In these cases a decent placeholder is enough
100 if (effectiveDate==Date() && first==Date()
103 QL_REQUIRE(evalDate < terminationDate, "null effective date");
104 Natural y;
105 if (nextToLast != Date()) {
106 y = (nextToLast - evalDate)/366 + 1;
107 effectiveDate = nextToLast - y*Years;
108 } else {
109 y = (terminationDate - evalDate)/366 + 1;
110 effectiveDate = terminationDate - y*Years;
111 }
112 } else
113 QL_REQUIRE(effectiveDate != Date(), "null effective date");
114
115 QL_REQUIRE(effectiveDate < terminationDate,
116 "effective date (" << effectiveDate
117 << ") later than or equal to termination date ("
118 << terminationDate << ")");
119
120 if (tenor.length()==0)
122 else
123 QL_REQUIRE(tenor.length()>0,
124 "non positive tenor (" << tenor << ") not allowed");
125
126 if (firstDate_ != Date()) {
127 switch (*rule_) {
130 QL_REQUIRE(firstDate_ > effectiveDate &&
131 firstDate_ <= terminationDate,
132 "first date (" << firstDate_ <<
133 ") out of effective-termination date range (" <<
134 effectiveDate << ", " << terminationDate << "]");
135 // we should ensure that the above condition is still
136 // verified after adjustment
137 break;
139 QL_REQUIRE(IMM::isIMMdate(firstDate_, false),
140 "first date (" << firstDate_ <<
141 ") is not an IMM date");
142 break;
149 QL_FAIL("first date incompatible with " << *rule_ <<
150 " date generation rule");
151 default:
152 QL_FAIL("unknown rule (" << Integer(*rule_) << ")");
153 }
154 }
155 if (nextToLastDate_ != Date()) {
156 switch (*rule_) {
159 QL_REQUIRE(nextToLastDate_ >= effectiveDate &&
160 nextToLastDate_ < terminationDate,
161 "next to last date (" << nextToLastDate_ <<
162 ") out of effective-termination date range [" <<
163 effectiveDate << ", " << terminationDate << ")");
164 // we should ensure that the above condition is still
165 // verified after adjustment
166 break;
168 QL_REQUIRE(IMM::isIMMdate(nextToLastDate_, false),
169 "next-to-last date (" << nextToLastDate_ <<
170 ") is not an IMM date");
171 break;
178 QL_FAIL("next to last date incompatible with " << *rule_ <<
179 " date generation rule");
180 default:
181 QL_FAIL("unknown rule (" << Integer(*rule_) << ")");
182 }
183 }
184
185
186 // calendar needed for endOfMonth adjustment
187 Calendar nullCalendar = NullCalendar();
188 Integer periods = 1;
189 Date seed, exitDate;
190 switch (*rule_) {
191
193 tenor_ = 0*Years;
194 dates_.push_back(effectiveDate);
195 dates_.push_back(terminationDate);
196 isRegular_.push_back(true);
197 break;
198
200
201 dates_.push_back(terminationDate);
202
203 seed = terminationDate;
204 if (nextToLastDate_ != Date()) {
205 dates_.insert(dates_.begin(), nextToLastDate_);
206 Date temp = nullCalendar.advance(seed,
207 -periods*(*tenor_), convention, *endOfMonth_);
208 if (temp!=nextToLastDate_)
209 isRegular_.insert(isRegular_.begin(), false);
210 else
211 isRegular_.insert(isRegular_.begin(), true);
212 seed = nextToLastDate_;
213 }
214
215 exitDate = effectiveDate;
216 if (firstDate_ != Date())
217 exitDate = firstDate_;
218
219 for (;;) {
220 Date temp = nullCalendar.advance(seed,
221 -periods*(*tenor_), convention, *endOfMonth_);
222 if (temp < exitDate) {
223 if (firstDate_ != Date() &&
224 (calendar_.adjust(dates_.front(),convention)!=
225 calendar_.adjust(firstDate_,convention))) {
226 dates_.insert(dates_.begin(), firstDate_);
227 isRegular_.insert(isRegular_.begin(), false);
228 }
229 break;
230 } else {
231 // skip dates that would result in duplicates
232 // after adjustment
233 if (calendar_.adjust(dates_.front(),convention)!=
234 calendar_.adjust(temp,convention)) {
235 dates_.insert(dates_.begin(), temp);
236 isRegular_.insert(isRegular_.begin(), true);
237 }
238 ++periods;
239 }
240 }
241
242 if (calendar_.adjust(dates_.front(),convention)!=
243 calendar_.adjust(effectiveDate,convention)) {
244 dates_.insert(dates_.begin(), effectiveDate);
245 isRegular_.insert(isRegular_.begin(), false);
246 }
247 break;
248
256 QL_REQUIRE(!*endOfMonth_,
257 "endOfMonth convention incompatible with " << *rule_ <<
258 " date generation rule");
259 // fall through
261
263 Date prev20th = previousTwentieth(effectiveDate, *rule_);
264 if (calendar_.adjust(prev20th, convention) > effectiveDate) {
265 dates_.push_back(prev20th - 3 * Months);
266 isRegular_.push_back(true);
267 }
268 dates_.push_back(prev20th);
269 } else {
270 dates_.push_back(effectiveDate);
271 }
272
273 seed = dates_.back();
274
275 if (firstDate_!=Date()) {
276 dates_.push_back(firstDate_);
277 Date temp = nullCalendar.advance(seed, periods*(*tenor_),
278 convention, *endOfMonth_);
279 if (temp!=firstDate_)
280 isRegular_.push_back(false);
281 else
282 isRegular_.push_back(true);
283 seed = firstDate_;
284 } else if (*rule_ == DateGeneration::Twentieth ||
289 Date next20th = nextTwentieth(effectiveDate, *rule_);
291 // distance rule inforced in natural days
292 static const Date::serial_type stubDays = 30;
293 if (next20th - effectiveDate < stubDays) {
294 // +1 will skip this one and get the next
295 next20th = nextTwentieth(next20th + 1, *rule_);
296 }
297 }
298 if (next20th != effectiveDate) {
299 dates_.push_back(next20th);
301 seed = next20th;
302 }
303 }
304
305 exitDate = terminationDate;
306 if (nextToLastDate_ != Date())
307 exitDate = nextToLastDate_;
308 for (;;) {
309 Date temp = nullCalendar.advance(seed, periods*(*tenor_),
310 convention, *endOfMonth_);
311 if (temp > exitDate) {
312 if (nextToLastDate_ != Date() &&
313 (calendar_.adjust(dates_.back(),convention)!=
314 calendar_.adjust(nextToLastDate_,convention))) {
315 dates_.push_back(nextToLastDate_);
316 isRegular_.push_back(false);
317 }
318 break;
319 } else {
320 // skip dates that would result in duplicates
321 // after adjustment
322 if (calendar_.adjust(dates_.back(),convention)!=
323 calendar_.adjust(temp,convention)) {
324 dates_.push_back(temp);
325 isRegular_.push_back(true);
326 }
327 ++periods;
328 }
329 }
330
331 if (calendar_.adjust(dates_.back(),terminationDateConvention)!=
332 calendar_.adjust(terminationDate,terminationDateConvention)) {
338 dates_.push_back(nextTwentieth(terminationDate, *rule_));
339 isRegular_.push_back(true);
340 } else {
341 dates_.push_back(terminationDate);
342 isRegular_.push_back(false);
343 }
344 }
345
346 break;
347
348 default:
349 QL_FAIL("unknown rule (" << Integer(*rule_) << ")");
350 }
351
352 // adjustments
354 for (Size i=1; i<dates_.size()-1; ++i)
356 dates_[i].month(),
357 dates_[i].year());
359 for (auto& date : dates_)
361
362 // first date not adjusted for old CDS schedules
363 if (convention != Unadjusted && *rule_ != DateGeneration::OldCDS)
364 dates_.front() = calendar_.adjust(dates_.front(), convention);
365
366 // termination date is NOT adjusted as per ISDA
367 // specifications, unless otherwise specified in the
368 // confirmation of the deal or unless we're creating a CDS
369 // schedule
370 if (terminationDateConvention != Unadjusted
373 dates_.back() = calendar_.adjust(dates_.back(),
374 terminationDateConvention);
375 }
376
377 if (*endOfMonth_ && calendar_.isEndOfMonth(seed)) {
378 // adjust to end of month
379 if (convention == Unadjusted) {
380 for (Size i=1; i<dates_.size()-1; ++i)
382 } else {
383 for (Size i=1; i<dates_.size()-1; ++i)
385 }
386 } else {
387 for (Size i=1; i<dates_.size()-1; ++i)
388 dates_[i] = calendar_.adjust(dates_[i], convention);
389 }
390
391 // Final safety checks to remove extra next-to-last date, if
392 // necessary. It can happen to be equal or later than the end
393 // date due to EOM adjustments (see the Schedule test suite
394 // for an example).
395 if (dates_.size() >= 2 && dates_[dates_.size()-2] >= dates_.back()) {
396 // there might be two dates only, then isRegular_ has size one
397 if (isRegular_.size() >= 2) {
398 isRegular_[isRegular_.size() - 2] =
399 (dates_[dates_.size() - 2] == dates_.back());
400 }
401 dates_[dates_.size() - 2] = dates_.back();
402 dates_.pop_back();
403 isRegular_.pop_back();
404 }
405 if (dates_.size() >= 2 && dates_[1] <= dates_.front()) {
406 isRegular_[1] =
407 (dates_[1] == dates_.front());
408 dates_[1] = dates_.front();
409 dates_.erase(dates_.begin());
410 isRegular_.erase(isRegular_.begin());
411 }
412
413 QL_ENSURE(dates_.size()>1,
414 "degenerate single date (" << dates_[0] << ") schedule" <<
415 "\n seed date: " << seed <<
416 "\n exit date: " << exitDate <<
417 "\n effective date: " << effectiveDate <<
418 "\n first date: " << first <<
419 "\n next to last date: " << nextToLast <<
420 "\n termination date: " << terminationDate <<
421 "\n generation rule: " << *rule_ <<
422 "\n end of month: " << *endOfMonth_);
423 }
424
425 Schedule Schedule::after(const Date& truncationDate) const {
426 Schedule result = *this;
427
428 QL_REQUIRE(truncationDate < result.dates_.back(),
429 "truncation date " << truncationDate <<
430 " must be before the last schedule date " <<
431 result.dates_.back());
432 if (truncationDate > result.dates_[0]) {
433 // remove earlier dates
434 while (result.dates_[0] < truncationDate) {
435 result.dates_.erase(result.dates_.begin());
436 if (!result.isRegular_.empty())
437 result.isRegular_.erase(result.isRegular_.begin());
438 }
439
440 // add truncationDate if missing
441 if (truncationDate != result.dates_.front()) {
442 result.dates_.insert(result.dates_.begin(), truncationDate);
443 result.isRegular_.insert(result.isRegular_.begin(), false);
445 }
446 else {
448 }
449
450 if (result.nextToLastDate_ <= truncationDate)
451 result.nextToLastDate_ = Date();
452 if (result.firstDate_ <= truncationDate)
453 result.firstDate_ = Date();
454 }
455
456 return result;
457 }
458
459 Schedule Schedule::until(const Date& truncationDate) const {
460 Schedule result = *this;
461
462 QL_REQUIRE(truncationDate>result.dates_[0],
463 "truncation date " << truncationDate <<
464 " must be later than schedule first date " <<
465 result.dates_[0]);
466 if (truncationDate<result.dates_.back()) {
467 // remove later dates
468 while (result.dates_.back()>truncationDate) {
469 result.dates_.pop_back();
470 if(!result.isRegular_.empty())
471 result.isRegular_.pop_back();
472 }
473
474 // add truncationDate if missing
475 if (truncationDate!=result.dates_.back()) {
476 result.dates_.push_back(truncationDate);
477 result.isRegular_.push_back(false);
479 } else {
481 }
482
483 if (result.nextToLastDate_>=truncationDate)
484 result.nextToLastDate_ = Date();
485 if (result.firstDate_>=truncationDate)
486 result.firstDate_ = Date();
487 }
488
489 return result;
490 }
491
492 std::vector<Date>::const_iterator
493 Schedule::lower_bound(const Date& refDate) const {
494 Date d = (refDate==Date() ?
496 refDate);
497 return std::lower_bound(dates_.begin(), dates_.end(), d);
498 }
499
500 Date Schedule::nextDate(const Date& refDate) const {
501 auto res = lower_bound(refDate);
502 if (res!=dates_.end())
503 return *res;
504 else
505 return {};
506 }
507
508 Date Schedule::previousDate(const Date& refDate) const {
509 auto res = lower_bound(refDate);
510 if (res!=dates_.begin())
511 return *(--res);
512 else
513 return {};
514 }
515
516 bool Schedule::hasIsRegular() const { return !isRegular_.empty(); }
517
518 bool Schedule::isRegular(Size i) const {
519 QL_REQUIRE(hasIsRegular(),
520 "full interface (isRegular) not available");
521 QL_REQUIRE(i<=isRegular_.size() && i>0,
522 "index (" << i << ") must be in [1, " <<
523 isRegular_.size() <<"]");
524 return isRegular_[i-1];
525 }
526
527 const std::vector<bool>& Schedule::isRegular() const {
528 QL_REQUIRE(!isRegular_.empty(), "full interface (isRegular) not available");
529 return isRegular_;
530 }
531
532 MakeSchedule& MakeSchedule::from(const Date& effectiveDate) {
533 effectiveDate_ = effectiveDate;
534 return *this;
535 }
536
537 MakeSchedule& MakeSchedule::to(const Date& terminationDate) {
538 terminationDate_ = terminationDate;
539 return *this;
540 }
541
543 tenor_ = tenor;
544 return *this;
545 }
546
548 tenor_ = Period(frequency);
549 return *this;
550 }
551
553 calendar_ = calendar;
554 return *this;
555 }
556
558 convention_ = conv;
559 return *this;
560 }
561
565 return *this;
566 }
567
569 rule_ = r;
570 return *this;
571 }
572
575 return *this;
576 }
577
580 return *this;
581 }
582
584 endOfMonth_ = flag;
585 return *this;
586 }
587
589 firstDate_ = d;
590 return *this;
591 }
592
594 nextToLastDate_ = d;
595 return *this;
596 }
597
598 MakeSchedule::operator Schedule() const {
599 // check for mandatory arguments
600 QL_REQUIRE(effectiveDate_ != Date(), "effective date not provided");
601 QL_REQUIRE(terminationDate_ != Date(), "termination date not provided");
602 QL_REQUIRE(tenor_, "tenor/frequency not provided");
603
604 // set dynamic defaults:
605 BusinessDayConvention convention;
606 // if a convention was set, we use it.
607 if (convention_) { // NOLINT(readability-implicit-bool-conversion)
608 convention = *convention_;
609 } else {
610 if (!calendar_.empty()) {
611 // ...if we set a calendar, we probably want it to be used;
612 convention = Following;
613 } else {
614 // if not, we don't care.
615 convention = Unadjusted;
616 }
617 }
618
619 BusinessDayConvention terminationDateConvention;
620 // if set explicitly, we use it;
621 if (terminationDateConvention_) { // NOLINT(readability-implicit-bool-conversion)
622 terminationDateConvention = *terminationDateConvention_;
623 } else {
624 // Unadjusted as per ISDA specification
625 terminationDateConvention = convention;
626 }
627
628 Calendar calendar = calendar_;
629 // if no calendar was set...
630 if (calendar.empty()) {
631 // ...we use a null one.
632 calendar = NullCalendar();
633 }
634
635 return Schedule(effectiveDate_, terminationDate_, *tenor_, calendar,
636 convention, terminationDateConvention,
637 rule_, endOfMonth_, firstDate_, nextToLastDate_);
638 }
639
641 Date result = Date(20, d.month(), d.year());
642 if (result > d)
643 result -= 1 * Months;
644 if (rule == DateGeneration::TwentiethIMM ||
645 rule == DateGeneration::OldCDS ||
646 rule == DateGeneration::CDS ||
647 rule == DateGeneration::CDS2015) {
648 Month m = result.month();
649 if (m % 3 != 0) { // not a main IMM nmonth
650 Integer skip = m % 3;
651 result -= skip * Months;
652 }
653 }
654 return result;
655 }
656
657}
calendar class
Definition: calendar.hpp:61
bool isEndOfMonth(const Date &d) const
Definition: calendar.hpp:243
bool empty() const
Returns whether or not the calendar is initialized.
Definition: calendar.hpp:202
Date adjust(const Date &, BusinessDayConvention convention=Following) const
Definition: calendar.cpp:84
Date advance(const Date &, Integer n, TimeUnit unit, BusinessDayConvention convention=Following, bool endOfMonth=false) const
Definition: calendar.cpp:130
Date endOfMonth(const Date &d) const
last business day of the month to which the given date belongs
Definition: calendar.hpp:247
Concrete date class.
Definition: date.hpp:125
Month month() const
Definition: date.cpp:82
Year year() const
Definition: date.cpp:93
static Date endOfMonth(const Date &d)
last day of the month to which the given date belongs
Definition: date.hpp:428
std::int_fast32_t serial_type
serial number type
Definition: date.hpp:128
static Date nthWeekday(Size n, Weekday w, Month m, Year y)
n-th given weekday in the given month and year
Definition: date.cpp:802
MakeSchedule & withConvention(BusinessDayConvention)
Definition: schedule.cpp:557
ext::optional< BusinessDayConvention > convention_
Definition: schedule.hpp:146
MakeSchedule & withTerminationDateConvention(BusinessDayConvention)
Definition: schedule.cpp:562
ext::optional< Period > tenor_
Definition: schedule.hpp:145
ext::optional< BusinessDayConvention > terminationDateConvention_
Definition: schedule.hpp:147
MakeSchedule & withRule(DateGeneration::Rule)
Definition: schedule.cpp:568
MakeSchedule & backwards()
Definition: schedule.cpp:578
MakeSchedule & to(const Date &terminationDate)
Definition: schedule.cpp:537
MakeSchedule & withTenor(const Period &)
Definition: schedule.cpp:542
DateGeneration::Rule rule_
Definition: schedule.hpp:148
MakeSchedule & withFirstDate(const Date &d)
Definition: schedule.cpp:588
MakeSchedule & from(const Date &effectiveDate)
Definition: schedule.cpp:532
MakeSchedule & endOfMonth(bool flag=true)
Definition: schedule.cpp:583
MakeSchedule & withFrequency(Frequency)
Definition: schedule.cpp:547
MakeSchedule & forwards()
Definition: schedule.cpp:573
MakeSchedule & withNextToLastDate(const Date &d)
Definition: schedule.cpp:593
MakeSchedule & withCalendar(const Calendar &)
Definition: schedule.cpp:552
Calendar for reproducing theoretical calculations.
Integer length() const
Definition: period.hpp:50
Payment schedule.
Definition: schedule.hpp:40
Calendar calendar_
Definition: schedule.hpp:111
Date nextDate(const Date &refDate) const
Definition: schedule.cpp:500
ext::optional< Period > tenor_
Definition: schedule.hpp:110
ext::optional< BusinessDayConvention > terminationDateConvention_
Definition: schedule.hpp:113
std::vector< Date > dates_
Definition: schedule.hpp:117
const std::vector< Date > & dates() const
Definition: schedule.hpp:75
std::vector< bool > isRegular_
Definition: schedule.hpp:118
Date previousDate(const Date &refDate) const
Definition: schedule.cpp:508
bool endOfMonth() const
Definition: schedule.hpp:225
BusinessDayConvention convention_
Definition: schedule.hpp:112
ext::optional< bool > endOfMonth_
Definition: schedule.hpp:115
ext::optional< DateGeneration::Rule > rule_
Definition: schedule.hpp:114
Schedule after(const Date &truncationDate) const
truncated schedule
Definition: schedule.cpp:425
DateGeneration::Rule rule() const
Definition: schedule.hpp:216
const_iterator lower_bound(const Date &d=Date()) const
Definition: schedule.cpp:493
const std::vector< bool > & isRegular() const
Definition: schedule.cpp:527
const Date & date(Size i) const
Definition: schedule.hpp:160
bool hasIsRegular() const
Definition: schedule.cpp:516
Schedule until(const Date &truncationDate) const
Definition: schedule.cpp:459
const Period & tenor() const
Definition: schedule.hpp:190
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
Frequency
Frequency of events.
Definition: frequency.hpp:37
Month
Month names.
Definition: date.hpp:57
BusinessDayConvention
Business Day conventions.
@ Wednesday
Definition: weekday.hpp:44
unsigned QL_INTEGER Natural
positive integer
Definition: types.hpp:43
QL_INTEGER Integer
integer number
Definition: types.hpp:35
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
Date previousTwentieth(const Date &d, DateGeneration::Rule rule)
Definition: schedule.cpp:640
STL namespace.
static bool isIMMdate(const Date &d, bool mainCycle=true)
returns whether or not the given date is an IMM date
Definition: imm.cpp:34