Skip to content

DavisVaughan/calendarrr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

calendarrr

The goal of calendarrr is to enhance the current ecosystem of date manipulation packages out there, mainly lubridate, by adding date calculation methods that respect customizable business days and holidays.

calendarrr provides an R frontend to the QuantLib Calendar library. This package shamelessly rips out sections of QuantLib corresponding to calendar calculations, and exposes them as the S3 class, calendar.

Related work

The RQuantLib package exposes some of this as well, but in a different form and as a subset of a larger purpose of exposing the entire QuantLib library. There are a few benefits of calendarrr vs RQuantLib.

  • RQuantLib does not have the ability to add custom holidays.
  • RQuantLib requires that you install QuantLib yourself (at least on Mac), which can be a major pain and raise the barrier to entry significantly. calendarrr is self-contained.
  • calendarrr tries to focus on providing a consistent and user friendly interface to the calendar library.

Installation

You can install the released version of calendarrr from CRAN with:

# no you cannot
install.packages("calendarrr")

And the development version from GitHub with:

# install.packages("devtools")
devtools::install_github("DavisVaughan/calendarrr")

Example

Easily create a calendar with cal_create(). Provide it the name of the QuantLib calendar you want to create. There are ~30 calendars, each with their own unique holiday schedule (not all implemented yet).

Use cal_add_holidays() to add custom holidays on top of the holidays already

library(calendarrr)
library(magrittr)

# some random days to add as extra holidays
extra_holidays <- as.Date(c("2018-01-02", "2018-01-04"))

usa <- cal_create("UnitedStates") %>%
  cal_add_holidays(extra_holidays)

usa
#> <Calendar:UnitedStates>
#> Extra holidays:
#>    - 2018-01-02
#>    - 2018-01-04

You can check if a certain date is a holiday, weekend, business day, or the end of the month.

# A Tuesday
today <- as.Date("2018-07-31")
custom_holiday <- as.Date("2018-01-02")

cal_is_business_day(dates = today, cal = usa)
#> [1] TRUE

cal_is_end_of_month(today, usa)
#> [1] TRUE

cal_is_holiday(today, usa)
#> [1] FALSE

cal_is_holiday(custom_holiday, usa)
#> [1] TRUE

cal_is_weekend(today, usa)
#> [1] FALSE

You can “adjust” a date relative to a calendar and a business day convention. Adjusting moves a date to the next/previous business day if it is not already a business day.

a_saturday <- as.Date("2018-07-28")

# Adjusts to next monday
cal_adjust(a_saturday, usa, convention = "following")
#> [1] "2018-07-30"

# Adjusts to previous friday
cal_adjust(a_saturday, usa, convention = "preceding")
#> [1] "2018-07-27"

You can “advance” a date relative to a calendar and business day convention. Advancing moves a date by a length + unit to the next business day. For example, 1 day.

# Shift 5 business days forward
# (1 business week in this case because there were no holidays)
cal_advance(today, usa, n = 5, unit = "days")
#> [1] "2018-08-07"

# What if this was around a holiday? Say, July 4th?
# July 4th was a Wednesday
july_4 <- as.Date("2018-07-04")
july_2_monday <- july_4 - 2

# Moves forward 5 business days, ignoring July 4th
cal_advance(july_2_monday, usa, n = 5, unit = "days")
#> [1] "2018-07-10"

# You can go backwards too
cal_advance(july_2_monday, usa, n = -5, unit = "days")
#> [1] "2018-06-25"

# Also, note that the default calendar does not include July 4th as a holiday,
# but the UnitedStates one does. Here is the default:
cal_advance(july_2_monday, n = 5, unit = "days")
#> [1] "2018-07-09"

There is also a handy cal_end_of_month() function.

cal_end_of_month(as.Date("2018-01-15"), usa)
#> [1] "2018-01-31"

All functions are vectorized, of course, and are blazing fast because they are written in C++.

lub_end_of_month <- function(x) {
  d <- lubridate::days_in_month(x)
  m <- lubridate::month(x)
  y <- lubridate::year(x)
  lubridate::make_date(y, m, d)
}

dates <- as.Date("2018-01-01") + 1:1000

microbenchmark::microbenchmark(
  cal_end_of_month(dates, usa),
  lub_end_of_month(dates)
)
#> Unit: microseconds
#>                          expr      min        lq      mean    median
#>  cal_end_of_month(dates, usa)  163.334  179.8795  205.3536  189.6625
#>       lub_end_of_month(dates) 1074.118 1204.3595 3248.6423 1263.8750
#>         uq        max neval
#>   203.1485   1007.464   100
#>  1488.0445 132263.262   100

Also note that the results of these are not equivalent, as cal_end_of_month() again respects business days and will not allow the end of the month to fall on a business day or holiday. For example, 2018-03-31 is a Saturday.

# Respects business day and says the "end of month" is the last business day
# in March
cal_end_of_month(dates, usa)[59]
#> [1] "2018-03-30"

# Just goes to the end of the month
lub_end_of_month(dates)[59]
#> [1] "2018-03-31"

About

An R frontend to the QuantLib Calendar API

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published