Search code examples
rxts

R - Rolling correlation of each column with each other column


Hello and apologies for asking this, as I think variations on the question have been answered many times, but I cannot seem to apply those to my specific problem.

I have a huge time series of stock returns of many different companies that looks something like this

library(tidyquant)
library(PerformanceAnalytics)

df = data.frame(tq_get("AAPL"))

ts = df[ , 3:8] %>%
     xts(order.by = as.Date(df[ , 2], "%Y-%m-%d")) %>%
     Return.calculate()

Now I need to do rolling correlations of each column with each other column in my time series. For just two columns the following works perfectly

rollcor = rollapply(ts, 63, function(x) cor(x[ , 1],x[ , 2]), by.column=FALSE)

But I cannot get it to work with apply() over columns, so I tried a for loop to correlate at least the first column with all the others

rollcors = data.frame(ts)
for(j in ncol(rollcors)) {
  rollcors[ , j] = rollapply(rollcors, 63, function(x) cor(x[ , 1],x[ , j]), by.column=FALSE, fill = NA)
}

But this doesn't replace each column with a new one containing correlations like I hoped it would.

I'd also prefer to keep the output vertically oriented like it is now, for better readability. My perfect result would be a list of dataframes/time series, each containing the correlations of one column with all other columns, which I could then furter manipulate (daily medians, etc.).


Solution

  • This provides the correlation matrix unravelled into a row for each date. There will be n*n columns where ts has n columns:

    r1 <- rollapplyr(ts, 63, cor, fill = NA, by.column = FALSE)
    

    or this will show only the lower triangle and will have choose(n, 2) columns:

    ccor <- function(x) { cc <- cor(x); cc[lower.tri(cc)] }
    r2 <- rollapplyr(X, 63, ccor, fill = NA, by.column = FALSE)
    

    This can be used to assign column names, if needed.

    paste_ <- function(...) paste(..., sep = "_")
    names_mat <- do.call("outer", list(names(ts), names(ts), paste_))
    names(r1) <- names_mat
    names(r2) <- names_mat[lower.tri(names_mat)]