股票量化投资策略研究:股票多因子策略研究
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
股票多因子测试入门
一、前言
做这个研究的目的,一是为了搞清楚股票策略研究中的一些细节问题,熟悉股票研究框架;二是为了大致了解各类因子的作用。
用米筐测,那里数据完善。
现在要做的,主要就是模仿,看别人的。
先学barra。
二、Barra Multiple-Factor Modeling
来自Barra Risk Model HandBook。
(一)因子(Descriptor)筛选、单位化处理、搭配
然后选择所有备用的因子descriptors(类似因子?以下简称“因子”),要先检验因子的显著性;通常,因子要显著地解释截面收益。
descriptor可来自基本面数据、市场数据(价、量)、或者其他数据。
因子的选择可分为几步:(1)初步筛选;有用的因子,通常要有意义,也就是make sense intuitively;其次,好的因子还必须能够对市场上的所有股票进行很好的分类,也就是完备性,不应当存在某些股票不属于因子中某一类的情况;因子需要有理论基础;(2)同时,增加一个因子如果不能增加解释度,那这个增加没有必要。
然后要将descriptors单位化;很简单,减去均值,然后除以标准差。
然后,要选择不同因子进行搭配,risk index formulation;如何搭配,主观判断起到一定作用;但是诸如cluster analysis之类的统计方法也经常用到。
在单位化以后,我们用收益率对行业和descriptor进行回归,每次测试一个因子,我们要统计回归的显著性;通过上面的测试结果,我们就可以选择出有用的因子;因子搭配,是一个递归的过程,我们首先加入最显著的因子;此后,再加入另一个因子(剩下的因子里面的最显著的?),如果这个因子没有显著增加解释度,则不要这个因子,否则就加入这个新的因子(注:这里依然要考虑行业暴露)。
然后,行业因素也要考虑进行;或者叫,行业暴露。
通常,一个公司只属于一个行业;但是,在美国和日本,会根据该公司营收的比例来决定各个行业暴露的权重。
(二)估计因子的超额收益
通过截面回归,计算因子收益率;因子收益也被用于计算因子间的协方差,进而得到协方差矩阵。
r_t=X_t*f_t+u_t;
r_t:某个股票的超额收益(excess returns to each asset);
X_t:各个股票对各因子的暴露矩阵(exposure matrix of assets to factors);
f_t:factor returns to be estimated;
u_t:specific returns;
(注:这里的X_t,应该就是各个股票的因子值?。
)
因子收益率,是一个时间序列。
它代表某个因子在某段时间的收益;每个股票,由于在不同因子上有不同暴露,因此,多个因子收益率的加权,再加上该个股的specific returns,就构成了该股票在该段时间内的收益率。
(三)因子协方差矩阵
不同因子的收益率序列之间计算协方差,就可以计算出所有因子的协方差矩阵;这么做的隐形假设是,we are modeling a stable process,and therefore, each point in time contains equally relevant information。
但是,有证据表明,因子间的相关性是在变化。
stable process假设因子间的相关性是稳定不变的。
因此,简单的计算协方差矩阵,不太严谨。
barra在两个方面放宽了”stable”的假设:(1)在计算协方差时,给近期数据更多权重;(2)we estimate a model for the volatility of a market index portfolio, and scale the factor covariance matrix so that it produces the same volatility forecast for the market portfolio as the model of market volatility(??)。
一种指数加权平均:半衰期;(没认真看;后面再说,不难)
三、数据清洗
四、因子筛选:多重共线性问题
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
因子分类:按照风格或经济含义不同,可分为收入因子、规模因子、技术因子、估值因子、统计因子等(这个不一定全面,只是作为参考)。
相关系数法:计算所有因子的相关系数,在高度相关的因子中挑选代表因子保留,保证剩余因子相关性不高,避免多重共线性(这里应该是直接计算因子值的相关性,而不是因子收益率的相关性);
主成份分析法:采用主成份分析,计算能够代表各大类因子的第一、第二、第三主成份,只取主成份因子,避免多重共线性;
多因子合成:利用QEPM(Quantitative Equity Portfolio Management)中的最大化因子IC_IR的优化方法,把同类因子合成一个大类因子,因子数据必须经过处理(Winsorize 去极值,neutralize中性化,消除行业和风格因子等的影响、standardize标准化、orthogonalize残差正交化调整),因子间存在较强相关性同质性时,采用施密特正交化方法对因子做正交化处理,用得到的正交化残差作为因子去除共线性。
五、股票多因子框架(通俗版)
(一)数据清洗
数据清洗包括奇异数据的处理(去极值)、数据规范化、部分风格因子的因子载荷正交化以及缺失风险载荷的补足。
1、极值与数据规范化处理
首先对数据进行标准化,对每个个股每个时间点的数据,减去市值加权平均值,再除以简单平均标准差,就是标准化。
标准化公式如下:
X nk(std)=( X nk(raw)-u k)/αk;
其中,u k为市值加权平均;αk为简单平均标准差。
(这里,n应该是指时间,k应该是个股序号)。
X nk(std)
极值,就是超过多少个标准差以外的,比如超过均值三倍标准差的(也就是标准化后的值大于3或者小于-3);对于极值,不能直接去掉,否则会造成数据缺失;可以采取Winsorize的方式,也可以有其他算法;这种变换,要是保证原有数据的排序(单调变换),比如,如果有两个值,分别是a1=4和a2=5,那么经过变换以后分别得到b1和b2,我们需要保证b1和b2处于相对正常的区间,同时要保证b1<b2依然成立。
极值处理完后,需要重新对数据进行标准化。
2、缺失值处理
?
(二)初步选因子:因子有效性检验
因子通常可分为三类,宏观经济因子、基本面因子、统计面因子。
这些只是模糊的分类,具体,你可以开发出你想开发的任何因子。
如何检验因子有效性?
1、IC法
计算因子的IC值,即本期因子值和下期实际收益率之间的相关性,截面的;有个说法是,由于因子值和收益率这两个序列并不服从一定的分布函数,所以用平时计算相关性的公式,所以用spearman秩和相关性,具体在python的scipy.stats中的spearman函数;一般来说,IC值大于0.03,这个因子有效性就不错。
相关系数有两种,Pearson correlation 和Spearman correlation(Spearman秩相关系数);对应的,IC值也有两种计算方法;Pearson法,就是我们通常所说的那种相关系数,即直接对两组数据求相关系数;Spearman法则是对两组数据的排序序号求相关系
数,比如,第一组因子值是[2,1,3],对应的未来收益率是[0.2,0.3,0.1],那么,因子值的排列序号为[2,3,1],未来收益率的排列序号为[2,1,3],SpearMan相关系数就是对这两组排列序号进行求相关系数。
Spearman法描述了两组数据间的单调相关程度,得出的结果也比较稳定,我更喜欢Spearman。
2、Barra法
Barra提供了一系列评价因子是否有效的方法。
(1)单因子回归(通常还要剔除行业、国家因素的影响),对该因子的回归系数进行T检验,T值的绝对值均值,均值大于2,就比较理想了;(每一时期,都有一个截面回归,得到一个T值;所有时期的T值,就可以计算出T的均值)。
(2)单因子回归,计算因子系数的T检验值,计算T值的绝对值大于2的比例;
(3)利用回归计算出因子收益率,计算因子年化收益率、年化收益率波动率、以及两者的比值;(因子收益率:我的理解是,每一期都有一个下期收益率对当期因子值的截面回归;回归得到的因子参数,就是因子收益率;每一期的因子收益率连续复利起来,就得到了一个连续的累计收益率曲线,剩下的计算年化收益率、最大回撤等就都不是问题了。
)
(4)计算因子收益率与基准收益率(通常为指数)的相关性,相关性越低越好。
(5)因子自稳定性检验,计算自稳定系数(我的理解是,当期因子值和下期因子值之间的相关系数);这个系数大于0.9比较不错,小于0.8 就不好;(其实,很好理解,就跟原始价格和均线一样,均线变化更加平滑,自相关系数肯定比原始价格高,均线看起来当然也更加稳定;由稳健的指标得出的信号,自然也稳定);
3、因子排序法
将因子分档,看看每一档的走势;不过这种算法有问题,因为每一档因子在其他因子上的暴露是不确定的。
(也就是,控制变量法更加合理)。
(三)进一步选因子:排除多重共线性
多重共线性,也就是不同因子间相关性高;对于这种,有两个方法进行处理,一是根据因子有效性进行排序,然后保留最有效的一个、剔除其他的;第二个,就是把相关性高的因子合成为一个因子,以保留更多信息。
因子合成,可采取等权法,历史收益率加权法,历史信息比例加权法,PCA法(主成份分析)。
(四)多因子选股:各显神通的时候到了
把多个因子值,进行加权;
加权方法,有IR法(参考,Quantitative Equity Portfolio Management,modern techniques and applications)、WLS收益率加权法、各种机器学习深度学习。
六、因子检验:反转因子
关键点:数据清洗,主要有异常值处理(MAD法识别异常值,并做缩尾处理?);动量因子要中性化,比如市值、行业这两个维度。
注1:编程陷阱,如果说你定义了两个矩阵一个是
MOM=pd.DataFrame(index=trade_date,columns=ts_code),另一个是MOMRaw,MOMRaw的格式和MOM一样;但是,你不能用MOMRaw=MOM来初始化MOMRaw!因为,那样的话,如果后面计算出来MOMRaw和MOM的算法不同,但是,因为你事先写了MOMRaw=MOM,因此,MOMRaw的最终值和MOM一样!。
(这个在pandas 的dataframe和series格式下是成立的,测试过。
所以一定要注意啊。
)对于问题,可以用MOMRaw=MOM.copy()。
注2:原来的回测框架回测太慢了,回测一次就要几十分钟,要做参数遍历优化,基本不可能,这会严重影响效率。
解决办法是有的,(1)第一是不逐日计算收益,而是采用定期计算,比如说,我们回溯期是20天,持有期是10天,那么我们就每十天就计算一次收益(或者,我们直接按标准的周或者月来做,也是可以的)。
不过,也就是两家因子会有这个问题,如果是基本面因子,每个季度才有这个问题;(2)计算滚动收益率耗时:并不是每天都要计算,而是每到调仓时要计算一次,3600只股票,计算一次耗时约0.16秒,一年需要滚动不到30次,十年也不过300次,总体来说,这部分耗时不多;(3)原来的算法里,还有一个过程十分耗时间,那就是去除异常值的过程,这个要对每个股票进行遍历。
一年的数据,每个股票的异常值处理需要0.3-0.4秒,3600只股票,需要接近20分钟!这里可以优化;(4)计算每日收益率及仓位部分,这个每滚动一次耗时2-3秒,一年的数据需要滚动22次左右,一年大概 1分钟,十年十分钟,已经很快了。
(5)因此,综上所述,主要耗时,在去除异常值部分;这个,可以用apply;用了apply以后,这一步的耗时从20分钟,降低到了25秒。
(零)收益率计算:复权
不过,回测就都用前复权了;如果时间不是非常长,那么价格是负数的情况很少见。
更加精细的做法是,用前复权数据产生信号,用实际价格(考虑分红送股等因素)来计算收益
(一)因子计算:异常值处理(标准化?)
直接用前复权价格计算滚动收益率(这一步,可以有变通,比如用均线距离作为基础动量因子也是可行的,即价格和均线的距离除以均线)此后,对于每个股票的初始因子值,要进行异常值处理,可考虑winsorize;注意,这里的异常值处理,是时间维度上的,即针对某个股票的历史因子时间序列进行异常值处理。
计算之后,要对收益率进行标准化;这个标准化也是时间维度的;即减去某股票历史因子值均值,除以该股票历史因子值标准差。
可以用全局的,也可以用滚动的;这里就先用全局的(即减去所有回测期的因子的均值、再除以所有回测期的因子的标准差)。
不过,标准化明显,是有未来函数的,特别是时间短的时候,很容易产生好看的结果。
我不建议做标准化。
(二)因子中性化处理:市值中性化
一篇研报中讲到,“我们对因子的市值和行业的偏离程度做了初步统计,发现动量因子的最小组更偏向大市值,而且各个行业也存在不同程度的偏离,因此,还需对因子采取中性化处理;具体是,将每期因子值对市值和行业做回归,得到的残差项作为中性化后的因子值”。
市值中性化,就直接用动量因子值,对市值进行截面回归,去残差,就是市值中性化以后的动量因子。
市值中性化是截面处理;也可以采取分组的方法。
(三)因子中性化处理:行业中性化
中性化处理的第二种方法,就是标准化。
我们用单个股票的因子值,减去它所属行业的整个行业因子值均值,再除以该行业因子值标准差,得到的就是行业中性化以后的动量因子。
(市值中性化也可以采用这种方法,即先将股票按市值大小分组)
行业中性化是截面处理。
(四)因子中性化处理:市值中性化和行业中性化一起处理
这个肯定涉及到一个先后顺序的问题;不同处理顺序,得到的最终中性化因子值肯定不同。
哪个更好?这个不好说,要看具体结果,不仅要考虑表现,还要考虑稳健性。
(五)因子评价:分组收益率、各多空组合的收益率、IC
IC:计算因子值和未来收益率之间的相关性;这里采用Spearman correlation;
ICIR=mean(IC)/std(IC);(ICIR为IC序列的年化信息比率);
(六)测试结果(同时进行了标准化、市值中性化和行业中性化)(20100101-20181231)
收益率滚动长度:20日;
调仓间隔:20日;
分组数量:5组;Port1动量因子最大;Port5动量因子最小。
交易设置:无论开仓还是平仓,都按第二日开盘价成交;开平仓,摩擦成本各0.25%;
多空组合收益计算:用多空日收益率只差来合成,不能用两个组合的累计收益率只差,因为会出现很大的误差,比如,当一个组合累计净值达到0.5时,其收益率对组合的实际影响,就会大大减少,这与实际情况不符合;同时,要考虑摩擦成本,如果某个组合在多空组合中为空头,那么其摩擦成本应当设定为正数。
每期IC值的平均值:-0.07(说明有一定的反转效应);
异常值识别范围:2倍标准差;
1、所有组合
从历史总收益来看,Port1<Port2<Port3<Port4<Port5,呈单调变化;侧面证明反转效应;不过,还需要分段测试,因为有些时间段呈现动量,有些时间段呈现反转。
2、多空组合
所谓多空组合,就是Port5-Port4;Port4-Port3;Port3-Port2;Port2-Port1;
命名规则:Port_51,就是Port5-Port1;
小结:几乎所有组合,都比Port1要好;但是,和五个组合的递减效应对应,Port5相对于Port1的超额收益最大,然后Port4/Port3/Port2一次递减。
小结:随着“距离”的拉近,多空组合间的超额收益急剧下降。
这种单调变化的现象,为A股的反转效应提供了证据。
接下来,如果把股票分成10组、20组…,这样,可以发现更多距离够大的多空组合,这样可能更加能看出反转效应。
3、各组持仓股票的平均市值
这个,用来证明各个组合间没有市值偏差;即,各个组合的持仓股票的平均市值大致是在一个水平。
(初步测试,这一步其实可以省略)
4、分段测试(20100101-20101331)
注1:分段测试和全数据测试,有些不同,主要是因为异常值的处理,会产生差异,有可能还会使策略绩效虚高。
我们异常值处理,包括中性化,用的是全局的均值和标准差。
(参考价差套利的方式,如果我们用全局数据,那么,做反转策略相当好做,因为我们的中心点和上下界,都是用了未来函数的!;而且,时间越短,未来函数的影响就越大!)
注2:因此,因子标准化,不能用全局数据!用滚动的方法来单位化,或者不进行单位化。
平均IC值:-0.12;
5、分段测试(20110101-20111231)IC=-0.1;
6、分段测试(20120101-20121231)IC=-0.12;
7、分段测试(20130101-20131231)IC=-0.13
8、分段测试(20140101-20141231)IC=-0.1
9、分段测试(20150101-20151231)IC=-0.13
(牛市末期暴跌期间,动量效应明显;大部分时间,反转效应明显;反转效应存在,重要原因就是,第一组的表现很差。
)
10、分段测试(20160101-20161231)
IC=-0.13
11、分段测试(20170101-20171231)
IC=-0.11
12、分段测试(20180101-20181231)IC=-0.1
13、分段测试(20060101-20061231)IC=-0.15
14、分段测试(20070101-20071231)IC=-0.13
15、分段测试(20080101-20081231)IC=-0.11
16、分段测试(20090101-20091231)IC=-0.12
(七)测试结果(同时进行市值和行业中性化;但是,不进行标准化处理)收益率滚动长度:20日;
调仓间隔:20日;
异常值识别范围:2倍标准差;
1、分段测试(20060101-20061231)
IC=-0.11
2、分段测试(20070101-20071231)IC=-0.06
3、分段测试(20080101-20091231)IC=-0.09
4、分段测试(20100101-20111231)IC=-0.05
5、分段测试(20120101-20131231)IC=-0.07
6、分段测试(20140101-20151231)IC=-0.07
6、分段测试(20160101-20181231)IC=-0.08
7、分段测试(20060101-20181231)
IC=-0.062
(八)测试结果(同时进行市值和行业中性化;但是,不进行标准化处理)收益率滚动长度:20日;
调仓间隔:15日;
异常值识别范围:2倍标准差;
1、分段测试(20060101-20071231)
IC=-0.04
2、分段测试(20080101-20091231)IC=-0.1
3、分段测试(20100101-20111231)IC=-0.038
4、分段测试(20120101-20131231)
IC=-0.04
小节:可见,滚动回溯期长度保持在20天不变的情况下,调仓周期缩短为15天后,效果明显下降。
5、分段测试(20140101-20151231)
IC=-0.07
6、分段测试(20160101-20181231)IC=-0.06
7、分段测试(20060101-20181231)IC=-0.059
(九)测试结果(同时进行市值和行业中性化;但是,不进行标准化处理)收益率滚动长度:20日;
调仓间隔:25日;
异常值识别范围:2倍标准差;
1、分段测试(20060101-20071231)
IC=-0.065
牛市中,多空组合是跑不过大盘的;不过,利用反转效应,买跌的组合,就比大盘好。
2、分段测试(20080101-20091231)IC=-0.085
3、分段测试(20100101-20111231)IC=-0.06
4、分段测试(20120101-20131231)IC=-0.06
5、分段测试(20140101-20151231)IC=-0.12
6、分段测试(20160101-20181231)IC=-0.048
小节:表现也有所下滑;调仓周期大于回溯期,似乎有点违和。
7、分段测试(20060101-20181231)
IC=-0.066
(十)测试结果(同时进行市值和行业中性化;但是,不进行标准化处理)收益率滚动长度:25日;
调仓间隔:25日;
异常值识别范围:2倍标准差;
1、分段测试(20060101-20181231)
IC=-0.064
(十一)测试结果(同时进行市值和行业中性化;但是,不进行标准化处理)收益率滚动长度:25日;
调仓间隔:20日;
异常值识别范围:2倍标准差;
1、分段测试(20060101-20181231)
IC=-0.069
(十二)稳定性测试(同时进行市值和行业中性化;但是,不进行标准化处理)
1、数据起点
由于中间有持仓时间,所以,数据起点必定会对结果产生影响;这个影响有多大?我们的持有期为20,那么,我只需要做19次敏感度测试,即去掉第一个数据、去掉前两个数据、去掉前三个数据、…、去掉前19个数据,就可以知道所有可能数据起点的结果(去掉19个和去掉39个,结果是一样的)。
测试参数,RollLen=20,SwthLen=20,Wedge=5,t=2.
这个数据起点,怎么说,不是很敏感。
(十三)深市(整个深市、主板、中小板、创业板)、沪市分别测试
1、深市
# 剔除沪市股票;深市大概2150只;不过,创业板建立时间较短,不过不影响。
AAAAA0='600000.SH'
AAAAA1=ts_code[ts_code>=AAAAA0]
AAAAA2=ts_code[ts_code<AAAAA0]
CloseMat_Daily_Unadj=CloseMat_Daily_Unadj.drop(columns=AAAAA1)
CloseMat_Daily_qfq=CloseMat_Daily_qfq.drop(columns=AAAAA1)
OpenMat_Daily_Unadj=OpenMat_Daily_Unadj.drop(columns=AAAAA1)
OpenMat_Daily_qfq=OpenMat_Daily_qfq.drop(columns=AAAAA1)
total_mv_Mat_Daily=total_mv_Mat_Daily.drop(columns=AAAAA1)
IndustryMat_Daily=IndustryMat_Daily.drop(columns=AAAAA1)
ts_code=AAAAA2
#
RollLen=20,SwthLen=20,Wedge=5,Slip=0.0025;Range=(20060101,20181231);
#回测结果
MeanIC=-0.054
2、沪市
#去掉深市股票,大概1500只股票
AAAAA0='600000.SH'
AAAAA1=ts_code[ts_code<AAAAA0]
AAAAA2=ts_code[ts_code>=AAAAA0]
CloseMat_Daily_Unadj=CloseMat_Daily_Unadj.drop(columns=AAAAA1) CloseMat_Daily_qfq=CloseMat_Daily_qfq.drop(columns=AAAAA1) OpenMat_Daily_Unadj=OpenMat_Daily_Unadj.drop(columns=AAAAA1) OpenMat_Daily_qfq=OpenMat_Daily_qfq.drop(columns=AAAAA1)
total_mv_Mat_Daily=total_mv_Mat_Daily.drop(columns=AAAAA1) IndustryMat_Daily=IndustryMat_Daily.drop(columns=AAAAA1)
ts_code=AAAAA2
#
RollLen=20,SwthLen=20,Wedge=5,Slip=0.0025;Range=(20060101,20181231);
# 回测结果
MeanIC=-0.065
3、创业板
# 剔除创业板以外的股票,剩下约750只
AAAAA01='300000.SZ'
AAAAA0='600000.SH'
AAAAA1=ts_code[ts_code>=AAAAA0]
AAAAA11=ts_code[ts_code<AAAAA01]
AAAAA111=AAAAA1 | AAAAA11
AAAAA2=ts_code[ts_code<AAAAA0] & ts_code[ts_code>=AAAAA01] CloseMat_Daily_Unadj=CloseMat_Daily_Unadj.drop(columns=AAAAA111) CloseMat_Daily_qfq=CloseMat_Daily_qfq.drop(columns=AAAAA111) OpenMat_Daily_Unadj=OpenMat_Daily_Unadj.drop(columns=AAAAA111) OpenMat_Daily_qfq=OpenMat_Daily_qfq.drop(columns=AAAAA111)
total_mv_Mat_Daily=total_mv_Mat_Daily.drop(columns=AAAAA111) IndustryMat_Daily=IndustryMat_Daily.drop(columns=AAAAA111)
ts_code=AAAAA2
#
RollLen=20,SwthLen=20,Wedge=5,Slip=0.0025;Range=(20100101,20181231);
# 回测结果
MeanIC=-0.047;
4、中小板
#剔除中小板以外的股票,剩余大概920只
AAAAA01='002000.SZ'
AAAAA0='300000.SZ'
AAAAA1=ts_code[ts_code>=AAAAA0]
AAAAA11=ts_code[ts_code<AAAAA01]
AAAAA111=AAAAA1 | AAAAA11
AAAAA2=ts_code[ts_code<AAAAA0] & ts_code[ts_code>=AAAAA01] CloseMat_Daily_Unadj=CloseMat_Daily_Unadj.drop(columns=AAAAA111) CloseMat_Daily_qfq=CloseMat_Daily_qfq.drop(columns=AAAAA111) OpenMat_Daily_Unadj=OpenMat_Daily_Unadj.drop(columns=AAAAA111) OpenMat_Daily_qfq=OpenMat_Daily_qfq.drop(columns=AAAAA111)
total_mv_Mat_Daily=total_mv_Mat_Daily.drop(columns=AAAAA111) IndustryMat_Daily=IndustryMat_Daily.drop(columns=AAAAA111)
ts_code=AAAAA2
#
RollLen=20,SwthLen=20,Wedge=5,Slip=0.0025,Range=[20060101,20181231]; #回测结果
MeanIC=-0.04
5、深市主板(剔除创业板和中小板)
# 剔除中小板和创业板;不到500只
AAAAA01='000000.SZ'
AAAAA0='002000.SZ'
AAAAA1=ts_code[ts_code>=AAAAA0]
AAAAA11=ts_code[ts_code<AAAAA01]
AAAAA111=AAAAA1 | AAAAA11
AAAAA2=ts_code[ts_code<AAAAA0] & ts_code[ts_code>=AAAAA01] CloseMat_Daily_Unadj=CloseMat_Daily_Unadj.drop(columns=AAAAA111) CloseMat_Daily_qfq=CloseMat_Daily_qfq.drop(columns=AAAAA111) OpenMat_Daily_Unadj=OpenMat_Daily_Unadj.drop(columns=AAAAA111) OpenMat_Daily_qfq=OpenMat_Daily_qfq.drop(columns=AAAAA111)
total_mv_Mat_Daily=total_mv_Mat_Daily.drop(columns=AAAAA111) IndustryMat_Daily=IndustryMat_Daily.drop(columns=AAAAA111)
ts_code=AAAAA2
#
RollLen=20,SwthLen=20,Wedge=5,Slip=0.0025,Range=[20060101,20181231] #
MeanIC=-0.047
6、深市(只剔除创业板)
# 剔除创业板,大概1400只
AAAAA01='000000.SZ'
AAAAA0='300000.SZ'
AAAAA1=ts_code[ts_code>=AAAAA0]
AAAAA11=ts_code[ts_code<AAAAA01]
AAAAA111=AAAAA1 | AAAAA11
AAAAA2=ts_code[ts_code<AAAAA0] & ts_code[ts_code>=AAAAA01]
CloseMat_Daily_Unadj=CloseMat_Daily_Unadj.drop(columns=AAAAA111)
CloseMat_Daily_qfq=CloseMat_Daily_qfq.drop(columns=AAAAA111)
OpenMat_Daily_Unadj=OpenMat_Daily_Unadj.drop(columns=AAAAA111)
OpenMat_Daily_qfq=OpenMat_Daily_qfq.drop(columns=AAAAA111)
total_mv_Mat_Daily=total_mv_Mat_Daily.drop(columns=AAAAA111)
IndustryMat_Daily=IndustryMat_Daily.drop(columns=AAAAA111)
ts_code=AAAAA2
#
MeanIC=-0.05;
#
(十四)初步结论:针对全A的结论
通过对上述以全A为样本的测试,有几个结论。
第一,剔除行业和市值影响后,无论是深市、还是沪市,反转效应都比较显著;不顾,如果把深市拆分为主板、中小板、创业板三块来分别检验,则反转效应有明显减弱。
第二,RollLen(计算收益率的回溯期)不能太小,通常要大于20个交易日;
第三,SwitchLen(持有期)不能太小,通常和RollLen相当比较好;
第四,SwitchLen和RollLen的打小关系。
如果SwitchLen大于RollLen,那么我们实际上就是在用较短周期的动量来预测未来较长时间内的收益;举个极端的例子,我们用过去一个月的的收益来选股,然后我们持股一年,不能说逻辑上有问题,但是,总感觉有点奇怪,当然实际收益有可能更好。
如果我们用一个月的时间计算反转因子,那么这个因子的持续时间也应当在一个月左右(主观感觉是这样),通过持续一个月左右
的因子选出来的股票却要持有一年,总感觉怪怪的。
但是,你不能说这是逻辑问题,因为,我们因子就是“过去一个月的收益率”,但是逻辑上的自洽性就差了一点;还有一个问题就是,如果SwitchLen大于RollLen,那么,中间肯定有数据没有被用到,这是个问题,因为信息本来就稀缺,你的系统却还要丢掉一些信息,这让我难以接受。
因此,综合来看,我认为,在类似的多因子策略中,一律默认RollLen>=SwitchLen(尽管如果反过来,结果可能更好)。
第五,关于参数,RollLen=20,SwitchLen=20,这个参数组合初步看来是比较合适的。
第六,关于分组数量,我之前都是分的五组,这个主要基于常识,不过也没必要一定分五组;后续再说。
第七,这个只能作为一种指导,不具备直接的实战意义,因为A股根本没有完全自由的做空;即使是融资融券标的,也是有成本的。
不过不是没有意义的,比如说,我看好这段行情啊,那我就根据反转效应买,这样赚得更多。
第八,关于后续研究,如果我能多找几个这种因子,组合起来选股,是不是很牛逼了?当然,前提是相关性低;从实际操作讲,我完全可以取成回溯一个月、持有一个月。
但是,我觉得还需要逻辑;比如我发现了另一个因子,现金流因子,这个为什么能和反转因子结合起来。
第九,第五组和第一组之间的表现差异最为明显;第一组,往往都很差;说明一个问题,不要买涨得最好的!(当然,是去除行业、市值影响以后的;引申,如果对行业、市值采取趋势跟随,结合中性化后的反转因子,结果会怎样?)
第十,如果不进行市值、行业中性化处理,那么反转效应的显著性有所减弱。
反转因子,是我的第一个有用的因子!。