CAPM.beta rollapply

喜欢而已 提交于 2019-12-08 13:31:41

问题


I have already successfully calculated my rolling correlations in my xts object with

x <- cbind(market_return,stock_returns)
rollcor_3year <- rollapplyr(
    x, width=width_cor,function(x) cor(x[,1],x[,-1],
    use="pairwise.complete.obs"),by.column=FALSE)

The correlation was later used to calculate rolling Betas.

Now I found the function CAPM.beta from the PerformanceAnalytics package and I wonder why I cannot use

beta <- rollapplyr(x,width=width_cor,function(x) CAPM.beta(x[,1],x[,-1]),by.column=FALSE)

or

beta <- rollapplyr(stock_returns,width=width_cor,CAPM.beta,Rb=market_return,by.column=FALSE)

directly.

With both functions it starts to calculate but doesnt stop...

It would be nice to see if I get the same betas out of the predefined function, but apparently it does not work like that. What did I do wrong?


回答1:


Actually, the PerformanceAnalytics function will give the same results but it takes longer to do it. The code below uses sample data for 2017-01-01 to now with AMZN and XOM as stocks and SPY as a proxy for market returns. A window of 40 trading days is used in the rolling calculations. The rolling beta value is calculated using the CAPM.beta and BetaCoVariance functions from PerformanceAnalytics and by three methods which directly calculate the covariance matrix and then taking the ratio of the pairwise covariances to the market variance. The results from the methods are displayed to show they are the same. microbenchmark from the microbenchmark package is used to measure execution times for all methods. The direct calculations is one to two orders of magnitude faster.

  library(xts)
  library(quantmod)
  library(PerformanceAnalytics)
  library(microbenchmark)
#
#  get price time histories and calculate returns
#  use SPY as proxy for S&P 500; SPY should be first symbol in assets
#
  assets <- c("SPY", "AMZN", "XOM")   
  getSymbols( assets, from = "2017-01-01", auto.assign = TRUE)

  asset_prices <- xts()
  asset_prices <- Reduce(f=function(x,y) {y_sym=eval(as.name(y));  merge(x,y_sym[,paste0(y,".Adjusted")])},
                         x = assets, init=asset_prices) 
  asset_returns <- diff.xts(asset_prices, arithmetic = FALSE, na.pad=FALSE)-1

  market_return <- asset_returns$SPY.Adjusted
  stock_returns <- asset_returns[,-1] 

#
#  calculate rolling beta with a 40 trading-day window using CAPM.beta.roll
#  For this amount of data and calculating daily betas (by = 1), calculation should take 5-10 seconds
#
  width_cor = 40
  CAPM.beta_roll <- rollapply(data=stock_returns, FUN=CAPM.beta, Rb= market_return, Rf = 2.5/252, 
                       width = width_cor, by = 1, align = "right", by.column=TRUE)

#
#  calculate rolling beta with a 40 trading-day window by calculating the covariance matrix and taking ratio of two elements
#  For this amount of data and calculating daily betas (by = 1), calculation should be very quick
#
  CovVar <- function(Ra, Rb) {R = merge.xts(Rb, Ra, join="inner"); cv=cov(x=R);  
                               cv[1,-1]/cv[1,1,drop=TRUE]}
  CovVar_roll <- rollapplyr(data=stock_returns, width=width_cor,
                            FUN= CovVar,  Rb = market_return, by.column=FALSE)

#
#  since rollapply does not apply the window to Rb, it is done in CovVar for each time window
#  CovVar1 is a faster version which passes the merged market and stock return to cov directly
#  Its single argument R must be the merged data matrix R
#
  CovVar1 <- function(R){  cv=cov(x=R); cv[-1,1]/cv[1,1]}
  CovVar1_roll <- rollapplyr(data=merge(market_return, stock_returns), width=width_cor,
                             FUN= CovVar1,  by.column=FALSE)

  #
  #  CovVar2 is a faster version which passes the merged market and stock return to cov directly and 
  #  calculates the covariances only between the market returns and stock_returns.  For a small number of stocks,
  #  this is less efficient than calculating the entire covariance for a single matrix as in CovVar1 but it should become more 
  #  efficient for a larger number of stocks.
  #  Its single argument R must be the merged data matrix R
  #
  CovVar2 <- function(R){  cv = cov(R[,1], R );  cv[,-1]/cv[1,1] }
  CovVar2_roll <- rollapplyr(data=merge(market_return, stock_returns), width=width_cor,
                             FUN= CovVar2,  by.column=FALSE)

#
# Compare to verify that results are the same 
#
  print(tail(merge(CAPM.beta_roll, CovVar_roll, CovVar1_roll, CovVar2_roll )))
#
#  Compare execution times for four above methods and third method using BetaCovariance function from PerformanceAnalytics
#  This should take 25-35 seconds to run
#

  elapsed_times <- microbenchmark(
                  CAPM.beta_roll = rollapplyr(data=stock_returns, width=width_cor,
                                              FUN= CAPM.beta, Rb=market_return,by.column=FALSE),
                  BetaCoVar_roll = rollapplyr(data=stock_returns, width=width_cor,
                                               FUN= BetaCoVariance, Rb=market_return,by.column=FALSE),
                  CovVar_roll = rollapplyr(data=stock_returns, width=width_cor,
                                           FUN= CovVar,  Rb = market_return, by.column=FALSE),
                  CovVar1_roll = rollapplyr(data=merge(market_return, stock_returns), width=width_cor,
                                             FUN= CovVar1,  by.column=FALSE),
                  CovVar2_roll = rollapplyr(data=merge(market_return, stock_returns), width=width_cor,
                                             FUN= CovVar2,  by.column=FALSE),
                   times = 3)

# 
#  Direct calculation using covariance matrix, CovVar, is 50 - 100 times faster than PerformanceAnalytics functions 
#
  print(elapsed_times)

The execution times are:

Unit: milliseconds
           expr        min         lq       mean     median         uq        max neval
 CAPM.beta_roll 3007.34309 3009.92618 3016.57905 3012.50928 3021.19703 3029.88477     3
 BetaCoVar_roll 3453.83531 3471.70954 3478.91433 3489.58377 3491.45383 3493.32390     3
    CovVar_roll   69.19571   69.57012   69.83189   69.94453   70.14999   70.35544     3
   CovVar1_roll   38.72437   39.17021   39.33052   39.61605   39.63359   39.65113     3
   CovVar2_roll   60.75020   61.08255   61.36130   61.41490   61.66684   61.91878     3 

CovVar1 is the quickest since at least for a small number of dimensions, R calculates the covariance matrix much more efficiently for a single matrix input than for an input of two matrices where it has to align the matrices. For some larger number of dimensions, the CovVar2 should be faster.




回答2:


Here is a solution as in WaltS's answer but around 16 times faster then the CovVar2 function using the rollRegres package

library(xts)
library(quantmod)
library(PerformanceAnalytics)
library(microbenchmark)

# setup
assets <- c("SPY", "AMZN", "XOM")
getSymbols( assets, from = "2017-01-01", auto.assign = TRUE)
#R [1] "SPY"  "AMZN" "XOM"

asset_prices <- xts()
asset_prices <- Reduce(f=function(x,y) {y_sym=eval(as.name(y));  merge(x,y_sym[,paste0(y,".Adjusted")])},
                       x = assets, init=asset_prices)
asset_returns <- diff.xts(asset_prices, arithmetic = FALSE, na.pad=FALSE)-1

market_return <- asset_returns$SPY.Adjusted
stock_returns <- asset_returns[,-1]

# solution from WaltS's answer
width_cor <-  40
CovVar2 <- function(R){  cv = cov(R[,1], R );  cv[,-1]/cv[1,1] }
CovVar2_roll <- rollapplyr(
  data = merge(market_return, stock_returns), width=width_cor,
  FUN= CovVar2,  by.column=FALSE)

# rollRegres solution
library(rollRegres)
dat <- as.matrix(merge(market_return, stock_returns))
X  <- cbind(1, dat[, 1])
Ys <- dat[, -1, drop = FALSE]
roll_out <- apply(Ys, 2, function(y)
  roll_regres.fit(x = X, y = y, width = width_cor)$coefs[, 2])

# gives the same
all.equal(as.matrix(CovVar2_roll), roll_out, check.attributes = FALSE)
#R [1] TRUE

# much faster
microbenchmark(
  CovVar2 = rollapplyr(
    data = merge(market_return, stock_returns), width=width_cor,
    FUN= CovVar2,  by.column=FALSE),
  rollRegres = {
    dat <- as.matrix(merge(market_return, stock_returns))
    X  <- cbind(1, dat[, 1])
    Ys <- dat[, -1, drop = FALSE]
    roll_out <- apply(Ys, 2, function(y)
      roll_regres.fit(x = X, y = y, width = width_cor)$coefs[, 2])
  }, times = 10)
#R Unit: milliseconds
#R       expr       min        lq      mean    median        uq      max neval
#R    CovVar2 37.669941 39.086237 39.877981 39.530485 41.011374 41.71893    10
#R rollRegres  1.987162  2.036149  2.486836  2.102717  3.342224  3.73689    10


来源:https://stackoverflow.com/questions/51101871/capm-beta-rollapply

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!