def strategy_capm(returns, start_date): """ CAPM using lagged optimal market portfolio tracker to predict company stock return. Positions are assigned as follows: - Buy when predicted return > expected return - Sell when predicted return < expected return - No transaction costs. For now. """ mkt_return = pdr.get_data_famafrench( 'F-F_Research_Data_Factors_daily', start='1-1-2010')[0]['Mkt-RF'] / 100 rf = pdr.get_data_famafrench('F-F_Research_Data_Factors_daily', start='1-1-2010', end=start_date)[0]['RF'] ols_capm = { 'slope': None, 'intercept': None, 'r_value': None, 'p_value': None, 'std_err': None } returns = returns.shift(1) for ret in returns.columns: slope, intercept, r_value, p_value, std_err = linregress( mkt_return, y=returns[ret]) ols_capm['slope'].add(slope) ols_capm['intercept'].add(intercept) ols_capm['r_value'].add(r_value) ols_capm['p_value'].add(p_value) ols_capm['std_err'].add(std_err) return ols_capm
def load_industries(): """Load industry portfolio returns from Ken French's website. Returns ------- industries : dictionary of Pandas DataFrames Each key is a portfolio group. Example ------- >>> from pyfinance import datasets >>> ind = datasets.load_industries() # Monthly returns to 5 industry portfolios >>> ind[5].head() Cnsmr Manuf HiTec Hlth Other Date 1950-01-31 1.26 1.47 3.21 1.06 3.19 1950-02-28 1.91 1.29 2.06 1.92 1.02 1950-03-31 0.28 1.93 3.46 -2.90 -0.68 1950-04-30 3.22 5.21 3.58 5.52 1.50 1950-05-31 3.81 6.18 1.07 3.96 1.36 """ n = [5, 10, 12, 17, 30, 38, 48] port = ("%s_Industry_Portfolios" % i for i in n) rets = [] for p in port: ret = pdr.get_data_famafrench(p, start=DSTART)[0] rets.append(ret.to_timestamp(how="end", copy=False)) industries = dict(zip(n, rets)) return industries
import statsmodels.api as sm from statsmodels.regression.rolling import RollingOLS seaborn.set_style("darkgrid") pd.plotting.register_matplotlib_converters() # `pandas-datareader` is used to download data from # [Ken French's website](https://mba.tuck.dartmouth.edu/pages/faculty/ken. # french/data_library.html). # The two data sets downloaded are the 3 Fama-French factors and the 10 # industry portfolios. # Data is available from 1926. # # The data are monthly returns for the factors or industry portfolios. factors = pdr.get_data_famafrench("F-F_Research_Data_Factors", start="1-1-1926")[0] factors.head() industries = pdr.get_data_famafrench("10_Industry_Portfolios", start="1-1-1926")[0] industries.head() # The first model estimated is a rolling version of the CAPM that # regresses # the excess return of Technology sector firms on the excess return of the # market. # # The window is 60 months, and so results are available after the first 60 # (`window`) # months. The first 59 (`window - 1`) estimates are all `nan` filled.
linestyle='--', linewidth=1.0) # compare the return distribution of 3 firms visually... grid = sns.pairplot(daily_pct_change, diag_kind='kde', kind="reg") grid.map_offdiag(plot_unity) # how cool is that! ############################################################################### # get the factor loadings ############################################################################### # get FF factors merged with the stock returns ff = pdr.get_data_famafrench( 'F-F_Research_Data_5_Factors_2x3_daily', start=2006 )[0] # the [0] is because the imported obect is a dictionary, and key=0 is the dataframe ff.rename(columns={"Mkt-RF": "mkt_excess"}, inplace=True) # cleaner name ff = ff.join(daily_pct_change, how='inner') # merge with stock returns for stock in ['MSFT', 'AAPL', 'VZ']: ff[stock] = ff[ stock] * 100 # FF store variables as percents, so convert to that ff[stock + '_excess'] = ff[stock] - ff[ 'RF'] # convert to excess returns in prep for regressions print(ff.describe()) # ugly... pd.set_option('display.float_format', lambda x: '%.2f' % x) # show fewer digits pd.options.display.max_columns = ff.shape[1] # show more columns print(ff.describe(include='all')) # better! # run the models-
import pandas_datareader as pdr import pandas as pd import statsmodels.api as sm from statsmodels.regression.rolling import RollingOLS from statsmodels.api import OLS, add_constant import matplotlib.pyplot as plt import seaborn seaborn.set_style('darkgrid') pd.plotting.register_matplotlib_converters() #%% factors = pdr.get_data_famafrench('F-F_Research_Data_Factors', start='1-1-2020')[0] # print(factors.head()) industries = pdr.get_data_famafrench('17_Industry_Portfolios', start='1-1-2020')[0] # print(industries.head()) #%% exog_vars = ['Mkt-RF', 'SMB', 'HML','RF'] exog = sm.add_constant(factors[exog_vars]) returns = industries.sub(factors.RF, axis=0) #%% betas = [] rsquared = [] #%% for industry in returns.columns: # print(returns.loc[returns.index, industry]) endog = returns.loc[returns.index, industry] rols = RollingOLS(endog, exog, window=12) rres = rols.fit()