Skip to content

Commit

Permalink
CDS schedule generation changes and tests for issue lballabio#727.
Browse files Browse the repository at this point in the history
The main addition is a function cdsMaturity(...) that can be used to
derive a CDS maturity date given a trade date, a valid CDS tenor and a
valid CDS date generation rule. The date generation is tested against
the dates provided in the ISDA documentation for CDS2015. It is also
tested for CDS and OldCDS. The logic for the 0M tenor is added for the
CDS and CDS2015 rules.
  • Loading branch information
francis committed Nov 16, 2020
1 parent a2fb7df commit 72c6064
Show file tree
Hide file tree
Showing 4 changed files with 573 additions and 47 deletions.
44 changes: 31 additions & 13 deletions ql/time/schedule.cpp
Expand Up @@ -315,11 +315,6 @@ namespace QuantLib {
exitDate = terminationDate;
if (nextToLastDate_ != Date())
exitDate = nextToLastDate_;
if(*rule_ == DateGeneration::CDS2015
&& nextTwentieth(terminationDate, *rule_) == terminationDate
&& terminationDate.month() %2 == 1) {
exitDate = nextTwentieth(terminationDate+1, *rule_);
}
for (;;) {
Date temp = nullCalendar.advance(seed, periods*(*tenor_),
convention, *endOfMonth_);
Expand Down Expand Up @@ -348,16 +343,10 @@ namespace QuantLib {
if (*rule_ == DateGeneration::Twentieth ||
*rule_ == DateGeneration::TwentiethIMM ||
*rule_ == DateGeneration::OldCDS ||
*rule_ == DateGeneration::CDS) {
*rule_ == DateGeneration::CDS ||
*rule_ == DateGeneration::CDS2015) {
dates_.push_back(nextTwentieth(terminationDate, *rule_));
isRegular_.push_back(true);
} else if(*rule_ == DateGeneration::CDS2015) {
Date tentativeTerminationDate =
nextTwentieth(terminationDate, *rule_);
if(tentativeTerminationDate.month() %2 == 0) {
dates_.push_back(tentativeTerminationDate);
isRegular_.push_back(true);
}
} else {
dates_.push_back(terminationDate);
isRegular_.push_back(false);
Expand Down Expand Up @@ -676,4 +665,33 @@ namespace QuantLib {
rule_, endOfMonth_, firstDate_, nextToLastDate_);
}

Date cdsMaturity(const Date& tradeDate, const Period& tenor, DateGeneration::Rule rule) {

QL_REQUIRE(rule == DateGeneration::CDS2015 || rule == DateGeneration::CDS || rule == DateGeneration::OldCDS,
"cdsMaturity should only be used with date generation rule CDS2015, CDS or OldCDS");

QL_REQUIRE(tenor.units() == Years || (tenor.units() == Months && tenor.length() % 3 == 0),
"cdsMaturity expects a tenor that is a multiple of 3 months.");

if (rule == DateGeneration::OldCDS) {
QL_REQUIRE(tenor != 0 * Months, "A tenor of 0M is not supported for OldCDS.");
}

Date anchorDate = previousTwentieth(tradeDate, rule);
if (rule == DateGeneration::CDS2015 && (anchorDate == Date(20, Dec, anchorDate.year()) ||
anchorDate == Date(20, Jun, anchorDate.year()))) {
if (tenor.length() == 0) {
return Null<Date>();
} else {
anchorDate -= 3 * Months;
}
}

Date maturity = anchorDate + tenor + 3 * Months;
QL_REQUIRE(maturity > tradeDate, "error calculating CDS maturity. Tenor is " << tenor << ", trade date is " <<
io::iso_date(tradeDate) << " generating a maturity of " << io::iso_date(maturity) << " <= trade date.");

return maturity;
}

}
14 changes: 14 additions & 0 deletions ql/time/schedule.hpp
Expand Up @@ -28,6 +28,7 @@

#include <ql/time/calendars/nullcalendar.hpp>
#include <ql/utilities/null.hpp>
#include <ql/time/calendars/weekendsonly.hpp>
#include <ql/time/period.hpp>
#include <ql/time/dategenerationrule.hpp>
#include <ql/errors.hpp>
Expand Down Expand Up @@ -151,7 +152,20 @@ namespace QuantLib {
Date firstDate_, nextToLastDate_;
};

/*! Return the CDS maturity date given the CDS trade date, \p tradeDate, the CDS \p tenor and a CDS \p rule.
A \c Null<Date>() is returned when a \p rule of \c CDS2015 and a \p tenor length of zero fail to yield a valid
CDS maturity date.
\warning An exception will be thrown if the \p rule is not \c CDS2015, \c CDS or \c OldCDS.
\warning An exception will be thrown if the \p rule is \c OldCDS and a \p tenor of 0 months is provided. This
restriction can be removed if 0M tenor was available before the CDS Big Bang 2009.
\warning An exception will be thrown if the \p tenor is not a multiple of 3 months. For the avoidance of
doubt, a \p tenor of 0 months is supported.
*/
Date cdsMaturity(const Date& tradeDate, const Period& tenor, DateGeneration::Rule rule);

// inline definitions

Expand Down

0 comments on commit 72c6064

Please sign in to comment.