<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/rolling-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/05/10/rolling-fama-french/"> R Views</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p> <br>
<br>


<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>



</p>
<p>In a <a rel="nofollow" href="https://rviews.rstudio.com/2018/04/11/introduction-to-fama-french/" target="_blank">previous post</a>, we reviewed how to import the Fama French 3-Factor data, wrangle that data, and then regress our portfolio returns on the factors. Please have a look at that previous post, as the following work builds upon it. For more background on Fama French, see the original article published in <em>The Journal of 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>Today, we will explore the rolling Fama French model and the explanatory power of the 3 factors in different time periods. In the financial world, we often look at rolling means, standard deviations and models to make sure we haven’t missed anything unusual, risky, or concerning during different market or economic regimes. Our portfolio returns history is for the years 2013 through 2017, which is rather a short history, but there still might a be a 24-month period where the Fama French factors were particularly strong, weak, or meaningless. We would like to unearth and hypothesize about what explains them or their future likelihood.</p>
<p>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 run a Fama French model for that portfolio, we need to find portfolio monthly returns, which was covered in <a rel="nofollow" href="https://rviews.rstudio.com/2017/10/11/from-asset-to-portfolio-returns/" target="_blank">this post</a>. I won’t go through the logic again but the code is here:</p>
<pre><code>library(tidyquant)
library(tidyverse)
library(timetk)


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 also need to import the Fama French factors and combine them into one object with our portfolio returns. We painstakingly covered this in the <a rel="nofollow" href="https://rviews.rstudio.com/2018/04/11/introduction-to-fama-french/" target="_blank">previous post</a> and the code for doing so is here:</p>
<pre><code>temp &lt;- tempfile()

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;)

download.file(
full_url,
temp,
quiet = TRUE)


Global_3_Factors &lt;- 
  read_csv(unz(temp, &quot;Global_3_Factors.csv&quot;), 
           skip = 6) %>% 
  rename(date = X1) %>% 
  mutate_at(vars(-date), as.numeric) %>% 
  mutate(date = 
           rollback(ymd(parse_date_time(date, &quot;%Y%m&quot;) + months(1)))) %>% 
  filter(date >= 
   first(portfolio_returns_tq_rebalanced_monthly$date) &amp; date &lt;= 
   last(portfolio_returns_tq_rebalanced_monthly$date))

ff_portfolio_returns &lt;- 
  portfolio_returns_tq_rebalanced_monthly %>% 
  left_join(Global_3_Factors, by = &quot;date&quot;) %>% 
  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))</code></pre>
<p>We now have one data frame <code>ff_portfolio_returns</code> that holds our Fama French factors and portfolio returns. Let’s get to the rolling analysis.</p>
<p>We first define a rolling model with the <code>rollify()</code> function from <code>tibbletime</code>. However, instead of wrapping an existing function, such as <code>kurtosis()</code> or <code>skewness()</code>, we will pass in our linear Fama French model.</p>
<pre><code># Choose a 24-month rolling window
window &lt;- 24

library(tibbletime)
# define a rolling ff model with tibbletime
rolling_lm &lt;- 
  rollify(.f = function(R_excess, MKT_RF, SMB, HML) {
  lm(R_excess ~ MKT_RF + SMB + HML)
  }, window = window, unlist = FALSE)</code></pre>
<p>Next, we pass columns from <code>ff_portfolio_returns</code> to the rolling function model.</p>
<pre><code>rolling_ff_betas &lt;-
  ff_portfolio_returns %>% 
  mutate(rolling_ff = 
           rolling_lm(R_excess, 
                      MKT_RF, 
                      SMB, 
                      HML)) %>%  
  slice(-1:-23) %>% 
  select(date, rolling_ff)

head(rolling_ff_betas, 3)</code></pre>
<pre><code># A tibble: 3 x 2
  date       rolling_ff
  </code></pre>