QuantLib: Calendars

In an earlier post I talked about day counters which are used yo calculate the day difference between two dates. Sometimes it is necessary to also keep track of weekends and holidays. This is particularly true when considering settlement dates or evaluation dates as these are often bound to some particular marketplace. Each market will have its particular rules for determining which days are trading days and which are not.

The Calendar class encapsulates the behavior for all calendars and allows correcting dates which happen to fall on non-trading days. Calendars have value semantics. This means that a calendar variable can be assigned to another by value and the assigned-to calendar will act as a calendar of the assigning calendar, irrespective of its type. Consider the following example.

// The UK stock exchange calendar
Calendar uk = UnitedKingdom( UnitedKingdom::exchange );
// The Italian stock exchange calendar
Italy italy(Italy::Exchange); 

italy = uk;

The assignment on the last line is possible, although it is discouraged. After the last line the italy calendar variable holds the UK Stock Exchange calender, even though it is of type Italy.

The following methods provide information about the calendar or a particular date in context of a calendar.

std::string name() const;
bool isBusinessDay(const Date& d) const;
bool isHoliday(const Date& d) const;
bool isWeekend(Weekday w) const;
bool isEndOfMonth(const Date& d) const;
Date endOfMonth(const Date& d) const;

The name() method returns a human readable name of the calendar. The name is meant for user interaction or diagnostic. It is not advised to use the name to distinguish between different calendar classes in the form of if statements. The strings returned by the method are not guaranteed to stay the same between different versions of the library.

The method, isBusinessDay(), returns true if the date passed to it is a business day in the calendar and false if it isn’t. In the same way, isHoliday() returns true for holidays and false for non holidays and isWeekend() returns true if the weekday passed to it falls on a weekend. Note that the last method does not take dates as argument but Weekday values. isEndOfMonth () returns true if the date is the last business day in the month. Finally, endOfMonth() takes a date and returns the date of the last business day within the same month. Let’s look at the following example.

void printDateInformation(Date d, Calendar cal) {
  if (cal.isBusinessDay(d))
    std::cout << d << " is a business day" << std::endl; 

  if (cal.isHoliday(d))
    std::cout << d << " is a holiday" << std::endl;

  if (cal.isWeekend(d.weekday()))
    std::cout << d << " falls on a weekend" << std::endl;

  if (cal.isEndOfMonth(d))
    std::cout << d << " is the last business day of the month"
      << std::endl;

  std::cout << "The last business day of " << d.month() << " "
    << d.year() << " is " << cal.endOfMonth(d) << std::endl;

Calendar uk=UnitedKingdom();

std:: cout << "Using calendar " << uk. name() << std:: endl;

printDateInformation(Date(25, Dec, 2012), uk);
printDateInformation(Date(28, Feb, 2013), uk);
printDateInformation(Date(26, Jan, 2013), uk);

This code will produce the following output.

Using calendar UK settlement
December 25th, 2012 is a holiday
The last business day of December 2012 is December 31st, 2012
February 28th, 2013 is a business day
February 28th, 2013 is the last business day of the month
The last business day of February 2013 is February 28th, 2013
January 26th, 2013 is a holiday
January 26th, 2013 falls on a weekend
The last business day of January 2013 is January 31st, 2013

Calendars can be adjusted by adding or removing user defined holidays. The following two methods allow the user to do just that.

void addHoliday(const Date&);
void removeHoliday(const Date&);
static std::vector
   holidayList(const Calendar& calendar,
               const Date& from,
               const Date& to,
               bool includeWeekEnds = false);

The addHoliday() method adds a holiday while the removeHoliday() method removes them. Note that, when adding or removing holidays from a calendar, this affects all the calendar instances of that particular calendar. The static method holidayList() returns a vector of dates corresponding to the holidays of a particular calendar. The calendar is passed as the first argument to the function and the date interval is passed in the second and third argument in form of a from and a to date. By default the function does not return weekend days unless the optional flag includeWeekEnds is set to true.

The most central methods of the Calendar class are the ones that adjust or advance dates according to the while ensuring that they fall on business days.

Date adjust(const Date&,
            BusinessDayConvention convention = Following) const;

Date advance(const Date&,
             Integer n,
             TimeUnit unit,
             BusinessDayConvention convention = Following,
             bool endOfMonth = false) const;

Date advance(const Date& date,
             const Period& period,
             BusinessDayConvention convention = Following,
              bool endOfMonth = false) const;

BigInteger businessDaysBetween(
        const Date& from,
        const Date& to,
        bool includeFirst = true,
        bool includeLast = false) const;

The method adjust() takes a date and, if it falls on a holiday or weekend, returns an adjusted date that lies on a business day. If the date is already a business day adjust () will simply return the date unchanged. The method takes an optional argument of the type BusinessDayConvention. The default for this argument is Following which means that adjust will always return the following business day after a holiday. BusinessDayConvention is an enum which defines the following values.

Following: Always adjust a holiday to the next business day following it.

ModifiedFollowing: Similar to Following with one exception. If the following business day is in a different month to the holiday the choose the last business day before the holiday.

Preceding: Always adjust a holiday to the last business day before the holiday.

ModifiedPreceding: Similar to Preceding with one exception. If the previous business day is in a different month to the holiday then choose the next business day after the holiday.

Unadjusted: Do not adjust holidays and always return the original date.

The method advance() advances a date by a specified period of time. The method takes three parameters, the optional BusinessDayConvention and a boolean flag which specifies the end of month behavior. The first argument is the date, the second and third specify the time interval and the time unit. For example advance(date,3,Month) will advance the given date by three months. The result of advance() is guaranteed to be a business day, and the fourth parameter specifies the business day convention by which any holiday should be adjusted. Finally, the endOfMonth flag specifies the behaviour if the input date happens to be the last business day of the month. In that case, if endOfMonth is true, then the resulting date will also be the last business day in its month.

To find out how many business days lie between two dates use the function businessDaysBetween(). This function takes two dates and calculates the number of business days between them. Two optional boolean flags determine whether the first date or the last date should be included in the count. By default the first date is included whereas the last day isn’t.

An example will illustrate the functionality.

Calendar de = Germany();
Date from(30, Nov, 2012);
Date to(31, Dec, 2012);
std::cout << "Business days between " << from << " and " << to 
    << std::endl
std::cout << "  according to " << de.name() << " calendar"
    << std::endl;

std::cout << "standard counting: "
    << de.businessDaysBetween(from, to) << std::endl;

std::cout << "including both end dates: "
    << de.businessDaysBetween(from, to, true, true) << std::endl;

This will write the following output to the console.

Business days between November 30th, 2012 and December 31st, 2012
  according to Frankfurt stock exchange calendar
standard counting: 18
including both end dates: 18

Finally, the method empty() will return a truth value signalling if the calendar is empty or if it has been initialised with a concrete calendar class.