Fama-French Five Factor Model is an extension of the classic CAPM to include SMB (Small Minus Big), HML (High Minus Low), RMW (Robust Minus Weak), and CMA (Conservative Minus Aggressive).
The Fama/French 5 factors (2x3) are constructed using the 6 value-weight portfolios formed on size and book-to-market, the 6 value-weight portfolios formed on size and operating profitability, and the 6 value-weight portfolios formed on size and investment.
The five factors daily data is from the link here: http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html, you can also download it directly through the link.
Here I import the data from the unfolded zip file,
library(readr)
ffd <- read_csv("F-F_Research_Data_5_Factors_2x3_daily.CSV", skip = 3)
head(ffd, 5)
## # A tibble: 5 × 7
## ...1 `Mkt-RF` SMB HML RMW CMA RF
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 19630701 -0.67 0.01 -0.35 0.03 0.11 0.012
## 2 19630702 0.79 -0.31 0.24 -0.08 -0.25 0.012
## 3 19630703 0.63 -0.16 -0.09 0.13 -0.24 0.012
## 4 19630705 0.4 0.09 -0.26 0.07 -0.28 0.012
## 5 19630708 -0.63 0.07 -0.19 -0.27 0.06 0.012
Change the first column’s name.
colnames(ffd)[1] <- "Date"
head(ffd, 5)
## # A tibble: 5 × 7
## Date `Mkt-RF` SMB HML RMW CMA RF
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 19630701 -0.67 0.01 -0.35 0.03 0.11 0.012
## 2 19630702 0.79 -0.31 0.24 -0.08 -0.25 0.012
## 3 19630703 0.63 -0.16 -0.09 0.13 -0.24 0.012
## 4 19630705 0.4 0.09 -0.26 0.07 -0.28 0.012
## 5 19630708 -0.63 0.07 -0.19 -0.27 0.06 0.012
Here I use the Amazon stock price data as an example. It is downloaded through the quantmod package.
library(quantmod)
amazon <- getSymbols("AMZN", from="2010-01-01", to="2022-08-01", auto.assign = F)
Calculate the daily return.
amazon$return1 <- dailyReturn(amazon$AMZN.Close, type = "log")
Or we can use this to get the exactly the same result.
amazon$return2 <- (amazon$AMZN.Close-stats::lag(amazon$AMZN.Close))/stats::lag(amazon$AMZN.Close)
head(amazon[, 7:8], 5)
## return1 return2
## 2010-01-04 0.000000000 NA
## 2010-01-05 0.005882589 0.005899925
## 2010-01-06 -0.018281771 -0.018115673
## 2010-01-07 -0.017159620 -0.017013233
## 2010-01-08 0.026716829 0.027076923
amazon_ret <- amazon$return1
amazon_ret2 <- fortify.zoo(amazon_ret)
colnames(amazon_ret2)[1] <- "Date"
library(lubridate)
ffd$Date <- ymd(ffd$Date)
library(tidyverse)
data_merged <- left_join(amazon_ret2, ffd, by="Date")
head(data_merged, 5)
## Date return1 Mkt-RF SMB HML RMW CMA RF
## 1 2010-01-04 0.000000000 1.69 0.79 1.13 -0.18 0.21 0
## 2 2010-01-05 0.005882589 0.31 -0.41 1.24 -0.20 0.19 0
## 3 2010-01-06 -0.018281771 0.13 -0.13 0.57 -0.05 0.20 0
## 4 2010-01-07 -0.017159620 0.40 0.25 0.98 -0.69 0.22 0
## 5 2010-01-08 0.026716829 0.33 0.32 0.01 0.22 -0.37 0
Plot the return
library(ggplot2)
p1 <- ggplot(amazon_ret2[-1, ], aes(x=Date, y=return1))
p1 + geom_line(color="steelblue")
Density plot with normal density curve
p2 <- ggplot(amazon_ret2)
p2 + geom_histogram(mapping = aes(x=return1, y=..density..), binwidth=0.005, color="steelblue", fill="grey", size=1) +
stat_function(fun = dnorm, args = list(mean = mean(amazon_ret2$return1, na.rm = T), sd = sd(amazon_ret2$return1, na.rm = T)), size=1)
names(data_merged)[3] <- "Mkt.RF"
fit <- lm(return1 ~ SMB + HML + CMA + Mkt.RF + RMW, data = data_merged)
fit2 <- lm(return1 ~ SMB + HML + CMA + Mkt.RF, data = data_merged)
library(stargazer)
stargazer(fit, fit2, title = "Fama-French Five Factor Regression OLS", type="text")
##
## Fama-French Five Factor Regression OLS
## =======================================================================
## Dependent variable:
## ---------------------------------------------------
## return1
## (1) (2)
## -----------------------------------------------------------------------
## SMB -0.002*** -0.002***
## (0.0005) (0.0005)
##
## HML -0.004*** -0.004***
## (0.0005) (0.0005)
##
## CMA -0.009*** -0.009***
## (0.001) (0.001)
##
## Mkt.RF 0.011*** 0.011***
## (0.0003) (0.0003)
##
## RMW 0.00000
## (0.001)
##
## Constant 0.0004 0.0004
## (0.0003) (0.0003)
##
## -----------------------------------------------------------------------
## Observations 3,145 3,145
## R2 0.453 0.453
## Adjusted R2 0.452 0.452
## Residual Std. Error 0.015 (df = 3139) 0.015 (df = 3140)
## F Statistic 519.464*** (df = 5; 3139) 649.537*** (df = 4; 3140)
## =======================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01
Plot the regression
par(mar = c(2, 2, 2, 2))
par(mfrow = c(2, 2))
plot(fit)
par(mar = c(2, 2, 2, 2))
par(mfrow = c(2, 2))
plot(fit2)