QuantLib icon indicating copy to clipboard operation
QuantLib copied to clipboard

calendar advance EOM rule - only activate if end of calendar month

Open klin333 opened this issue 2 years ago • 1 comments

Hi,

Currently I believe the EOM rule kicks in for date advance() if the start date is the last business day of the month. However, there are use cases where the user wants the EOM rule to kick in only if the start date is the last calendar day of the month. For example this is what Bloomberg does in its date generation in the terminal function ICVS.

Implementing this in QuantLib's user land would be quite tricky because the isEndOfMonth function, as defined in calendar.hpp, is not virtual, so I can't override it in my own calendar classes even if I wanted to. We can't just change isEndOfMonth either since it was officially documented as whether date is last business day of month. It's almost as if we'll need another argument to advance(), maybe endOfCalendarMonth?

import QuantLib as ql

cal = ql.WeekendsOnly()
start = ql.Date(29, ql.April, 2022) # last business day of month
tenor = ql.Period(1, ql.Months)
eom = True
cal.advance(start, tenor, ql.Following, eom)
# output Date(31,5,2022) because eom rule activated, 
# but some user may want Date(30,5,2022) ie for eom rule to not activate because
# the start date is only last business day but not last calendar day of month

klin333 avatar Jul 15 '22 07:07 klin333

This issue was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.

github-actions[bot] avatar Sep 14 '22 02:09 github-actions[bot]

This issue was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.

github-actions[bot] avatar Nov 14 '22 02:11 github-actions[bot]

Hi @klin333, I tried to debug a test case and I think that the EOM rule is triggering also for the last calendar day of the month. The source code in calendar.cpp which is managing the functionality of calendar advance is the following:

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

return adjust(d1, c);

endOfMonth is the argument passed to function Calendar::advance, isEndOfMonth(d) is the function which is checking if the start date d is on or after the last business day for that month. Hence the EOM rule is triggered also when the function is called with the last calendar day of the month, which can of course be after the last business day of the month. The function Calendar::endOfMonth(d1) is returning the last business day of the calculated date d1.

Let's for instance consider the following test case: start date 30 April 2023 (Sunday, it is not the last business day of the month, which is Friday 28 April 2023) tenor 1 Month endOfMonth true

The result seems consistent: start date: April 30th, 2023 EOM argument endOfMonth: true start date isEndOfMonth: true last business day for start date EndOfMonth: April 28th, 2023 start date + tenor: May 30th, 2023 Calendar::advance date: May 31st, 2023

It looks like that the EOM rule has been triggered successfully even if the start date is not the last business date of the month. It is in fact the last calendar date of the month. Maybe I am missing something but I can't see any inconsistency here. Any comment from QuantLib experienced developers is welcome. I paste here the source code used for the test.

#include <iostream>
#include <ql/time/all.hpp>
using namespace std;
using namespace QuantLib;

int main() {
    Calendar cal = WeekendsOnly();
    Date start = Date(30, April, 2023);
    bool endom_flag = cal.isEndOfMonth(start);
    Date endom = cal.endOfMonth(start);
    Period tenor = Period(1, Months);
    bool eom = true;
    Date next = cal.advance(start, tenor, Following, eom);
    cout << "start date: " << start << '\n'
         << "EOM argument endOfMonth: " << (eom?"true":"false") << '\n'
         << "start date isEndOfMonth: " << (endom_flag?"true":"false") << '\n'
         << "last business day for start date EndOfMonth: " << endom << '\n'
         << "start date + tenor: " << start + 1*TimeUnit::Months << '\n'
         << "Calendar::advance date: " << next << '\n';
    return 0;
}

jakeheke75 avatar Dec 18 '22 18:12 jakeheke75

Hi @lballabio since I haven't received any feedback from @klin333 about the analysis above, do you think that this issue can be closed?

jakeheke75 avatar Jan 24 '23 21:01 jakeheke75

I think what they wanted was for the rule to trigger only on the last calendar day of the month, and not on previous ones even if they're the last business day.

I'd leave the issue open for a while more to have more chances of feedback. It will be closed automatically if there's no activity for a while.

lballabio avatar Jan 25 '23 08:01 lballabio

This issue was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.

github-actions[bot] avatar Mar 27 '23 01:03 github-actions[bot]

This issue was automatically closed because it has been stalled for two weeks with no further activity.

github-actions[bot] avatar Apr 11 '23 01:04 github-actions[bot]