Factor Analysis using the CAPM and Fama-French Factor models

The main idea in Factor Analysis is to take a set of observed returns and decompose it into a set of explanatory returns. We'll follow Asset Management (Ang 2014, Oxford University Press) Chapter 10 and analyze the returns of Berkshire Hathaway. First, we'll need the returns of Berkshire Hathaway which are contained in data/brka_d_rets.csv. Read it in as follows:

In [14]:
%matplotlib inline
import PortfolioAnalytics as PortfolioAnalytics
import PortfolioLoadData as PortfolioLoadData
import PortfolioRisk as PortfolioRisk
import PortfolioStatistics as PortfolioStatistics
import PortfolioBacktest as PortfolioBacktest

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm

%load_ext autoreload
%autoreload 2
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload
In [15]:
# load and transform Berkshire Hathaway A to monthly returns
brka_d = pd.read_csv("data/brka_d_ret.csv", parse_dates=True, index_col=0)
brka_m = brka_d.resample('M').apply(PortfolioStatistics.compound).to_period('M')
# write the resampled time series to disk
brka_m.to_csv("./data/brka_m.csv")
brka_m.head()
Out[15]:
BRKA
DATE
1990-01 -0.140634
1990-02 -0.030852
1990-03 -0.069204
1990-04 -0.003717
1990-05 0.067164

Next, we need to load the explanatory variables, which is the Fama-French monthly returns data set. This was part of their original 1993 paper: The Fama and French model has three factors: size of firms, book-to-market values and excess return on the market. In other words, the three factors used are SMB (small minus big), HML (high minus low) and the portfolio's return less the risk free rate of return.

Later on in 2014 came their extended version: the 5-factor Model: 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. (See the description of the 6 size/book-to-market, size/operating profitability, size/investment portfolios.)

However we will stick to the original 3-factor model. Load that as follows:

In [16]:
fff = PortfolioLoadData.get_fff_returns()
fff.head()
Out[16]:
Mkt-RF SMB HML RF
1926-07 0.0296 -0.0230 -0.0287 0.0022
1926-08 0.0264 -0.0140 0.0419 0.0025
1926-09 0.0036 -0.0132 0.0001 0.0023
1926-10 -0.0324 0.0004 0.0051 0.0032
1926-11 0.0253 -0.0020 -0.0035 0.0031

Next, we need to decompose the observed BRKA 1990-May 2012 as in Ang(2014) into the portion that's due to the market and the rest that is not due to the market, using the CAPM as the explanatory model.

i.e.

$$ R_{brka,t} - R_{f,t} = \alpha + \beta(R_{mkt,t} - R_{f,t}) + \epsilon_t $$

We can use the stats.api for the linear regression as follows:

In [17]:
brka_excess = brka_m["1990":"2012-05"] - fff.loc["1990":"2012-05", ['RF']].values
mkt_excess = fff.loc["1990":"2012-05",['Mkt-RF']]
exp_var = mkt_excess.copy()
exp_var["Constant"] = 1
lm = sm.OLS(brka_excess, exp_var).fit()
In [18]:
# Single regression market model
lm.summary()
Out[18]:
OLS Regression Results
Dep. Variable: BRKA R-squared: 0.154
Model: OLS Adj. R-squared: 0.150
Method: Least Squares F-statistic: 48.45
Date: Thu, 10 Oct 2019 Prob (F-statistic): 2.62e-11
Time: 11:00:05 Log-Likelihood: 388.47
No. Observations: 269 AIC: -772.9
Df Residuals: 267 BIC: -765.7
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Mkt-RF 0.5402 0.078 6.961 0.000 0.387 0.693
Constant 0.0061 0.004 1.744 0.082 -0.001 0.013
Omnibus: 45.698 Durbin-Watson: 2.079
Prob(Omnibus): 0.000 Jarque-Bera (JB): 102.573
Skew: 0.825 Prob(JB): 5.33e-23
Kurtosis: 5.535 Cond. No. 22.2


Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

The CAPM benchmark interpretation

This implies that the CAPM benchmark consists of 46 cents in T-Bills and 54 cents in the market. i.e. each dollar in the Berkshire Hathaway portfolio is equivalent to 46 cents in T-Bills and 54 cents in the market. Relative to this, the Berkshire Hathaway is adding (i.e. has 𝛼 of) 0.61% (per month!) although the degree of statistica significance is not very high. Now, let's add in some additional explanatory variables, namely Value and Size.

In [19]:
exp_var["Value"] = fff.loc["1990":"2012-05",['HML']]
exp_var["Size"] = fff.loc["1990":"2012-05",['SMB']]
exp_var.head()
Out[19]:
Mkt-RF Constant Value Size
1990-01 -0.0785 1 0.0087 -0.0129
1990-02 0.0111 1 0.0061 0.0103
1990-03 0.0183 1 -0.0290 0.0152
1990-04 -0.0336 1 -0.0255 -0.0050
1990-05 0.0842 1 -0.0374 -0.0257
In [20]:
# Multiple Linear Regression:
lm = sm.OLS(brka_excess, exp_var).fit()
lm.summary()
Out[20]:
OLS Regression Results
Dep. Variable: BRKA R-squared: 0.290
Model: OLS Adj. R-squared: 0.282
Method: Least Squares F-statistic: 36.06
Date: Thu, 10 Oct 2019 Prob (F-statistic): 1.41e-19
Time: 11:00:05 Log-Likelihood: 412.09
No. Observations: 269 AIC: -816.2
Df Residuals: 265 BIC: -801.8
Df Model: 3
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Mkt-RF 0.6761 0.074 9.155 0.000 0.531 0.821
Constant 0.0055 0.003 1.679 0.094 -0.001 0.012
Value 0.3814 0.109 3.508 0.001 0.167 0.595
Size -0.5023 0.101 -4.962 0.000 -0.702 -0.303
Omnibus: 42.261 Durbin-Watson: 2.146
Prob(Omnibus): 0.000 Jarque-Bera (JB): 67.954
Skew: 0.904 Prob(JB): 1.75e-15
Kurtosis: 4.671 Cond. No. 37.2


Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

The Fama-French Benchmark Interpretation

The alpha has fallen from .61% to about 0.55% per month. The loading on the market has moved up from 0.54 to 0.67, which means that adding these new explanatory factors did change things. If we had added irrelevant variables, the loading on the market would be unaffected.

We can interpret the loadings on Value being positive as saying that Hathaway has a significant Value tilt - which should not be a shock to anyone that follows Buffet. Additionally, the negative tilt on size suggests that Hathaway tends to invest in large companies, not small companies.

In other words, Hathaway appears to be a Large Value investor. Of course, you knew this if you followed the company, but the point here is that numbers reveal it!

The new way to interpret each dollar invested in Hathaway is (the coefficients):

* 67 % in the market, 33 % in Bills, 
* 38 % in Value stocks and short 38 % in Growth stocks, 
* 50 % in LargeCap stocks and short 50 % in SmallCap stocks. 

If you did all this, you would still end up underperforming Hathaway by about 55 basis points per month.

In [ ]: