MBAlib百科对动量策略和反转策略作了很好的解释:
动量/反向策略是指买入赢家/输家组合,同时卖空输家/赢家组合的交易策略。其主要步骤为:
①确定目标证券市场作为交易对象的范围。
②选定一个时间长度作为证券业绩评价期,通常称为投资组合的形成期或排名期。
④根据形成期各样本证券的收益率的大小,对目标市场所有样本证券进行升序、降序排列,然后等分成若干组,其中收益率最大的一组称为赢家组合,收益率最小的一组称为输家组合。
⑤形成期之后或间隔一段时间后,再选一个时间长度,作为卖买赢家组合和输家组合后的持有期限。
⑥连续或间隔一段时期,不断重复 ②一⑤行为。
⑦业绩评价。计算动量/反向策略各持有期的回报率均值及t统计值,如果t统计值表明动量/反转策略的收益率显著大少0,实业界则称动量/反向策略成功,学术界称存在动量/反转现象,反之亦反。
本人尝试着用sas一步一步完成上述操作:股票范围为国内整个A股,形成期用P周来表示,组合持有期用Q周表示,这里将P,Q都简单的取1,2,3。后续的T检验待继续完善。
这里test数据系包含2000多只A股的日线数据。
* test系多只股票的日线数据,选取2009-2012年度日线数据; data test1; set test; year=year(date); month=month(date); week=week(date); keep id date year month week close ; if 2009<=year<=2012 then output; run; *计算两年期间股票的日线数据长度,剔除较短数据; proc freq data=test1 noprint ; table id /out=test2(keep=id count) ; run; data test3; merge test1 test2; by id; if count<360 then delete ; if id eq lag(id) then do; ret_1=log(close)-log(lag(close)); end; run; proc sort data=test3;by id;run; *计算每支股票的周累计收益; proc sql; create table test4 as select *, sum(ret_1) as sum_ret from test3 group by id,year,month,week; quit; *计算日均收益率,对其进行排序,进而对2000多只股票进行分组; proc sql; create table test5 as select distinct id,year,month,week,sum_ret from test4; quit; *选定一个测试时点,例如以2011年1月第一周开始,找到该时点前p周到数据, 进而按照前P周到累计收益率进行排序,这里p取1,2,3; data test6; set test5; if id eq lag(id) then do; ret_lag1=lag(sum_ret); ret_lag2=lag(sum_ret)+lag2(sum_ret); ret_lag3=ret_lag2+lag3(sum_ret); end; run; *考虑lag函数产生缺失值的问题,我们选取观测时间点位2011年1月第一周; data test7; set test6; if year=2011 & month=1 & week=1 then output; run; *对观测时间点进行前P周到累计收益进行排序:升序:轮转策略;降序:动量策略; %macro rank(num); %do i=1 %to # proc rank data=test7 out=test7_&i group=14; var ret_lag&i; ranks group; run; data test_dong&i test_fan&i; set test7_&i; if group=0 then output test_fan&i; if group=13 then output test_dong&i; run; *从待选股票中选出动量组合股票,从观测日开始,计算持有组合内股票Q周的累计收益; data new; set test6; if year<2011 then delete; run; *计算动量策略形成期为1周,持有期为1,2,3周到收益,同理可以计算 形成期为2/3周到动量策略; data merge_d&i; merge test_dong&i(in=a) new(in=b); by id; if a=1 & b=1 then output; run; proc expand data=merge_d&i out=d_&i; convert ret_lag1=ret1 / transform=(lead 2); convert ret_lag2=ret2 / transform=(lead 3); convert ret_lag3=ret3 / transform=(lead 4); run; data d_&i; set d_&i; if year=2011 & month=1 & week=1 then output; run; %end; %mend; %rank(3);
试图将上面代码得到的组合和沪深300指数进行比对,考察其收益率情况。下面需要计算相应时间段的沪深300指数收益率,进而进行差值比对。沪深300指数数据需要首先下载。
*沪深300指数收益率的计算; data sz399300_1; set sz399300; year=year(var1); month=month(var1); week=week(var1); ret=dif(log(var5)); drop var: ; run; proc sql; create table sz399300_2 as select distinct year,month,week, sum(ret) as sum_ret from sz399300_1 group by year,month,week ; quit; data sz399300_3; set sz399300_2; ret_lag1=lag(sum_ret); ret_lag2=lag(sum_ret)+lag2(sum_ret); ret_lag3=ret_lag2+lag3(sum_ret); run; proc expand data=sz399300_3 out=sz399300_4; convert ret_lag1=ret1 / transform=(lead 2); convert ret_lag2=ret2 / transform=(lead 3); convert ret_lag3=ret3 / transform=(lead 4); run; data sz399300_4; set sz399300_4; if year=2011 & month=1 & week=1 then output; run; *沪深300与组合收益率比较; %macro diff_hs(num); %do i= 1 %to # proc sql; create table d&i_need as select distinct a.year,a.month,a.week, mean(a.ret1-b.ret1) as ret1, mean(a.ret2-b.ret2) as ret2, mean(a.ret3-b.ret3) as ret3 from d_&i as a join sz399300_4 as b on a.year=b.year; quit; proc sql; create table f&i_need as select distinct a.year,a.month,a.week, mean(a.ret1-b.ret1) as ret1, mean(a.ret2-b.ret2) as ret2, mean(a.ret3-b.ret3) as ret3 from f_&i as a join sz399300_4 as b on a.year=b.year; quit; %end; %mend; %diff_hs(3);
下面系组合形成期和持有期(p,q)都用月来表示的代码:
libname yu "E:\TMP"; * test系多只股票的日线数据,选取2009-2012年度日线数据; data test1; set YU.test; year=year(date); month=month(date); keep id date year month close ; if 2009<=year<=2012 then output; run; *计算两年期间股票的日线数据长度,剔除较短数据; proc freq data=test1 noprint ; table id /out=test2(keep=id count) ; run; data test3; merge test1 test2; by id; if count<360 then delete ; if id eq lag(id) then do; ret_1=log(close)-log(lag(close)); end; run; proc sort data=test3;by id;run; *计算每支股票的月累计收益; proc sql; create table test4 as select distinct id,year,month, sum(ret_1) as sum_ret from test3 group by id,year,month; quit; *选定一个测试时点,例如以2011年1月1日开始,找到该时点前p月到数据, 进而按照前P月到累计收益率进行排序,这里p取1,2,3,4,5,6; data test5; set test4; if id eq lag(id) then do; ret_lag1=lag(sum_ret); ret_lag2=lag(sum_ret)+lag2(sum_ret); ret_lag3=ret_lag2+lag3(sum_ret); ret_lag4=ret_lag3+lag4(sum_ret); ret_lag5=ret_lag4+lag5(sum_ret); ret_lag6=ret_lag5+lag6(sum_ret); end; run; *考虑lag函数产生缺失值的问题,我们选取观测时间点位2011年1月第一周; data test6; set test5; if year=2011 & month=10 then output; run; *对观测时间点进行前P周到累计收益进行排序:升序:轮转策略;降序:动量策略; %macro rank(num); %do i=1 %to # proc rank data=test6 out=test6_&i group=14; var ret_lag&i; ranks group; run; data test_dong&i test_fan&i; set test6_&i; if group=0 then output test_fan&i; if group=13 then output test_dong&i; run; *从待选股票中选出动量组合股票,从观测日开始,计算持有组合内股票Q周的累计收益; data new; set test6; if year<2011 then delete; run; *计算动量策略形成期为1周,持有期为1,2,3周到收益,同理可以计算 形成期为2/3周到动量策略; data merge_d&i; merge test_dong&i(in=a) new(in=b); by id; if a=1 & b=1 then output; run; proc expand data=merge_d&i out=d_&i; convert ret_lag1=ret1 / transform=(lead 2); convert ret_lag2=ret2 / transform=(lead 3); convert ret_lag3=ret3 / transform=(lead 4); convert ret_lag4=ret4 / transform=(lead 5); convert ret_lag5=ret5 / transform=(lead 6); convert ret_lag6=ret6 / transform=(lead 7); run; data d_&i; set d_&i; if year=2011 & month=10 then output; run; data merge_f&i; merge test_fan&i(in=a) new(in=b); by id; if a=1 & b=1 then output; run; proc expand data=merge_f&i out=f_&i; convert ret_lag1=ret1 / transform=(lead 2); convert ret_lag2=ret2 / transform=(lead 3); convert ret_lag3=ret3 / transform=(lead 4); convert ret_lag4=ret4 / transform=(lead 5); convert ret_lag5=ret5 / transform=(lead 6); convert ret_lag6=ret6 / transform=(lead 7); run; data f_&i; set f_&i; if year=2011 & month=10 then output; run; %end; %mend; %rank(6); *沪深300指数收益率的计算; data sz399300_1; set YU.sz399300; year=year(var1); month=month(var1); ret=dif(log(var5)); drop var: ; run; proc sql; create table sz399300_2 as select distinct year,month, sum(ret) as sum_ret from sz399300_1 group by year,month ; quit; data sz399300_3; set sz399300_2; ret_lag1=lag(sum_ret); ret_lag2=lag(sum_ret)+lag2(sum_ret); ret_lag3=ret_lag2+lag3(sum_ret); ret_lag4=ret_lag3+lag4(sum_ret); ret_lag5=ret_lag4+lag5(sum_ret); ret_lag6=ret_lag5+lag6(sum_ret); run; proc expand data=sz399300_3 out=sz399300_4; convert ret_lag1=ret1 / transform=(lead 2); convert ret_lag2=ret2 / transform=(lead 3); convert ret_lag3=ret3 / transform=(lead 4); convert ret_lag4=ret4 / transform=(lead 5); convert ret_lag5=ret5 / transform=(lead 6); convert ret_lag6=ret6 / transform=(lead 7); run; data sz399300_4; set sz399300_4; if year=2011 & month=10 then output; run; %macro diff_hs(num); %do i= 1 %to # proc sql; create table d_need&i as select distinct a.year,a.month, mean(a.ret1-b.ret1) as ret1, mean(a.ret2-b.ret2) as ret2, mean(a.ret3-b.ret3) as ret3, mean(a.ret4-b.ret4) as ret4, mean(a.ret5-b.ret5) as ret5, mean(a.ret6-b.ret6) as ret6 from d_&i as a join sz399300_4 as b on a.year=b.year; quit; proc sql; create table f_need&i as select distinct a.year,a.month, mean(a.ret1-b.ret1) as ret1, mean(a.ret2-b.ret2) as ret2, mean(a.ret3-b.ret3) as ret3, mean(a.ret4-b.ret4) as ret4, mean(a.ret5-b.ret5) as ret5, mean(a.ret6-b.ret6) as ret6 from f_&i as a join sz399300_4 as b on a.year=b.year; quit; %end; %mend; %diff_hs(6); data final_d9; set d_need:; run; data final_f9; set f_need:; run; proc datasets library=work; delete d_: f_: merge_: Sz399300: test: new; run; quit;
如果以日为单位进行测试,可以稍微变化下:
*e:\temp\test系国内A股数据,sz399300系沪深300指数数据; libname gao "e:\tmp"; data test1; set gao.test; if id eq lag(id) then do; ret=dif(close)/lag(close); end; if year(date)<2009 then delete; keep id date ret close; run; *计算两年期间股票的日线数据长度,剔除较短数据; proc freq data=test1 noprint ; table id /out=test2(keep=id count) ; run; data test3; merge test1 test2; by id; if count<360 then delete ; run; *选定一个测试时点,例如以2011年1月5日,计算前P日累计收益率并进行排序, 这里p取21,42; proc expand data=test3 out=test4 method=none; by id; convert ret =ret_lag1 / transformout=(movsum 21); convert ret =ret_lag2 / transformout=(movsum 42); run; *选定测试日; data test5; set test4; if date="05jan2012"d then output; run; *以05jan2011日前21/42日累计收益率进行排序,生产动量组合和反转组合; %macro rank(num); %do i=1 %to # proc rank data=test5 out=test5_&i group=10; var ret_lag&i; ranks group; run; data test_dong&i test_fan&i; set test5_&i; if group=0 then output test_fan&i; if group=9 then output test_dong&i; run; *从待选股票中选出动量组合股票,从观测日开始,计算持有组合内股票Q日的累 计收益; data new; set test4; if date<"05jan2012"d then delete; run; *计算动量策略形成期为1,持有期为1,2,3收益,同理可以计算 形成期为2/3到动量策略; data merge_d&i; merge test_dong&i(in=a) new(in=b); by id; if a=1 & b=1 then output; run; proc expand data=merge_d&i out=d_&i; convert ret_lag1=ret1 / transform=(lead 21); convert close=close21 / transform=(lead 21); convert ret_lag2=ret2 / transform=(lead 42); convert close=close42 / transform=(lead 42); run; data d_&i; set d_&i; if date="05jan2012"d then output; run; data merge_f&i; merge test_fan&i(in=a) new(in=b); by id; if a=1 & b=1 then output; run; proc expand data=merge_f&i out=f_&i; convert ret_lag1=ret1 / transform=(lead 21); convert close=close21 / transform=(lead 21); convert ret_lag2=ret2 / transform=(lead 42); convert close=close42 / transform=(lead 42); run; data f_&i; set f_&i; if date="05jan2012"d then output; run; %end; %mend; %rank(2); *沪深300指数收益率的计算; data sz399300_1; set gao.sz399300(rename=(var1=date var5=close)); ret=dif(close)/lag(close); drop var: ; run; proc expand data=sz399300_1 out=sz399300_2 method=none; convert ret =ret_lag1 / transformout=(sum 21); convert ret =ret_lag2 / transformout=(sum 42); run; proc expand data=sz399300_2 out=sz399300_3; convert ret_lag1=ret1 / transform=(lead 21); convert close=close21 / transform=(lead 21); convert ret_lag2=ret2 / transform=(lead 42); convert close=close42 / transform=(lead 42); run; data sz399300_4; set sz399300_3; c0=close*300; c21=close21*300; C42=close42*300; if date="05jan2012"d then output; run; %macro diff_hs(num); %do i= 1 %to # proc sql; create table d_need&i as select distinct a.date, mean(a.ret1-b.ret1) as ret1, mean(a.ret2-b.ret2) as ret2, (sum((ceil(b.c0/193)/a.close)*a.close21) -c21)/c0 as r21, (sum((ceil(b.c0/193)/a.close)*a.close42) -c42)/c0 as r42 from d_&i as a join sz399300_4 as b on a.date=b.date; quit; proc sql; create table f_need&i as select distinct a.date, mean(a.ret1-b.ret1) as ret1, mean(a.ret2-b.ret2) as ret2, (sum((ceil(b.c0/193)/a.close)*a.close21) -c21)/c0 as r21, (sum((ceil(b.c0/193)/a.close)*a.close42) -c42)/c0 as r42 from f_&i as a join sz399300_4 as b on a.date=b.date; quit; %end; %mend; %diff_hs(2); data final_d1; set d_need:; run; data final_f1; set f_need:; run;