Applies an arbitrary summary function over rolling time-period windows.
Each window spans periods units of period (e.g., 12 months). All rows
that fall into the same period receive the value of that period's window.
Before calling .f, rows with any missing values are dropped from the
window; if fewer than min_obs rows remain, the result is NA_real_
instead.
Usage
compute_rolling_value(
data,
.f,
period = "month",
periods = 12,
min_obs = periods,
data_options = NULL
)Arguments
- data
A data frame with a date column of class
Date, named according todata_options$date(default"date").- .f
A function applied to each window. Receives a data-frame slice (complete cases only) and must return a single scalar value.
- period
A string specifying the period for rolling windows (e.g.,
"month","quarter","year").- periods
Number of periods to include in the rolling window.
- min_obs
Minimum number of non-missing rows required per window. Defaults to
periods.- data_options
A list of class
tidyfinance_data_options(created viadata_options()) specifying column name mappings. Thedateelement is used to specify the date column. Usesdata_options()default ifNULL:"date" = "date".
See also
Other rolling and lagging functions:
add_lagged_columns(),
join_lagged_values()
Examples
library(dplyr)
#>
#> Attaching package: ‘dplyr’
#> The following objects are masked from ‘package:stats’:
#>
#> filter, lag
#> The following objects are masked from ‘package:base’:
#>
#> intersect, setdiff, setequal, union
# Rolling standard deviation
set.seed(42)
df <- tibble(
date = seq.Date(
from = as.Date("2020-01-01"),
by = "month",
length.out = 24
),
value = rnorm(24)
)
df |>
mutate(
rolling_sd = compute_rolling_value(
pick(everything()),
.f = ~ sd(.x$value, na.rm = TRUE),
period = "month",
periods = 4,
min_obs = 2
)
)
#> # A tibble: 24 × 3
#> date value rolling_sd
#> <date> <dbl> <dbl>
#> 1 2020-01-01 1.37 NA
#> 2 2020-02-01 -0.565 1.37
#> 3 2020-03-01 0.363 0.968
#> 4 2020-04-01 0.633 0.800
#> 5 2020-05-01 0.404 0.529
#> 6 2020-06-01 -0.106 0.310
#> 7 2020-07-01 1.51 0.675
#> 8 2020-08-01 -0.0947 0.760
#> 9 2020-09-01 2.02 1.10
#> 10 2020-10-01 -0.0627 1.08
#> # ℹ 14 more rows
# Rolling last residual from a regression
set.seed(42)
df_reg <- tibble(
date = seq.Date(
from = as.Date("2020-01-01"),
by = "month",
length.out = 60
),
ret_excess = rnorm(60, 0, 0.05),
mkt_excess = rnorm(60, 0, 0.04),
smb = rnorm(60, 0, 0.03),
hml = rnorm(60, 0, 0.03)
)
df_reg |>
mutate(
residual = compute_rolling_value(
pick(everything()),
.f = \(x) {
last(lm(ret_excess ~ mkt_excess + smb + hml, data = x)$residuals)
},
period = "month",
periods = 24,
min_obs = 12
)
)
#> # A tibble: 60 × 6
#> date ret_excess mkt_excess smb hml residual
#> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2020-01-01 0.0685 -0.0147 -0.0448 0.00454 NA
#> 2 2020-02-01 -0.0282 0.00741 -0.0441 -0.0175 NA
#> 3 2020-03-01 0.0182 0.0233 0.00374 0.0111 NA
#> 4 2020-04-01 0.0316 0.0560 -0.0299 0.00884 NA
#> 5 2020-05-01 0.0202 -0.0291 -0.0000547 -0.00838 NA
#> 6 2020-06-01 -0.00531 0.0521 -0.0128 -0.0401 NA
#> 7 2020-07-01 0.0756 0.0134 -0.0184 0.0210 NA
#> 8 2020-08-01 -0.00473 0.0415 -0.0607 0.0166 NA
#> 9 2020-09-01 0.101 0.0368 -0.0367 -0.0251 NA
#> 10 2020-10-01 -0.00314 0.0288 0.00539 -0.0478 NA
#> # ℹ 50 more rows
# Rolling cumulative-return-to-SD ratio
set.seed(42)
df_resid <- tibble(
date = seq.Date(
from = as.Date("2020-01-01"),
by = "month",
length.out = 24
),
int_roll_residual = rnorm(24, 0, 0.02)
)
df_resid |>
mutate(
return_to_sd = compute_rolling_value(
pick(everything()),
.f = ~ (prod(1 + .x$int_roll_residual) - 1) / sd(.x$int_roll_residual),
period = "month",
periods = 12,
min_obs = 12
)
)
#> # A tibble: 24 × 3
#> date int_roll_residual return_to_sd
#> <date> <dbl> <dbl>
#> 1 2020-01-01 0.0274 NA
#> 2 2020-02-01 -0.0113 NA
#> 3 2020-03-01 0.00726 NA
#> 4 2020-04-01 0.0127 NA
#> 5 2020-05-01 0.00809 NA
#> 6 2020-06-01 -0.00212 NA
#> 7 2020-07-01 0.0302 NA
#> 8 2020-08-01 -0.00189 NA
#> 9 2020-09-01 0.0404 NA
#> 10 2020-10-01 -0.00125 NA
#> # ℹ 14 more rows