The 3 steps to factor risk analysis
The 3 steps to factor risk analysis
The 3 steps to factor risk analysis
In today’s newsletter, I’m going to show you how to use a factor model to figure out a portfolio’s exposure to those factors.
In previous newsletters, you learned how to hedge beta and use principal component analysis to analyze factors. Quants use factors to target specific drivers of returns and manage risk. Diversification is great until the entire market declines in value. That’s because the market influences all stocks. Factors can offset some of these risks by targeting drivers of return not influenced by the market.
Common factors are size (large-cap versus small-cap) and style (value versus growth). If you think small-cap stocks will outperform large-cap stocks, then you might want exposure to small-cap stocks. If you think value stocks will outperform growth stocks, then you might want exposure to value stocks. In either case, you want to measure the risk contribution of the factor.
Use the Fama-French factor model to measure risk exposure
Eugene Fama and Kenneth French built the Fama-French three-factor model in 1992. It's a popular factor model you can use for free. The model includes size, style, and excess returns. You can read about the model on Kenneth French’s website. For this analysis, I will show you how to use the size and style factors.
By the end of this newsletter, you will be able to:
• Download historic factor data
• Compute the sensitivities to the factors
• Figure out the risk contribution of the factors
All with Python.
Step 1: Download historic factor data
First, import the libraries. You can use pandas_datareader
to download the factor data and yfinance
to download stock price data. Use statsmodels
for modeling.
1import numpy as np
2import pandas as pd
3
4import pandas_datareader as pdr
5import yfinance as yf
6
7import statsmodels.api as sm
8from statsmodels import regression
9from statsmodels.regression.rolling import RollingOLS
Download the data.
1factors = pdr.get_data_famafrench(
2 'F-F_Research_Data_Factors',
3 start='2000-01-01'
4)[0][1:]
5
6SMB = factors.SMB
7HML = factors.HML
SMB
is “small minus big” representing the size factor. HML
is “high minus low” representing the style factor. This also downloads a third factor, Rm-Rf
, which is the market excess return. I only use SMB
and HML
for this analysis.
Now get the stock price data for your portfolio. You can pick any stocks you want. (Make sure to include a benchmark like SPY.)
1data = yf.download(
2 ['SPY', 'MSFT', 'AAPL', 'INTC'],
3 start="2000-01-01",
4 interval="1mo"
5)['Adj Close']
6
7monthly_returns = data.pct_change().to_period("M")
The factor data is monthly so to align with the stock data, you need to get monthly closing prices and resample to monthly labels. pandas makes it easy.
Step 2: Compute the sensitivities to the factors
Next, compute the active return of the portfolio. The active return is the portfolio return minus the benchmark return.
bench = monthly_returns.pop("SPY")
R = monthly_returns.mean(axis=1)
active = R - bench
“Pop” the benchmark return off the returns data frame. Then, calculate the portfolio returns and subtract the benchmark.
Use regression to compute the sensitivities to the factors.
df = pd.DataFrame({
'R': active,
'F1': SMB,
'F2': HML,
}).dropna()
b1, b2 = regression.linear_model.OLS(
df.R,
df[['F1', 'F2']]
).fit().params
print(f'Sensitivities of active returns to factors:\nSMB: {b1}\nHML: {b2}')
Put the active returns and factors into a DataFrame to make it easy to align the dates. Then run a regression with the active returns as the dependent variable on the factors. Fitting the model gives you the two coefficients that determine the sensitivities of the portfolio’s active returns to the factors.
The sensitivities are estimates so it’s important to see how they evolve through time with their confidence intervals.
1exog_vars = ["SMB", "HML"]
2exog = sm.add_constant(factors[exog_vars])
3rols = RollingOLS(df.R, exog, window=12)
4rres = rols.fit()
5fig = rres.plot_recursive_coefficient(variables=exog_vars)
The sensitivities tell you how much the active portfolio returns change in response to changes in the factors. In other words, how the factors drive the active portfolio returns.
Step 3: Figure out the risk contribution of the factors
Marginal Contribution To Active Risk (MCTAR) measures the incremental active risk each additional factor introduces to your portfolio.
1F1 = df.F1
2F2 = df.F2
3
4cov = np.cov(F1, F2)
5ar_squared = (active.std())**2
6mcar1 = (b1 * (b2 * cov[0,1] + b1 * cov[0,0])) / ar_squared
7mcar2 = (b2 * (b1 * cov[0,1] + b2 * cov[1,1])) / ar_squared
8print (f'SMB risk contribution: {mcar1}')
9print (f'HML risk contribution: {mcar2}')
10print (f'Unexplained risk contribution: {1 - (mcar1 + mcar2)}')
To figure out the factors' MCTAR, multiply the factor sensitivity by the covariance between the factors. Then divide by the standard deviation of the active returns, squared.
This tells you how much risk you take on by being exposed to each factor given the other factors you’re already exposed to. The unexplained risk contribution is the exposure you have to other factors outside of the two you analyzed.
You can use this analysis to increase or decrease your exposure to these factors. You would do this by under- or overweighting the stocks that represent these factors (e.g. large cap or value).