Fama-Macbeth 回归和Newey-West调整
- 2019 年 12 月 30 日
- 筆記
1. 综述
Fama Macbeth是一种通过回归方法做因子检验,并且可以剔除残差截面上自相关性的回归方法,同时为了剔除因子时序上的自相关性,可以通过Newey West调整对回归的协方差进行调整。
2. 原理
2.1 系数估计
Fama Macbeth回归分为两步,第一步是横截面回归 ,在截面上用股票收益率对各因子暴露做回归,得到各因子的收益率;第二部是对系数的时间序列取平均得到作为参数的估计值,并进行t检验,t检验用到的标准误经过Newey West调整,总结如下
2.2 标准误估计
- 简单估计
其中,分子上为回归系列的标准差,可以直接计算,也可以进行Newey West调整消除异方差和序列自相关。
- Newey West 调整
Newey West的原理主要参考了石川大佬的文章[2][3],简单说明,考虑一个线性模型
当残差不存在异方差和自相关性时,残差协方差阵为单位阵的倍数,回归系数的协方差估计是一致估计量,当残差存在异方差或自相关性时,协方差阵估计有问题,可以通过Newey West调整解决,具体来说是估计上式中的
Newey West调整即对Q进行估计,最终给出的估计量具有一致性,表达式如下,用S表示
上式中,括号中第一项为仅有异方差时的调整,后面一项为针对自相关的调整,其中,e为样本残差,L为计算自相关性影响的最大滞后阶数,w_l是滞后期l的系数,从公式来看,随着滞后期数的增加,影响减小。将S带入系数协方差阵的估计可以得到协方差的Newey West估计量
其中,L常用的取法有很多种,python的famamacbeth函数的取法包括
以上是对于OLS的Newey West调整,对于Fama Macbeth回归,是对已经回归出来的一堆beta系数序列的方差进行调整,跟回归有一定差别,可以做一个转换:用回归出来的所有beta做因变量,1做自变量,做一个回归,这样回归出来的系数是所有beta的均值,残差也捕捉了beta中的异方差性和自相关性,对这个回归方程做newey west即可,这个在石川大佬的文章中有更细致的说明。
3. Python实现
Python的linearmodels中自带FamaMacBeth函数,本文一方面调用这一函数,另一方面自己写,用两种方法实现Fama Macbeth回归,确保结果的准确性。
数据使用2010-2018年全A股的市值、动量、PB、roe因子进行测试。
3.1 数据载入
from linearmodels import FamaMacBeth import numpy as np import pandas as pd import datetime import statsmodels.api as sm import statsmodels.formula.api as sml def getICSeries(factors,ret,method): icall = pd.DataFrame() fall = pd.merge(factors,ret,left_on = ['tradedate','stockcode'],right_on = ['tradedate','stockcode']) icall = fall.groupby('tradedate').apply(lambda x:x.corr(method = method)['ret']).reset_index() icall = icall.drop(['ret'],axis = 1).set_index('tradedate') return icall def ifst(x): if pd.isnull(x.entry_dt): return 0 elif (x.tradedate < x.entry_dt) |(x.tradedate > x.remove_dt): return 0 else: return 1 def ols_coef(x,y): x = x.astype('float64') y = y.astype('float64') return sm.OLS(y,sm.add_constant(x),missing = 'drop').fit().params def ols_coef1(x,formula): return sml.ols(formula, data=x).fit(missing = 'drop').params price = pd.read_csv('price.csv',index_col = 0) pb = pd.read_csv('pb.csv',index_col = 0) roe = pd.read_csv('roe.csv',index_col = 0) mkt = pd.read_csv('mkt.csv',index_col = 0) ST = pd.read_excel('ST.xlsx') ''' 收益率计算 ''' price['tradedate'] = price.tradedate.apply(getdate) ret_m = getRet(price,freq ='m',if_shift = True) mom1 = getRet(price,freq ='m',if_shift = False) mom1 = mom1.rename(columns = {'ret':'mom1'}) fall = pd.merge(pb,roe,left_on = ['tradedate','stockcode'],right_on = ['tradedate','stockcode']) fall = pd.merge(fall,mkt,left_on = ['tradedate','stockcode'],right_on = ['tradedate','stockcode']) fall['tradedate'] = fall.tradedate.apply(getdate) fall = pd.merge(fall,mom1,left_on = ['tradedate','stockcode'],right_on = ['tradedate','stockcode']) del fall['rptdate'] fall = pd.merge(fall,ST,left_on = 'stockcode',right_on = 'stockcode',how = 'left') fall['if_st'] = fall.apply(ifst,axis = 1) fall = fall.loc[fall.if_st == 0].reset_index(drop = True) fall = fall.drop(['if_st','entry_dt','remove_dt'],axis = 1) alldata = pd.merge(fall,ret_m,left_on = ['tradedate','stockcode'],right_on = ['tradedate','stockcode']) alldata['mktcap'] = np.log(alldata.mktcap)
3.2 计算因子IC
alldata中包含所有的因子和收益率数据,并且已经剔除了ST,用alldata做测试。首先用alldata计算因子的IC,ICIR结果如下
ics = getICSeries(fall,ret_m,'spearman') icir = ics.mean()/ics.std()*np.sqrt(12) ics.cumsum().plot()
3.3 Fama macbeth回归
接下来用这四个因子做FamaMacbeth回归,首先用python自带的函数FamaMacbeth
这个函数用法和statsmodels中的OLS基本一致,输入因变量(dependent),自变量(exog)和样本权重(weights),需要注意的是因变量、自变量都是面板数据,或者用MultiIndex的dataframe,日期在前,个体编码在后。生成FamaMacbeth对象后用fit方法进行系数估计,fit的输入参数较多
- cov_type表示是否对方差进行调整,'unadjusted'表示不调整,默认为不调整。'kernel'表示调整,即用Newey West方法进行调整
- debiased:是否对协方差进行自由度调整,即分母用n还是n-1
- bandwitdh:窗宽,即上文NW调整中的L,如果不设置会通过算法自动生成最优的,也可以根据上面L的公式手动输入。
关于这两个函数的细致说明可以参考[1],这里首先给出不进行调整的回归结果
fmdata = alldata.set_index(['stockcode','tradedate']) fm = FamaMacBeth(dependent = fmdata['ret'], exog = sm.add_constant(fmdata[['pb','mktcap','mom1','roe_ttm']])) res_fm = fm.fit(debiased=False) res_fm
手动回归并与上述结果相对比
- 回归系数
- 回归标准误
接下来看Newey West调整后的结果,这里根据上面的公式计算最优的L
T = res.shape[0] L = int(np.ceil(4 * (T / 100) ** (2 / 9)))
取bandwidth = 5,NW调整后的回归结果如下
res_fm = fm.fit(cov_type= 'kernel',debiased = False,bandwidth = 5) res_fm
手动回归,用beta序列对1进行回归,对结果做NW调整,这里回归用statsmodels中的OLS函数构造辅助函数ols_nw_se完成,最大滞后阶数也设置为5,返回标准误
最后对回归结果做简单分析,从FM结果来看,市值和动量通过了显著性检验,方向与IC的方向一致,表明因子对股票收益率有一定的解释力,pb、roe未能通过检验,表明这两个因子中的信息有跟其他两个重叠了,没有信息增益。但是要说明本文建模整个过程都比较粗糙,只是为实现FM回归,结论不具有一般性。
获取数据源码,后台回复"famamacbeth"
参考文献
[1]https://bashtage.github.io/linearmodels/panel/models.html#linearmodels.panel.model.FamaMacBeth
[2] https://zhuanlan.zhihu.com/p/40984029
[3] https://zhuanlan.zhihu.com/p/54913149
[4] Fama E F, MacBeth J D. Risk, return, and equilibrium: Empirical tests[J]. Journal of political economy, 1973, 81(3): 607-636.