
Calendar and holiday regressors
Source:vignettes/seasight-calendar-holidays.Rmd
seasight-calendar-holidays.RmdCalendar effects are part of the model specification. In
seasight, they are therefore treated as explicit candidate
choices rather than hidden package data. This keeps the package focused
on model search, diagnostics and reporting while leaving production
calendars under the control of the user or institution.
The practical rule is:
- use X-13 or
seasonalbuilt-ins for standard effects where possible; - use
build_user_xreg()for institution-supplied moving-holiday dates; - pass the resulting named regressors through
td_candidates; - inspect
with_td,td_nameand the report’s “TD regressor” column.
seasight intentionally does not ship broad holiday
datasets such as holiday or chcal. National
holidays, bridge days, school calendars, religious holidays and trading
calendars are source- and sector-specific. A generic bundled calendar
can easily be wrong for a production series.
Built-in Easter handling
For Easter, the simplest path is usually to let X-13 handle the
effect through the model specification. seasight exposes
this through include_easter.
library(seasight)
library(seasonal)
y <- AirPassengers
res_easter <- auto_seasonal_analysis(
y = y,
include_easter = "auto",
engine = "auto"
)
res_easter$table[1, c(
"model_label", "with_easter", "easter_window", "with_td", "td_name",
"score_100"
)]In "auto" mode, X-13 tests whether Easter improves the
model and selects among its supported Easter windows. The result columns
report the effect actually retained, not merely the requested mode. Use
include_easter = "always" only when the effect is part of
the production policy for that series; this fixes
easter[easter_len]. Use include_easter = "off"
when Easter is known to be irrelevant or is handled elsewhere; this
disables both inclusion and testing.
Precomputed trading-day regressors
For working-day or trading-day effects, many institutions already maintain calendar regressors. Pass those directly as a named list. The names are carried through into the candidate table and HTML report.
dates <- seq(as.Date("1949-01-01"), by = "month", length.out = length(y))
days_in_month <- function(date) {
first <- as.Date(format(date, "%Y-%m-01"))
next_month <- seq(first, by = "month", length.out = 2)[2]
as.integer(next_month - first)
}
length_of_month <- vapply(dates, days_in_month, integer(1))
td_len <- ts(length_of_month - mean(length_of_month), start = start(y), frequency = frequency(y))
res_td <- auto_seasonal_analysis(
y = y,
td_candidates = list(length_of_month = td_len),
td_usertype = "td",
include_easter = "auto",
engine = "auto"
)
res_td$table[1, c("model_label", "with_td", "td_name", "td_p", "score_100")]The example above is deliberately simple. In production, the regressor should come from the relevant business, statistical or national-accounts calendar.
Moving holidays with build_user_xreg()
For holidays with known dates, such as Diwali, Lunar New Year,
Ramadan-related effects or local events, use
build_user_xreg(). Internally this uses
seasonal::genhol() and then aligns the resulting regressor
to the target series.
diwali_dates <- as.Date(c(
"2018-11-07", "2019-10-27", "2020-11-14", "2021-11-04",
"2022-10-24", "2023-11-12", "2024-11-01"
))
cny_dates <- as.Date(c(
"2018-02-16", "2019-02-05", "2020-01-25", "2021-02-12",
"2022-02-01", "2023-01-22", "2024-02-10"
))
holiday_xreg <- build_user_xreg(
y = y,
holidays = list(
diwali = list(dates = diwali_dates, start = -7, end = 0),
lunar_new_year = list(dates = cny_dates, start = -3, end = 3)
),
td_usertype = "holiday"
)
names(holiday_xreg)
res_holiday <- auto_seasonal_analysis(
y = y,
td_candidates = holiday_xreg,
include_easter = "auto",
engine = "auto"
)
res_holiday$table[1, c(
"model_label", "with_td", "td_name", "with_easter", "easter_window",
"td_p", "score_100"
)]For SEATS candidates with user regressors, X-13 needs future
regressor values over its forecast horizon. seasight pads
pulse-type holiday regressors with zeros for this purpose. For non-pulse
regressors, such as trading-day counts, provide future calendar values
yourself where possible.
Inspecting the final decision
The candidate table and the HTML report show which calendar option
was selected. The final “Top candidates” table includes a “TD regressor”
column with either the candidate name, such as diwali, or
none.
sa_report_html(
y = y,
td_candidates = holiday_xreg,
include_easter = "auto",
title = "AirPassengers calendar-regressor example",
outfile = tempfile(fileext = ".html")
)This makes the calendar decision auditable: a reviewer can see whether no calendar regressor was used, whether Easter was included, and which user-supplied holiday candidate won.