This R session will illustrate the practical implementation and use of factor models.

The R package covFactorModel, available in GitHub, is recommended.

(Useful R links: Cookbook R, Quick-R, R documentation, CRAN, METACRAN.)

Macroeconomic factor model with single market factor

We will start with a simple example consisting of a single known factor (i.e., the market index). The model is \[ \mathbf{x}_t = \boldsymbol{\alpha} + \boldsymbol{\beta}f_t + \boldsymbol{\epsilon}_t, \quad t=1,\ldots,T \] where the explicit factor \(f_t\) is the S&P 500 index. We will do a simple least squares (LS) regression to estimate the intercept \(\boldsymbol{\alpha}\) and the loading beta \(\boldsymbol{\beta}\): \[ \underset{\boldsymbol{\alpha},\boldsymbol{\beta}}{\text{minimize}}\quad \sum_{t=1}^T\|\mathbf{x}_t - \boldsymbol{\alpha} - \boldsymbol{\beta}f_t\|^2 \]

Most the code lines go into preparing the data rather than actually performing the factor modeling. Let’s start getting the data ready:

library(xts)
library(quantmod)

# set begin-end date and stock namelist
begin_date <- "2016-01-01"
end_date <- "2017-12-31"
stock_namelist <- c("AAPL", "AMD", "ADI",  "ABBV", "AET", "A",  "APD", "AA","CF")
sector_namelist <- c(rep("Information Technology", 3), rep("Health Care", 3), rep("Materials", 3))

# download data from YahooFinance
data_set <- xts()
for (stock_index in 1:length(stock_namelist))
  data_set <- cbind(data_set, Ad(getSymbols(stock_namelist[stock_index], 
                                            from = begin_date, to = end_date, auto.assign = FALSE)))
colnames(data_set) <- stock_namelist
indexClass(data_set) <- "Date"
str(data_set)
#> An 'xts' object on 2016-01-04/2017-12-29 containing:
#>   Data: num [1:503, 1:9] 100.3 97.8 95.8 91.8 92.3 ...
#>  - attr(*, "dimnames")=List of 2
#>   ..$ : NULL
#>   ..$ : chr [1:9] "AAPL" "AMD" "ADI" "ABBV" ...
#>   Indexed by objects of class: [Date] TZ: UTC
#>   xts Attributes:  
#>  NULL
head(data_set)
#>                 AAPL  AMD      ADI     ABBV      AET        A      APD
#> 2016-01-04 100.27451 2.77 51.05404 52.05566 106.0680 39.70486 109.8707
#> 2016-01-05  97.76168 2.75 50.67892 51.83879 107.5435 39.56824 107.9061
#> 2016-01-06  95.84851 2.51 48.52197 51.84784 106.9999 39.74389 105.2782
#> 2016-01-07  91.80328 2.28 47.28407 51.69422 107.0484 38.05577 101.7488
#> 2016-01-08  92.28870 2.14 46.87144 50.28463 103.9419 37.65570 101.2215
#> 2016-01-11  93.78307 2.34 47.98742 48.68528 102.2431 37.02144 101.6212
#>                  AA       CF
#> 2016-01-04 23.00764 36.08226
#> 2016-01-05 21.96506 34.95080
#> 2016-01-06 20.40121 31.93058
#> 2016-01-07 19.59558 30.41601
#> 2016-01-08 19.12169 30.13092
#> 2016-01-11 18.95583 28.91036
tail(data_set)
#>                AAPL   AMD      ADI     ABBV      AET        A      APD
#> 2017-12-21 173.0230 10.89 87.35595 95.24335 179.2424 67.05882 158.9106
#> 2017-12-22 173.0230 10.54 87.55302 95.53518 178.4787 66.88999 159.1638
#> 2017-12-26 168.6334 10.46 87.33624 95.08771 178.9349 66.79068 158.7548
#> 2017-12-27 168.6631 10.53 87.79938 95.41844 179.3614 66.84033 159.4073
#> 2017-12-28 169.1377 10.55 88.07529 95.12663 179.7383 66.98931 160.3325
#> 2017-12-29 167.3086 10.28 87.73040 94.07604 178.9052 66.65984 160.7342
#>               AA       CF
#> 2017-12-21 48.99 40.37555
#> 2017-12-22 49.99 40.82579
#> 2017-12-26 50.38 41.94162
#> 2017-12-27 51.84 42.15696
#> 2017-12-28 54.14 41.70672
#> 2017-12-29 53.87 41.63820

SP500_index <- Ad(getSymbols("^GSPC", from = begin_date, to = end_date, auto.assign = FALSE))
colnames(SP500_index) <- "index"
head(SP500_index)
#>              index
#> 2016-01-04 2012.66
#> 2016-01-05 2016.71
#> 2016-01-06 1990.26
#> 2016-01-07 1943.09
#> 2016-01-08 1922.03
#> 2016-01-11 1923.67
plot(SP500_index)