6.9 KiB
This code performs a multifactor analysis on monthly stock returns, applying the Fama-French three-factor model for financial analysis. It fetches historical factor data, calculates active returns of selected stocks, and estimates their sensitivities to the Fama-French factors. The code also performs rolling regression to analyze the stability of factor exposures over time. Lastly, it calculates and prints the marginal contributions to risk from each factor.
import numpy as np import pandas as pd
import pandas_datareader as pdr import yfinance as yf
import statsmodels.api as sm from statsmodels import regression from statsmodels.regression.rolling import RollingOLS
Fetch Fama-French factors data starting from 2000-01-01 and select the SMB and HML factors
factors = pdr.get_data_famafrench( 'F-F_Research_Data_Factors', start='2000-01-01' )[0][1:]
SMB = factors.SMB HML = factors.HML
Download monthly adjusted close prices for specified stocks starting from 2000-01-01
data = yf.download( ['SPY', 'MSFT', 'AAPL', 'INTC'], start="2000-01-01", interval="1mo" )['Adj Close']
Calculate the monthly returns and convert them to period-based returns
monthly_returns = data.pct_change().to_period("M")
Extract the benchmark returns (SPY) and calculate active returns against the benchmark
bench = monthly_returns.pop("SPY") R = monthly_returns.mean(axis=1) active = R - bench
Create a DataFrame with active returns and Fama-French factors SMB and HML
df = pd.DataFrame({ 'R': active, 'F1': SMB, 'F2': HML, }).dropna()
Perform Ordinary Least Squares (OLS) regression to estimate sensitivities to the factors
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}')
Perform rolling OLS regression to estimate how factor sensitivities change over time
exog_vars = ["SMB", "HML"] exog = sm.add_constant(factors[exog_vars]) rols = RollingOLS(df.R, exog, window=12) rres = rols.fit() fig = rres.plot_recursive_coefficient(variables=exog_vars)
Calculate covariance between factors and marginal contributions to active risk (MCAR) for each factor
F1 = df.F1 F2 = df.F2
cov = np.cov(F1, F2) ar_squared = (active.std())**2 mcar1 = (b1 * (b2 * cov[0,1] + b1 * cov[0,0])) / ar_squared mcar2 = (b2 * (b1 * cov[0,1] + b2 * cov[1,1])) / ar_squared print(f'SMB risk contribution: {mcar1}') print(f'HML risk contribution: {mcar2}') print(f'Unexplained risk contribution: {1 - (mcar1 + mcar2)}')
PyQuant News is where finance practitioners level up with Python for quant finance, algorithmic trading, and market data analysis. Looking to get started? Check out the fastest growing, top-selling course to get started with Python for quant finance. For educational purposes. Not investment advise. Use at your own risk.
