library(tidyverse)
stock_panel <- read_csv("stock_panel.csv")
stock_panel
smb <- stock_panel %>%
arrange(permno, date) %>%
group_by(permno) %>%
mutate(
market_cap = abs(prc) * shrout,
lag_market_cap = lag(market_cap)
) %>%
ungroup() %>%
drop_na(lag_market_cap) %>%
group_by(date) %>%
mutate(
size = if_else(
lag_market_cap < median(lag_market_cap, na.rm = T),
"small", "big")
) %>%
ungroup() %>%
group_by(date, size) %>%
summarize(portfolio_return = mean(ret, na.rm = T)) %>%
ungroup() %>%
pivot_wider(names_from = size, values_from = portfolio_return) %>%
mutate(smb = small - big)
smb15 Fama-French Three-Factor Model (1992)
Parts 1-2 of this assignment are done on paper. Part 3 will be completed in R.
CAPM had us estimate: \(r_a - r_f = \alpha + \beta (r_m - r_f)\), where \(r_a\) is the return for a stock, \(r_f\) is the risk-free rate at that time, and \(r_m\) is the overall average market return.
CAPM says only market beta should predict returns: if two stocks are equally risky (as measured by exposure to market-level risk), they should earn the same return on average. That is, CAPM alpha should be 0.
But data doesn’t back this up. When we estimate the CAPM, more often then not, we get nonzero alpha. There are many, many risk factors a stock could be exposed to, not just \(r_m\) (overall market risk). If we omit those risk factors, CAPM will have omitted variable bias.
The Fama-French Three-Factor Model (1992) is a response to this issue. It adds two more risk factors to the CAPM model:
- Outperformance of small versus big companies (SMB: small minus big)
- Outperformance of high book to market versus low book to market companies (HML: high minus low)
So the Fama-French model: \[r_a - r_f = \alpha + \beta (r_m - r_f) + b_s \cdot SMB + b_v \cdot HML\]
Where \(\beta\) measures exposure to overall market risk, \(b_s\) measures exposure to the SMB risk factor, and \(b_v\) measures exposure to the HML risk factor.
SMB: \(r_{small} - r_{big}\). This factor measures how much small companies have outperformed larger companies in the given time period. If a stock has a large positive \(b_s\), its returns are high when small firms are outperforming large ones, and low when small firms are not doing so well comparatively. So you can interpret \(b_s\) as how much a stock behaves like a small company.
HML: \(r_{high\ book \ to \ market} - r_{low\ book \ to \ market}\). The book-to-market ratio compares: \(\frac{Book\ Value \ of \ Equity}{Market \ Value\ of \ Equity}\). The book value is the accounting value of the company from its balance sheet. The market value is the stock market value of the company, measured by \(Price \ per \ Share \times \ Shares \ Outstanding\).
- High book-to-market firms: their market value is low and their book value is high. If market value is low, that means investors don’t expect much growth from the company. If book value is high, that means the firm has a large amount of accounting equity: lots of factories, equipment, cash, inventory, or land relative to its debts. High book-to-market firms are called “value stocks”.
- Low book-to-market firms: their market value is high and their book value is low. If market value is high, that means investors expect a lot of growth (these are called “growth stocks”). If book value is low, that means that the firm doesn’t have much accounting equity, or if it does, it’s also in a lot of debt.
So if a stock has a positive Fama-French \(b_v\) coefficient, that means the stock behaves like a high book-to-market firm (a value stock). If a stock has a negative Fama-French \(b_v\), the stock behaves like a growth stock.
Part 1: Constructing SMB (Small Minus Big)
To see how these Fama-French risk factors are calculated, let’s build our own simple SMB variable.
SMB is calculated for each time period. It asks, what are the average returns for small firms? And what are the average returns for large firms? And then it subtracts the two.
\[ SMB = r_{small} - r_{big} \]
If SMB is positive, small firms outperformed big firms that month.
If SMB is negative, big firms outperformed small firms that month.
Question 1: sketch what the tibble should look like after the first mutate call. mutate(market_cap = abs(prc) * shrout, lag_market_cap = lag(market_cap))
Question 2: sketch what the tibble should look like after the second mutate call. mutate(size = if_else(lag_market_cap < median(lag_market_cap, na.rm = T), "small", "big"))
Question 3: sketch what the tibble should look like after the summarize call. summarize(portfolio_return = mean(ret, na.rm = T))
Question 4: Historically, SMB is positive: small firms outperform big ones. What does the query below say about the stock market since 2010?
smb %>%
group_by(date = if_else(date > ymd(20100101), "after 2010", "before 2010")) %>%
summarize(avg_smb = mean(smb, na.rm = T))Question 5: Write code to visualize SMB over time.
Part 2: Estimate CAPM versus the Fama-French 3 Factor Model
We’ll use Kenneth French’s official Mkt-RF, SMB, and HML.
library(frenchdata)
fama <- download_french_data('Fama/French 3 Factors')$subsets$data[[1]] %>%
rename(mkt_rf = `Mkt-RF`) %>%
mutate(
date = ym(date),
across(c(mkt_rf, SMB, HML, RF), ~ .x / 100)
)
joined_data <- stock_panel %>%
mutate(date = floor_date(date, unit = "month")) %>%
left_join(fama, join_by(date))Here we compare CAPM to the Fama-French 3 Factor model for Apple’s stock (permno 14593):
joined_data %>%
filter(permno == 14593)
joined_data %>%
filter(permno == 14593) %>%
lm(ret - RF ~ mkt_rf, data = .) %>%
broom::tidy()
joined_data %>%
filter(permno == 14593) %>%
lm(ret - RF ~ mkt_rf + SMB + HML, data = .) %>%
broom::tidy()Question 6: Fill in the blanks to interpret Apple’s CAPM versus Fama-French 3 Factor:
- Apple has a CAPM beta of _________ and a Fama-French beta of _________: the coefficients are consistent and they both show Apple is riskier than the S&P500 when it comes to market-level risk.
- Apple has a Fama-French SMB loading of _________, which indicates that Apple stock behaves more like a (big/small) firm, although the coefficient (is/is not) statistically significantly different from 0.
- Apple has a Fama-French HML loading of _________, which indicates that Apple stock behaves more like a (growth/value) stock. This coefficient (is/is not) statistically significant.
- Apple’s CAPM alpha is _________ and Apple’s Fama-French alpha is _________, and both (are/are not) statistically significantly different from zero. This indicates Apple may still have some omitted risk factors beyond what mkt_rf, SMB, and HML are able to account for.
Part 3: Comparing CAPM vs Fama-French for these 12 Stocks
Your goal: use map() to estimate CAPM versus the Fama-French 3 Factor model for 12 stocks in the data set.
map() should return a tibble that looks like this:
| comnam | permno | CAPM beta | FF beta | CAPM alpha | FF alpha | SMB loading | HML loading |
|---|---|---|---|---|---|---|---|
| Microsoft | 10107 | ||||||
| Amazon | 84788 | ||||||
| Tesla | 93436 | ||||||
| NVIDIA | 86580 | ||||||
| 13407 | |||||||
| McDonalds | 43449 | ||||||
| Coca Cola | 11995 | ||||||
| Netflix | 89393 | ||||||
| Nike | 57665 | ||||||
| Walmart | 55976 | ||||||
| Costco | 87055 | ||||||
| Starbucks | 77702 |
Question 7: Fill in the blanks to estimate CAPM and FF3 for each of these stocks.
factor_loadings <- map(
.x = c(10107, 84788, 93436, 86580, 13407, 43449, 11995,
89393, 57665, 55976, 87055, 77702),
.f = function(p) {
data <- joined_data %>%
filter(_______________________)
capm_results <- data %>%
lm(_______________________, data = .) %>%
broom::tidy()
ff_results <- data %>%
lm(_______________________, data = .) %>%
broom::tidy()
data %>%
slice(1) %>%
select(permno, comnam) %>%
mutate(
capm_beta = capm_results %>% filter(term == "mkt_rf") %>% pull(estimate),
ff_beta = ______________________________________________,
capm_alpha = ______________________________________________,
ff_alpha = ______________________________________________,
smb_loading = ______________________________________________,
hml_loading = ______________________________________________
)
}
) %>%
bind_rows()
# Interpretation questions: answer these questions in R after you've
# run the map() analysis.
# Which 3 stocks have the highest exposure to market-level risk according to CAPM?
factor_loadings %>% arrange(___________) %>% slice(1:3)
# What about according to Fama-French?
factor_loadings %>% arrange(___________) %>% slice(1:3)
# Which 3 stocks have the highest SMB loading (which behaves most like a small company)?
factor_loadings %>% arrange(___________) %>% slice(1:3)
# Which 3 stocks have the lowest SMB loading (which behaves most like a large company)?
factor_loadings %>% arrange(___________) %>% slice(1:3)
# Which 3 stocks have the highest HML loading (which behaves most like a value company)?
factor_loadings %>% arrange(___________) %>% slice(1:3)
# Which 3 stocks have the lowest HML loading (which behaves most like a growth company)?
factor_loadings %>% arrange(___________) %>% slice(1:3)
# Which 5 stocks have the largest CAPM alpha? Did controlling for SMB and HML help bring alpha down for these stocks?
factor_loadings %>% arrange(___________) %>% slice(1:5)Download this assignment
Here’s a link to download this assignment.