简体   繁体   中英

Rolling calculation of beta (linear regression slope)

I have a dataframe

> df
      date comp   ret  mret
1   1/1/75    A  0.07  0.06
2   1/2/75    A  0.04  0.05
3   1/3/75    A  0.01  0.01
4   1/4/75    A -0.05 -0.04
5   1/5/75    A  0.05  0.05
6   1/6/75    A  0.04  0.04
7   1/7/75    A  0.07  0.08
8   1/8/75    A  0.01  0.00
9   1/9/75    A -0.02 -0.01
10 1/10/75    A -0.03 -0.01
11 1/11/75    A  0.01  0.02
12 1/12/75    A  0.03  0.04
13  1/1/75    B  0.09  0.06
14  1/2/75    B  0.07  0.05
15  1/3/75    B  0.04  0.01
16  1/4/75    B -0.02 -0.04
17  1/5/75    B  0.06  0.05
18  1/6/75    B  0.08  0.04
19  1/7/75    B  0.10  0.08
20  1/8/75    B  0.02  0.00
21  1/9/75    B -0.01 -0.01
22 1/10/75    B  0.01 -0.01
23 1/11/75    B -0.01  0.02
24 1/12/75    B  0.07  0.04

I want to calculate beta based on CAPM which is the slope between ret and mret (y-variable = ret, x-variable = mret). This means that I need to do a linear regression to calculate this beta.

The twist is then that I want to calculate the rolling beta over the past 5 months and at least 3 months for each company. To break it down:

  1. I need to make the first beta calculation at line number 3 since this has 3 months of data. At line 4 I want to use the past 4 months of data when calculating beta, at line 5 I want the past 5 months of data, at line 6 I want the past 5 months of data again etc.

  2. I want to group the calculation by the variable 'comp', meaning that at line 13 everything resets and the first calculation starts at line 15 and then follows the method mentioned above.

The results should end up looking like this:

      date comp   ret  mret   beta
1   1/1/75    A  0.07  0.06     NA
2   1/2/75    A  0.04  0.05     NA
3   1/3/75    A  0.01  0.01 1.0714
4   1/4/75    A -0.05 -0.04 1.1129
5   1/5/75    A  0.05  0.05 1.1098
6   1/6/75    A  0.04  0.04 1.0578
7   1/7/75    A  0.07  0.08 1.0193
8   1/8/75    A  0.01  0.00 0.9839
9   1/9/75    A -0.02 -0.01 0.9307
10 1/10/75    A -0.03 -0.01 1.0161
11 1/11/75    A  0.01  0.02 0.9895
12 1/12/75    A  0.03  0.04 1.0106
13  1/1/75    B  0.09  0.06     NA
14  1/2/75    B  0.07  0.05     NA
15  1/3/75    B  0.04  0.01 0.9286
16  1/4/75    B -0.02 -0.04 1.0484
17  1/5/75    B  0.06  0.05 0.9913
18  1/6/75    B  0.08  0.04 0.9932
19  1/7/75    B  0.10  0.08 0.9807
20  1/8/75    B  0.02  0.00 1.0046
21  1/9/75    B -0.01 -0.01 1.1496
22 1/10/75    B  0.01 -0.01 1.1613
23 1/11/75    B -0.01  0.02 1.0559
24 1/12/75    B  0.07  0.04 1.0426

Is there a way to do this in R?

Using df from the Note at the end, create a slope function and use rollapplyr to run it on a moving window. partial = 3 tells it to use partial windows at the beginning of at least 3 rows.

library(dplyr)
library(zoo)

slope <- function(m) {
  ret <- m[, 1]
  mret <- m[, 2]
  cov(ret, mret) / var(mret)
}

df %>%
  group_by(comp) %>%
  mutate(beta = rollapplyr(cbind(ret, mret), 5, slope, partial = 3, fill = NA,
      by.column = FALSE)) %>%
  ungroup

giving:

# A tibble: 24 x 5
   date    comp    ret  mret   beta
   <chr>   <chr> <dbl> <dbl>  <dbl>
 1 1/1/75  A      0.07  0.06 NA    
 2 1/2/75  A      0.04  0.05 NA    
 3 1/3/75  A      0.01  0.01  1.07 
 4 1/4/75  A     -0.05 -0.04  1.11 
 5 1/5/75  A      0.05  0.05  1.11 
 6 1/6/75  A      0.04  0.04  1.06 
 7 1/7/75  A      0.07  0.08  1.02 
 8 1/8/75  A      0.01  0     0.984
 9 1/9/75  A     -0.02 -0.01  0.931
10 1/10/75 A     -0.03 -0.01  1.02 
# ... with 14 more rows

Note

Input in reproducible form:

Lines <- "date comp   ret  mret
1   1/1/75    A  0.07  0.06
2   1/2/75    A  0.04  0.05
3   1/3/75    A  0.01  0.01
4   1/4/75    A -0.05 -0.04
5   1/5/75    A  0.05  0.05
6   1/6/75    A  0.04  0.04
7   1/7/75    A  0.07  0.08
8   1/8/75    A  0.01  0.00
9   1/9/75    A -0.02 -0.01
10 1/10/75    A -0.03 -0.01
11 1/11/75    A  0.01  0.02
12 1/12/75    A  0.03  0.04
13  1/1/75    B  0.09  0.06
14  1/2/75    B  0.07  0.05
15  1/3/75    B  0.04  0.01
16  1/4/75    B -0.02 -0.04
17  1/5/75    B  0.06  0.05
18  1/6/75    B  0.08  0.04
19  1/7/75    B  0.10  0.08
20  1/8/75    B  0.02  0.00
21  1/9/75    B -0.01 -0.01
22 1/10/75    B  0.01 -0.01
23 1/11/75    B -0.01  0.02
24 1/12/75    B  0.07  0.04"
df <- read.table(text = Lines)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM