之前两篇分别总结了因子数据的预处理和单因子测试的分层测试法,本篇总结回归测试法,相较于分层测试法,回归测试法更简洁。
因子预处理
与分层测试法不同,回归法测试时,因子可以不进行中性化处理,只进行异常值处理和标准化(zscore)处理,将中性化的过程包含在测试过程中。
方法说明
每一期,对全样本做一次回归,回归时将本期到下一期的股票收益率作为因变量,当期的因子暴露值作为自变量,同时考虑到市值中性和行业中性,加入行业虚拟变量和市值变量作为自变量,市值变量可以取对数消除量纲,之后进行回归,即
得到的回归结果中,因子暴露的系数即为因子收益率,通过多期回归后,就可以得到因子收益率序列及回归的t值序列,通过这两个序列可以构造指标分析因子的表现。
一些细节
评价指标
基本都是一些非常简单的指标,至于为什么取t值绝对值大于2,IC值大于0.02,也没有太好的原因,但也是符合常理的,t值绝对值越大,回归方程系数的显著性越高,IC表示相关系数,绝对值越大,表明因子暴露跟股票收益率的相关性更高。
因子测试实例
测试因子:pb_lf,需倒数 测试区间:2010年1月-2018年5月
PB因子收益序列显著大于0,因子收益状况良好
1def MultiPeriodFactorTest(factor,DateStart,DateEnd,if_reciprocal,if_neutral_industry=True, if_neutral_mktcap=True):
2
3
4 # 获取交易日序列
5 BargainDate = w.tdays(DateStart, DateEnd, "Period=M")
6 BargainDate = pd.DataFrame(BargainDate.Data[0],columns = ['date'])
7 # 循环调用单期因子测试函数,得到收益率序列,IC序列,t值序列
8 result = pd.DataFrame(columns=["DateStart","DateEnd","factor_return","t_values","IC"])
9 for i in range(1,BargainDate.shape[0]):
10 datebuy = BargainDate.date[i-1]
11 datesell = BargainDate.date[i]
12 result1 = SingelePeriodFactorTest(factor,datebuy,datesell,if_neutral_industry, if_neutral_mktcap,if_reciprocal)
13 result = result.append(result1)
14
15 result.factor_return = result.factor_return
16
17 # 计算均值
18 t_mean = result.t_values.mean()
19 return_mean = result.factor_return.mean()
20 t_abs_mean = result.t_values.abs().mean()
21
22
23 # t>0比例
24 if_t_0 = pd.DataFrame.mean(result.t_values>0)
25
26
27# IC统计量
28 IC_mean = result.IC.mean()
29 IC_std = result.IC.std()
30 if_IC_0 = pd.DataFrame.mean(result.IC>0)
31 if_abs_IC_002 = pd.DataFrame.mean(result.IC.abs()>0.02)
32
33
34 # 计算ICIR
35 ICIR = IC_mean/IC_std
36
37 final = {"因子收益序列t均值":t_mean,
38 "因子收益序列均值":return_mean,
39 "t>0比例":if_t_0,
40 "abs(t)均值":t_abs_mean,
41 "IC均值":IC_mean,
42 "IC标准差":IC_std,
43 "IC>0比例":if_IC_0,
44 "abs(IC)>0.02比例":if_abs_IC_002,
45 "ICIR":ICIR
46 }
47# '''
48# 作图
49# '''
50# X = np.arange(result.shape[0])
51#
52# # 因子收益
53# plt.figure()
54# plt.subplot(221)
55# plt.bar(X,result.factor_return)
56# plt.title('factor_return')
57# plt.subplot(222)
58# plt.hist(result.factor_return)
59# plt.title('factor_return')
60#
61# # t值
62# plt.subplot(223)
63# plt.bar(X,abs(result.t_values))
64# plt.title('abs(t_value)')
65#
66#
67# # IC
68# plt.subplot(224)
69# plt.bar(X,result.IC)
70# plt.title('IC')
71# plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
72#
73
74 return(final,result)
75
76'''
77 单期因子测试函数
78'''
79def SingelePeriodFactorTest(factor,DateStart,DateEnd,if_neutral_industry, if_neutral_mktcap,if_reciprocal):
80
81 factor_name = factor['value'][0][0]
82
83 print(factor_name + '单因子测试:' + str(DateStart) + ' -- ' + str(DateEnd))
84 data = getData(factor,DateStart)
85 # 是否取倒数
86 if if_reciprocal:
87 data.iloc[:,0] = 1/data.iloc[:,0]
88 # 通过本地数据库计算股票收益率
89 stock_list = data.index.tolist()
90 stock_list = list(map(lambda x:x.strip('.SZ'),stock_list))
91 stock_list = list(map(lambda x:x.strip('.SH'),stock_list))
92 stock_list = tuple(stock_list)
93 price_s = pd.read_sql("select stockcode,closeprice as price_s \
94 from database\
95 where stockcode in {} and bargaindate='{}'\
96 order by stockcode".format((stock_list),DateStart),stkbase)
97 price_s=price_s.set_index('stockcode')
98 price_e = pd.read_sql("select stockcode,closeprice as price_e \
99 from database\
100 where stockcode in {} and bargaindate='{}'\
101 order by stockcode".format((stock_list),DateEnd),stkbase)
102
103
104
105 price_e=price_e.set_index('stockcode')
106 price=pd.merge(price_s,price_e,left_index=True,right_index=True)
107
108
109 price['rt']=price['price_e']/price['price_s']-1
110 # 标准化
111 factor_all= norm(data,if_neutral_industry, if_neutral_mktcap)
112 factor_all.index.name = 'stockcode'
113 factor_all = factor_all.reset_index()
114 factor_all['stockcode'] = factor_all['stockcode'].apply(lambda x:x.strip('.SZ|.SH'))
115 factor_all = factor_all.set_index('stockcode')
116 Alldata = pd.merge(factor_all,price,left_index=True,right_index=True,how = 'left')
117
118
119
120
121 y = Alldata[['rt']]
122 X = factor_all
123 X['Intercept'] = 1
124
125 model = sml.OLS(y,X)
126 result=model.fit()
127
128
129 # 计算IC,IR
130 IC = calc_IC(factor_all[factor_name], y, 'Spearman')
131
132 print(str(DateStart) + "——" +str(DateEnd)+","+factor_name + '因子收益为:'+ str(round(result.params[0],4)*100) +'%')
133
134 return_t=pd.DataFrame([[DateStart,DateEnd,result.params[0],result.tvalues[0],IC]],
135 columns=["DateStart","DateEnd","factor_return","t_values","IC"])
136
137 return(return_t)
参考文献
1. 20170410-光大证券-光大证券多因子系列报告之一:因子测试框架