Skip to content

Commit

Permalink
Merge branch 'QPR-12492_nathaniel' into 'master'
Browse files Browse the repository at this point in the history
QPR-12492 -- Add EOM convention

Closes QPR-12492

See merge request qs/quantlib!70
  • Loading branch information
pcaspers committed May 24, 2024
2 parents cc52fb7 + a30de00 commit 4afd269
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 23 deletions.
10 changes: 6 additions & 4 deletions ql/time/calendar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ namespace QuantLib {
Date Calendar::advance(const Date& d,
Integer n, TimeUnit unit,
BusinessDayConvention c,
bool endOfMonth) const {
bool endOfMonth,
const ext::optional<BusinessDayConvention>& eomConvention) const {
QL_REQUIRE(d!=Date(), "null date");
if (n == 0) {
return adjust(d,c);
Expand Down Expand Up @@ -160,7 +161,7 @@ namespace QuantLib {

// we are sure the unit is Months or Years
if (endOfMonth && isEndOfMonth(d))
return Calendar::endOfMonth(d1);
return Calendar::endOfMonth(d1, eomConvention);

return adjust(d1, c);
}
Expand All @@ -169,8 +170,9 @@ namespace QuantLib {
Date Calendar::advance(const Date & d,
const Period & p,
BusinessDayConvention c,
bool endOfMonth) const {
return advance(d, p.length(), p.units(), c, endOfMonth);
bool endOfMonth,
const ext::optional<BusinessDayConvention>& eomConvention) const {
return advance(d, p.length(), p.units(), c, endOfMonth, eomConvention);
}

Date::serial_type Calendar::businessDaysBetween(const Date& from,
Expand Down
13 changes: 8 additions & 5 deletions ql/time/calendar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#define quantlib_calendar_hpp

#include <ql/errors.hpp>
#include <ql/optional.hpp>
#include <ql/time/date.hpp>
#include <ql/time/businessdayconvention.hpp>
#include <ql/shared_ptr.hpp>
Expand Down Expand Up @@ -113,7 +114,7 @@ namespace QuantLib {
*/
bool isEndOfMonth(const Date& d) const;
//! last business day of the month to which the given date belongs
Date endOfMonth(const Date& d) const;
Date endOfMonth(const Date& d, const ext::optional<BusinessDayConvention>& c) const;

/*! Adds a date to the set of holidays for the given calendar. */
void addHoliday(const Date&);
Expand Down Expand Up @@ -141,15 +142,17 @@ namespace QuantLib {
Integer n,
TimeUnit unit,
BusinessDayConvention convention = Following,
bool endOfMonth = false) const;
bool endOfMonth = false,
const ext::optional<BusinessDayConvention>& eomConvention = ext::nullopt) const;
/*! Advances the given date as specified by the given period and
returns the result.
\note The input date is not modified.
*/
Date advance(const Date& date,
const Period& period,
BusinessDayConvention convention = Following,
bool endOfMonth = false) const;
bool endOfMonth = false,
const ext::optional<BusinessDayConvention>& eomConvention = ext::nullopt) const;
/*! Calculates the number of business days between two given
dates and returns the result.
*/
Expand Down Expand Up @@ -244,8 +247,8 @@ namespace QuantLib {
return (d.month() != adjust(d+1).month());
}

inline Date Calendar::endOfMonth(const Date& d) const {
return adjust(Date::endOfMonth(d), Preceding);
inline Date Calendar::endOfMonth(const Date& d, const ext::optional<BusinessDayConvention>& c = ext::nullopt) const {
return adjust(Date::endOfMonth(d), c ? *c : Preceding);
}

inline bool Calendar::isHoliday(const Date& d) const {
Expand Down
35 changes: 23 additions & 12 deletions ql/time/schedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ namespace QuantLib {
const ext::optional<bool>& endOfMonth,
std::vector<bool> isRegular,
const bool removeFirstDate,
const bool removeLastDate)
const bool removeLastDate,
const ext::optional<BusinessDayConvention>& endOfMonthConvention)
: tenor_(tenor), calendar_(std::move(calendar)), convention_(convention),
terminationDateConvention_(terminationDateConvention), rule_(rule), dates_(dates),
isRegular_(std::move(isRegular)) {
terminationDateConvention_(terminationDateConvention), rule_(rule),
endOfMonthConvention_(endOfMonthConvention), dates_(dates), isRegular_(std::move(isRegular)) {

if (tenor && !allowsEndOfMonth(*tenor))
endOfMonth_ = false;
Expand Down Expand Up @@ -96,10 +97,12 @@ namespace QuantLib {
const Date& first,
const Date& nextToLast,
const bool removeFirstDate,
const bool removeLastDate)
const bool removeLastDate,
const ext::optional<BusinessDayConvention>& endOfMonthConvention)
: tenor_(tenor), calendar_(std::move(cal)), convention_(convention),
terminationDateConvention_(terminationDateConvention), rule_(rule),
endOfMonth_(allowsEndOfMonth(tenor) ? endOfMonth : false),
endOfMonthConvention_(endOfMonthConvention),
firstDate_(first == effectiveDate ? Date() : first),
nextToLastDate_(nextToLast == terminationDate ? Date() : nextToLast) {
// sanity checks
Expand Down Expand Up @@ -224,7 +227,7 @@ namespace QuantLib {
if (nextToLastDate_ != Date()) {
dates_.insert(dates_.begin(), nextToLastDate_);
Date temp = nullCalendar.advance(seed,
-periods*(*tenor_), convention, *endOfMonth_);
-periods*(*tenor_), convention, *endOfMonth_, endOfMonthConvention_);
if (temp!=nextToLastDate_)
isRegular_.insert(isRegular_.begin(), false);
else
Expand All @@ -238,7 +241,7 @@ namespace QuantLib {

for (;;) {
Date temp = nullCalendar.advance(seed,
-periods*(*tenor_), convention, *endOfMonth_);
-periods*(*tenor_), convention, *endOfMonth_, endOfMonthConvention_);
if (temp < exitDate) {
if (firstDate_ != Date() &&
(calendar_.adjust(dates_.front(),convention)!=
Expand Down Expand Up @@ -300,7 +303,7 @@ namespace QuantLib {
if (firstDate_!=Date()) {
dates_.push_back(firstDate_);
Date temp = nullCalendar.advance(seed, periods*(*tenor_),
convention, *endOfMonth_);
convention, *endOfMonth_, endOfMonthConvention_);
if (temp!=firstDate_)
isRegular_.push_back(false);
else
Expand Down Expand Up @@ -332,7 +335,7 @@ namespace QuantLib {
exitDate = nextToLastDate_;
for (;;) {
Date temp = nullCalendar.advance(seed, periods*(*tenor_),
convention, *endOfMonth_);
convention, *endOfMonth_, endOfMonthConvention_);
if (temp > exitDate) {
if (nextToLastDate_ != Date() &&
(calendar_.adjust(dates_.back(),convention)!=
Expand Down Expand Up @@ -434,7 +437,10 @@ namespace QuantLib {

if (*endOfMonth_ && calendar_.isEndOfMonth(seed)) {
// adjust to end of month
if (convention == Unadjusted) {
if (endOfMonthConvention_) {
for (Size i=1; i<dates_.size()-1; ++i)
dates_[i] = calendar_.endOfMonth(dates_[i], endOfMonthConvention_);
} else if (convention == Unadjusted) {
for (Size i=1; i<dates_.size()-1; ++i)
dates_[i] = Date::endOfMonth(dates_[i]);
} else {
Expand Down Expand Up @@ -629,6 +635,11 @@ namespace QuantLib {
return *this;
}

MakeSchedule& MakeSchedule::withEndOfMonthConvention(BusinessDayConvention conv) {
endOfMonthConvention_ = conv;
return *this;
}

MakeSchedule& MakeSchedule::withRule(DateGeneration::Rule r) {
rule_ = r;
return *this;
Expand Down Expand Up @@ -696,9 +707,9 @@ namespace QuantLib {
calendar = NullCalendar();
}

return Schedule(effectiveDate_, terminationDate_, *tenor_, calendar,
convention, terminationDateConvention,
rule_, endOfMonth_, firstDate_, nextToLastDate_);
return Schedule(effectiveDate_, terminationDate_, *tenor_, calendar, convention,
terminationDateConvention, rule_, endOfMonth_, firstDate_, nextToLastDate_,
false, false, endOfMonthConvention_);
}

Date cdsMaturity(const Date& tradeDate, const Period& tenor, DateGeneration::Rule rule) {
Expand Down
20 changes: 18 additions & 2 deletions ql/time/schedule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ namespace QuantLib {
const ext::optional<bool>& endOfMonth = ext::nullopt,
std::vector<bool> isRegular = std::vector<bool>(0),
const bool removeFirstDate = false,
const bool removeLastDate = false);
const bool removeLastDate = false,
const ext::optional<BusinessDayConvention>& endOfMonthConvention = ext::nullopt);
/*! rule based constructor */
Schedule(Date effectiveDate,
const Date& terminationDate,
Expand All @@ -67,7 +68,8 @@ namespace QuantLib {
const Date& firstDate = Date(),
const Date& nextToLastDate = Date(),
const bool removeFirstDate = false,
const bool removeLastDate = false);
const bool removeLastDate = false,
const ext::optional<BusinessDayConvention>& endOfMonthConvention = ext::nullopt);
Schedule() = default;
//! \name Date access
//@{
Expand All @@ -93,6 +95,8 @@ namespace QuantLib {
BusinessDayConvention businessDayConvention() const;
bool hasTerminationDateBusinessDayConvention() const;
BusinessDayConvention terminationDateBusinessDayConvention() const;
bool hasEndOfMonthBusinessDayConvention() const;
BusinessDayConvention endOfMonthBusinessDayConvention() const;
bool hasRule() const;
DateGeneration::Rule rule() const;
bool hasEndOfMonth() const;
Expand All @@ -118,6 +122,7 @@ namespace QuantLib {
ext::optional<BusinessDayConvention> terminationDateConvention_;
ext::optional<DateGeneration::Rule> rule_;
ext::optional<bool> endOfMonth_;
ext::optional<BusinessDayConvention> endOfMonthConvention_;
Date firstDate_, nextToLastDate_;
std::vector<Date> dates_;
std::vector<bool> isRegular_;
Expand All @@ -137,6 +142,7 @@ namespace QuantLib {
MakeSchedule& withCalendar(const Calendar&);
MakeSchedule& withConvention(BusinessDayConvention);
MakeSchedule& withTerminationDateConvention(BusinessDayConvention);
MakeSchedule& withEndOfMonthConvention(BusinessDayConvention);
MakeSchedule& withRule(DateGeneration::Rule);
MakeSchedule& forwards();
MakeSchedule& backwards();
Expand All @@ -152,6 +158,7 @@ namespace QuantLib {
ext::optional<BusinessDayConvention> terminationDateConvention_;
DateGeneration::Rule rule_ = DateGeneration::Backward;
bool endOfMonth_ = false;
ext::optional<BusinessDayConvention> endOfMonthConvention_;
Date firstDate_, nextToLastDate_;
};

Expand Down Expand Up @@ -248,6 +255,15 @@ namespace QuantLib {
return *endOfMonth_;
}

inline bool Schedule::hasEndOfMonthBusinessDayConvention() const {
return static_cast<bool>(endOfMonthConvention_);
}

inline BusinessDayConvention Schedule::endOfMonthBusinessDayConvention() const {
QL_REQUIRE(hasEndOfMonthBusinessDayConvention(),
"full interface (end of month bdc) not available");
return *endOfMonthConvention_;
}
}

#endif

0 comments on commit 4afd269

Please sign in to comment.