<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/introduction-to-fama-french/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://rviews.rstudio.com/2018/04/11/introduction-to-fama-french/"> R Views</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>In two previous posts, we <a rel="nofollow" href="https://rviews.rstudio.com/2018/02/08/capm-beta/" target="_blank">calculated</a> and then <a rel="nofollow" href="https://rviews.rstudio.com/2018/03/02/capm-and-visualization/" target="_blank">visualized</a> the CAPM beta of a portfolio by fitting a simple linear model.</p>
<p>Today, we move beyond CAPM’s simple linear regression and explore the Fama French (FF) multi-factor model of equity risk/return. For more background, have a look at the original article published in <em>The Journal Financial Economics</em>, <a rel="nofollow" href="https://www.sciencedirect.com/science/article/pii/0304405X93900235" target="_blank">Common risk factors in the returns on stocks and bonds</a>.</p>
<p>The FF model extends CAPM by regressing portfolio returns on several variables, in addition to market returns. From a general data science point of view, FF extends CAPM’s simple linear regression, where we had one independent variable, to a multiple linear regression, where we have numerous independent variables.</p>
<p>We are going to look at the FF 3-factor model, which tests the explanatory power of (1) market returns (same as CAPM), (2) firm size (small versus big) and (3) firm value (book to market ratio). The <code>firm value</code> factor is labeled as <code>HML</code> in FF, which stands for high-minus-low and refers to a firm’s book-to-market ratio. When we regress portfolio returns on the <code>HML</code> factor, we are investigating how much of the returns are the result of including stocks with a high book-to-market ratio (sometimes called the <code>value premium</code>, because high book-to-market stocks are called value stocks).</p>
<p>A large portion of this post covers importing data from the FF website and wrangling it for use with our portfolio returns. We will see that wrangling the data is conceptually easy to understand but practically time-consuming to implement. However, mashing together data from disparate sources is a necessary skill for anyone in industry that has data streams from different vendors and wants to get creative about how to use them. Once the data is wrangled, fitting the model is not time-consuming.</p>
<p>Today, we will be working with our usual portfolio consisting of:</p>
<pre><code>+ SPY (S&amp;P500 fund) weighted 25%
+ EFA (a non-US equities fund) weighted 25%
+ IJS (a small-cap value fund) weighted 20%
+ EEM (an emerging-mkts fund) weighted 20%
+ AGG (a bond fund) weighted 10%</code></pre>
<p>Before we can calculate beta for that portfolio, we need to find portfolio monthly returns, which was covered in my previous post, <a rel="nofollow" href="https://rviews.rstudio.com/2017/10/11/from-asset-to-portfolio-returns/" target="_blank">Introduction to Portfolio Returns</a>. I won’t go through the logic again, but the code is here:</p>
<pre><code>library(tidyquant)
library(tidyverse)
library(timetk)
library(broom)
library(glue)

symbols &lt;- c(&quot;SPY&quot;,&quot;EFA&quot;, &quot;IJS&quot;, &quot;EEM&quot;,&quot;AGG&quot;)

prices &lt;- 
  getSymbols(symbols, src = 'yahoo', 
             from = &quot;2012-12-31&quot;,
             to = &quot;2017-12-31&quot;,
             auto.assign = TRUE, warnings = FALSE) %>% 
  map(~Ad(get(.))) %>%
  reduce(merge) %>% 
  `colnames&lt;-`(symbols)

w &lt;- c(0.25, 0.25, 0.20, 0.20, 0.10)

asset_returns_long &lt;-  
  prices %>% 
  to.monthly(indexAt = &quot;lastof&quot;, OHLC = FALSE) %>% 
  tk_tbl(preserve_index = TRUE, rename_index = &quot;date&quot;) %>%
  gather(asset, returns, -date) %>% 
  group_by(asset) %>%  
  mutate(returns = (log(returns) - log(lag(returns)))) %>% 
  na.omit()

portfolio_returns_tq_rebalanced_monthly &lt;- 
  asset_returns_long %>%
  tq_portfolio(assets_col  = asset, 
               returns_col = returns,
               weights     = w,
               col_rename  = &quot;returns&quot;,
               rebalance_on = &quot;months&quot;)</code></pre>
<p>We will be working with one object of portfolio returns:</p>
<pre><code>+ portfolio_returns_tq_rebalanced_monthly</code></pre>
<p>Let’s get to it.</p>
<div>
<h3>Importing and Wrangling the Fama French Factors</h3>
<p>Our first task is to get the FF data and, fortunately, FF make their factor data available on the internet. We will document each step for importing and cleaning this data, to an extent that might be overkill. Frustrating for us now, but a time-saver later when we need to update this model or extend to the 5-factor case.</p>
<p>Have a look at the <a rel="nofollow" href="http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html" target="_blank">FF website</a>. The data are packaged as zip files, so we will need to do a bit more than call <code>read_csv()</code>. Let’s use the <code>tempfile()</code> function from base R to create a variable called <code>temp</code>. This is where we will put the zipped file.</p>
<pre><code>temp &lt;- tempfile()</code></pre>
<p>R has created a temporary file called <code>temp</code> that will be cleaned up when we exit this session. Download 3-factor zip with <a rel="nofollow" href="https://rviews.rstudio.com/2018/04/11/introduction-to-fama-french/" target="_blank">this link</a>. We want to pass that to <code>download.file()</code> and store the result in <code>temp</code>.</p>
<p>First, though, we will break that string into three pieces: <code>base</code>, <code>factor</code> and <code>format</code> – this is not necessary for today’s task, but it will come in handy if we want to build a Shiny application to let a user choose a factor from the FF website, or if we just want to re-run this analysis with a different set of FF factors. We will then <code>glue()</code> those together and save the string as <code>full_url</code>.</p>
<pre><code>base &lt;- 
&quot;http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/&quot;

factor &lt;- 
  &quot;Global_3_Factors&quot;

format&lt;-
  &quot;_CSV.zip&quot;

full_url &lt;-
  glue(base,
        factor,
        format,
        sep =&quot;&quot;)</code></pre>
<p>Now we pass <code>full_url</code> to <code>download.file()</code>.</p>
<pre><code>download.file(
full_url,
temp,
quiet = TRUE)</code></pre>
<p>Finally, we can read the csv file using <code>read_csv()</code> after unzipping that data with the <code>unz()</code> function.</p>
<pre><code>Global_3_Factors &lt;- 
  read_csv(unz(temp, 
               &quot;Global_3_Factors.csv&quot;))

head(Global_3_Factors)  </code></pre>
<pre><code>## # A tibble: 6 x 1
##   `This file was created using the 201802 Bloomberg database.`
##   </code></pre></div>