Follow these steps to implement the rolling three-factor model in Python.
- Import the libraries:
import pandas as pd
import yfinance as yf
import statsmodels.formula.api as smf
import pandas_datareader.data as web
- Define the parameters:
ASSETS = ['AMZN', 'GOOG', 'AAPL', 'MSFT']
WEIGHTS = [0.25, 0.25, 0.25, 0.25]
START_DATE = '2009-12-31'
END_DATE = '2018-12-31'
- Download the factor-related data:
df_three_factor = web.DataReader('F-F_Research_Data_Factors',
'famafrench', start=START_DATE)[0]
df_three_factor = df_three_factor.div(100)
df_three_factor.index = df_three_factor.index.format()
- Download the prices of risky assets from Yahoo Finance:
asset_df = yf.download(ASSETS,
start=START_DATE,
end=END_DATE,
adjusted=True,
progress=False)
- Calculate the monthly returns on the risky assets:
asset_df = asset_df['Adj Close'].resample('M')
.last()
.pct_change()
.dropna()
asset_df.index = asset_df.index.strftime('%Y-%m')
- Calculate the portfolio returns:
asset_df['portfolio_returns'] = np.matmul(asset_df[ASSETS].values,
WEIGHTS)
- Merge the datasets:
ff_data = asset_df.join(df_three_factor).drop(ASSETS, axis=1) ff_data.columns = ['portf_rtn', 'mkt', 'smb', 'hml', 'rf'] ff_data['portf_ex_rtn'] = ff_data.portf_rtn - ff_data.rf
- Define a function for the rolling n-factor model:
def rolling_factor_model(input_data, formula, window_size):
coeffs = []
for start_index in range(len(input_data) - window_size + 1):
end_index = start_index + window_size
ff_model = smf.ols(
formula=formula,
data=input_data[start_index:end_index]
).fit()
coeffs.append(ff_model.params)
coeffs_df = pd.DataFrame(
coeffs,
index=input_data.index[window_size - 1:]
)
return coeffs_df
For a version with a docstring explaining the input/output, please refer to this book's GitHub repository.
- Estimate the rolling three-factor model and plot the results:
MODEL_FORMULA = 'portf_ex_rtn ~ mkt + smb + hml' results_df = rolling_factor_model(ff_data, MODEL_FORMULA, window_size=60) results_df.plot(title = 'Rolling Fama-French Three-Factor model')
Executing the code results in the following plot:
By inspecting the preceding plot, we can see the following:
- The intercept is almost constant and very close to 0.
- There is some variability in the factors, but no sudden reversals or unexpected jumps.