Billsyd
Billsyd

Reputation: 25

rollapply a function across different columns in a panel dataset

I am trying to calculate the idiosyncratic skewness for different funds in a panel data. Basically, I hope to regress the daily returns of a fund on the market return and the squared market return to obtain the residuals. Then calculate the skewness of the residuals using skewness(). However, I need to perform this calculation over a 20-day moving window, moving 1-day forward per step. I am thinking to write a function and rollapply the function for each fund in my panel data. However, I failed to obtain my expected results. The following codes generate a mock datatable.

library(dplyr)
library(zoo)

set.seed(123)

# Generate mock data
n <- 100
date_sequence <- seq(as.Date("2022-01-01"), by = "1 day", length.out = n)
fund_sequence <- rep(c("Fund_A", "Fund_B", "Fund_C"), each = n/3)

panel_data <- data.frame(
  fund = rep(fund_sequence, each = n), 
  date = rep(date_sequence, times = 3), 
  returns = rnorm(n * 3), 
  market_returns = rnorm(n * 3)
)

# My own iKewness function
getIskewness <- function(x, y, z) {
  aa <- residuals(lm(x ~ y + y^2))
  aa <- skewness(aa, na.rm = TRUE)
  return(aa)
}

## run a rolling regression 
kk <- panel_data %>%
  group_by(fund) %>%
  arrange(date) %>%
  mutate(Iskewness=rollapply(across(c(returns, market_returns)), width = 20, 
                             FUN=getIskewness, x=returns, y=market_returns, 
                             by.column = FALSE, align = "right", fill="NA")) %>%
  arrange(fund, date)

I found the results are constant for each fund. What I expect is a variable changing daily because the function is supposed to be rollapplied over a 20-day moving window. Could anyone help me? Thanks!

Upvotes: 0

Views: 63

Answers (1)

G. Grothendieck
G. Grothendieck

Reputation: 270065

There are a few problems:

  • SO questions should have minimal reproducible examples so use n<-4 and set width to 3
  • skewness is missing so set it to mean for purposes of allowing it to run
  • use NA, not "NA"
  • rollapply can be written rollapplyr with an r on the end to avoid align="right"
  • only one argument passed to FUN is rolling so create an anonymous function to handle that as shown (or else define getIskewness appropriately with one argument).
  • omit x= and y= as rollapply arguments since that notation is reserved for non-rolling arguments passed to FUN=
  • the z argument is not used in getIskewness
  • use cbind in rollapplyr

Code:

set.seed(123)
# Generate mock data
n <- 4
date_sequence <- seq(as.Date("2022-01-01"), by = "1 day", length.out = n)
fund_sequence <- rep(c("Fund_A", "Fund_B", "Fund_C"), each = n/3)
panel_data <- data.frame(fund = rep(fund_sequence, each = n),
  date = rep(date_sequence, times = 3),
  returns = rnorm(n * 3),
  market_returns = rnorm(n * 3)
)
# My own iKewness function

skewness <- mean
getIskewness<-function(x, y) {
  aa <- residuals(lm(x~y+y^2))
  aa <- skewness(aa, na.rm = TRUE)
  return(aa)
}

## run a rolling regression
kk <- panel_data %>%
  group_by(fund) %>%
  arrange(date) %>%
  mutate(Iskewness = rollapplyr(
    cbind(returns, market_returns),
    width = 3,
    FUN = \(X) getIskewness(X[, 1], X[, 2]),
    by.column = FALSE,
    fill = NA)) %>%
  ungroup %>%
  arrange(fund, date)
kk

giving:

# A tibble: 12 × 5
   fund   date       returns market_returns Iskewness
   <chr>  <date>       <dbl>          <dbl>     <dbl>
 1 Fund_A 2022-01-01 -0.560           0.401 NA       
 2 Fund_A 2022-01-02 -0.230           0.111 NA       
 3 Fund_A 2022-01-03  1.56           -0.556  1.62e-17
 4 Fund_A 2022-01-04  0.0705          1.79  -1.11e-16
 5 Fund_B 2022-01-01  0.129           0.498 NA       
 6 Fund_B 2022-01-02  1.72           -1.97  NA       
 7 Fund_B 2022-01-03  0.461           0.701 -2.31e-17
 8 Fund_B 2022-01-04 -1.27           -0.473  0       
 9 Fund_C 2022-01-01 -0.687          -1.07  NA       
10 Fund_C 2022-01-02 -0.446          -0.218 NA       
11 Fund_C 2022-01-03  1.22           -1.03  -2.04e-16
12 Fund_C 2022-01-04  0.360          -0.729  9.25e-18

Upvotes: 0

Related Questions