Skip to content

Commit

Permalink
Fix calendar advance for unadjusted convention (#1917)
Browse files Browse the repository at this point in the history
Fix calendar advance for unadjusted convention
  • Loading branch information
lballabio committed Feb 28, 2024
2 parents ea15ebb + 4ed9da4 commit bd7242c
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
12 changes: 9 additions & 3 deletions ql/time/calendar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,15 @@ namespace QuantLib {
Date d1 = d + n*unit;

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

if (endOfMonth){
if (c == Unadjusted && Date::isEndOfMonth(d)){
// move to end of calendar day if using Unadjusted convention and d is last calendar day
return Date::endOfMonth(d1);
} else if (isEndOfMonth(d)) {
// move to end of business day if d is last bussiness day
return Calendar::endOfMonth(d1);
}
}
return adjust(d1, c);
}
}
Expand Down
2 changes: 1 addition & 1 deletion test-suite/businessdayconventions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(testConventions) {
//Unadjusted
SingleCase(SouthAfrica(), Unadjusted, Date(3,February,2015), Period(1,Months), false, Date(3,March,2015)),
SingleCase(SouthAfrica(), Unadjusted, Date(3,February,2015), Period(4,Days), false, Date(9,February,2015)),
SingleCase(SouthAfrica(), Unadjusted, Date(31,January,2015), Period(1,Months), true, Date(27,February,2015)),
SingleCase(SouthAfrica(), Unadjusted, Date(31,January,2015), Period(1,Months), true, Date(28,February,2015)),
SingleCase(SouthAfrica(), Unadjusted, Date(31,January,2015), Period(1,Months), false, Date(28,February,2015)),

//HalfMonthModifiedFollowing
Expand Down
32 changes: 32 additions & 0 deletions test-suite/cashflows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,38 @@ BOOST_AUTO_TEST_CASE(testIrregularFirstCouponReferenceDatesAtEndOfMonth) {
"got " << firstCoupon->referencePeriodStart());
}

BOOST_AUTO_TEST_CASE(testIrregularFirstCouponReferenceDatesAtEndOfCalendarMonth) {
BOOST_TEST_MESSAGE("Testing irregular first coupon reference dates at end of calendar month with end of month enabled...");
Schedule schedule =
MakeSchedule()
.withCalendar(UnitedStates(UnitedStates::GovernmentBond))
.from(Date(30, September, 2017)).to(Date(30, September, 2022))
.withTenor(6*Months)
.withConvention(Unadjusted)
.withTerminationDateConvention(Unadjusted)
.withFirstDate(Date(31, March, 2018))
.withNextToLastDate(Date(31, March, 2022))
.endOfMonth()
.backwards();

Leg leg = FixedRateLeg(schedule)
.withNotionals(100.0)
.withCouponRates(0.01875, ActualActual(ActualActual::ISMA));

for (const auto& elem : leg) {
BOOST_TEST_MESSAGE("Reference Period: " << ext::dynamic_pointer_cast<Coupon>(elem)->referencePeriodStart() << " - " << ext::dynamic_pointer_cast<Coupon>(elem)->referencePeriodEnd());
BOOST_TEST_MESSAGE("Amount: " << ext::dynamic_pointer_cast<Coupon>(elem)->amount());
}

ext::shared_ptr<Coupon> firstCoupon =
ext::dynamic_pointer_cast<Coupon>(leg.front());
if (firstCoupon->referencePeriodStart() != Date(30, September, 2017))
BOOST_ERROR("Expected reference start date at end of calendar day of the month, "
"got " << firstCoupon->referencePeriodStart());
// Expect first cashflow to be 0.9375
BOOST_TEST(firstCoupon->amount() == 0.9375, boost::test_tools::tolerance(0.0001));
}

BOOST_AUTO_TEST_CASE(testIrregularLastCouponReferenceDatesAtEndOfMonth) {
BOOST_TEST_MESSAGE("Testing irregular last coupon reference dates with end of month enabled...");
Schedule schedule =
Expand Down

0 comments on commit bd7242c

Please sign in to comment.