Introduction to Fama French

Introduction to Fama French

This is my note for learning Introduction to Fama French.

Today, we will be workding with our usual portfolio consisting of:

  • SPY (S&P500 fund) weighted 25%
  • EFA (a small-cap value fund) weighted 25%
  • IJS (a small-cap value fund) weighted 20%
  • EEM (a emerging-mkts fund) weighted 20%
  • AGG (a bond fund) weighted 10%

Preparing Data

R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
library(tidyquant)
library(tidyverse)
library(timetk)
library(broom)
library(glue)

symbols <- c("SPY", "EFA", "IJS", "EEM", "AGG")

prices <- getSymbols(symbols,
src = "yahoo",
from = "2012-12-31",
to = "2019-11-02",
auto.assign = TRUE,
warnings = FALSE) %>%
map(~Ad(get(.))) %>%
reduce(merge) %>%
`colnames<-`(symbols)

w <- c(0.25, 0.25, 0.20, 0.20, 0.10)

asset_returns_long <- prices %>%
to.monthly(indexAt = "lastof", OHLC = FALSE) %>%
tk_tbl(preserve_index = TRUE, rename_index = "date") %>%
gather(asset, returns, -date) %>%
group_by(asset) %>%
mutate(returns = (log(returns) - log(dplyr::lag(returns)))) %>%
na.omit()

portfolio_returns_tq_rebalanced_monthly <- asset_returns_long %>%
tq_portfolio(
assets_col = asset,
returns_col = returns,
weights = w,
col_rename = "returns",
rebalance_on = "months"
)
portfolio_returns_tq_rebalanced_monthly

#> # A tibble: 83 x 2
#> date returns
#> <date> <dbl>
#> 1 2013-01-31 0.0308
#> 2 2013-02-28 -0.000870
#> 3 2013-03-31 0.0187
#> 4 2013-04-30 0.0206
#> 5 2013-05-31 -0.00535
#> 6 2013-06-30 -0.0229
#> 7 2013-07-31 0.0412
#> 8 2013-08-31 -0.0255
#> 9 2013-09-30 0.0544
#> 10 2013-10-31 0.0352
#> # … with 73 more rows

Importing and Wrangling the Fama French Factors

R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
temp <- tempfile()
base <- "http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/"
factor <- "Global_3_Factors"
format <- "_CSV.zip"
full_url <- glue(base, factor, format, sep = "")
download.file(full_url, temp, quiet = TRUE)
(Global_3_Factors <- read_csv(
unz(temp, "Global_3_Factors.csv"),
skip = 6, col_types = cols(
`Mkt-RF` = col_double(),
SMB = col_double(),
HML = col_double(),
RF = col_double()
)) %>%
rename(date = X1) %>%
mutate_at(vars(-date), as.numeric) %>%
# roll back one day
mutate(date = rollback(ymd(parse_date_time(date, "%Y%m") + months(1)))) %>%
dplyr::filter(date >= first(portfolio_returns_tq_rebalanced_monthly$date) & date <=
last(portfolio_returns_tq_rebalanced_monthly$date)))

ff_portfolio_returns <-
portfolio_returns_tq_rebalanced_monthly %>%
left_join(Global_3_Factors, by = "date") %>%
dplyr::filter(!is.na(SMB)) %>%
mutate(MKT_RF = Global_3_Factors$`Mkt-RF`/100,
SMB = Global_3_Factors$SMB/100,
HML = Global_3_Factors$HML/100,
RF = Global_3_Factors$RF/100,
R_excess = round(returns - RF, 4))
ff_portfolio_returns

#> # A tibble: 78 x 8
#> date returns `Mkt-RF` SMB HML RF MKT_RF
#> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-01-31 3.08e-2 5.46 0.0017 2.01e-2 0 0.0546
#> 2 2013-02-28 -8.70e-4 0.09 0.00350 -7.60e-3 0 0.0009
#> 3 2013-03-31 1.87e-2 2.29 0.0085 -2.02e-2 0 0.0229
#> 4 2013-04-30 2.06e-2 3.02 -0.0113 9.00e-3 0 0.0302
#> 5 2013-05-31 -5.35e-3 0.56 -0.0066 9.70e-3 0 0.0056
#> 6 2013-06-30 -2.29e-2 -2.52 0.0021 -6.00e-4 0 -0.0252
#> 7 2013-07-31 4.12e-2 5.58 0.0017 3.50e-3 0 0.0558
#> 8 2013-08-31 -2.55e-2 -1.83 0.0122 -6.60e-3 0 -0.0183
#> 9 2013-09-30 5.44e-2 5.52 0.0222 -5.40e-3 0 0.0552
#> 10 2013-10-31 3.52e-2 3.71 -0.0175 1.97e-2 0 0.0371
#> # … with 68 more rows, and 1 more variable: R_excess <dbl>
#> > ff_portfolio_returns
#> # A tibble: 78 x 8
#> date returns `Mkt-RF` SMB HML RF MKT_RF R_excess
#> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-01-31 0.0308 5.46 0.0017 0.0201 0 0.0546 0.0308
#> 2 2013-02-28 -0.000870 0.09 0.00350 -0.0076 0 0.0009 -0.0009
#> 3 2013-03-31 0.0187 2.29 0.0085 -0.0202 0 0.0229 0.0187
#> 4 2013-04-30 0.0206 3.02 -0.0113 0.009 0 0.0302 0.0206
#> 5 2013-05-31 -0.00535 0.56 -0.0066 0.0097 0 0.0056 -0.0054
#> 6 2013-06-30 -0.0229 -2.52 0.0021 -0.000600 0 -0.0252 -0.0229
#> 7 2013-07-31 0.0412 5.58 0.0017 0.00350 0 0.0558 0.0412
#> 8 2013-08-31 -0.0255 -1.83 0.0122 -0.0066 0 -0.0183 -0.0255
#> 9 2013-09-30 0.0544 5.52 0.0222 -0.0054 0 0.0552 0.0544
#> 10 2013-10-31 0.0352 3.71 -0.0175 0.0197 0 0.0371 0.0352
#> # … with 68 more rows
R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ff_dplyr_byhand <- ff_portfolio_returns %>% 
dplyr::do(model = lm(R_excess ~ MKT_RF + SMB + HML, data = .)) %>%
tidy(model, conf.int = T, conf.level = 0.95)

ff_dplyr_byhand %>%
mutate_if(is.numeric, ~round(., 3)) %>%
select(-statistic) %>%
dplyr::filter(term != "(Intercept)") %>%
ggplot(aes(term, estimate, shape = term, color = term)) +
geom_point() +
geom_errorbar(aes(ymin = conf.low, ymax = conf.high)) +
labs(title = "Fama French 3-Factor Coefficients for Our Portfolio",
subtitle = "nothing in this post is investment advice",
x = "",
y = "coefficient",
caption = "Data Source: Fama French website and yahoo! Finance") +
scale_color_tq()

# R

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×