动量模型回测——基于米矿ricequant的jupyter notebook平台
受@earletf 启发,做个动量模型验证验证:
思路来源文章:https://xueqiu.com/3559889031/166758703
标的:
biaodichi=['159996.XSHE','512400.XSHG','515210.XSHG','515220.XSHG','515030.XSHG','512800.XSHG','512880.XSHG','512290.XSHG','512170.XSHG','512200.XSHG','512790.XSHG','515050.XSHG','512660.XSHG','512690.XSHG','510650.XSHG']#标的
参数设置:
time1p=10 #时间参数1,前x天动量
time2p=10 #时间参数2,后x天动量
headc=3 #买入前3个
tailc=3 #买入后3个
startdate= '20191001' #数据开始时间
enddate='20201231' #数据开始时间
frequency='1d' #日线数据
代码:
提取某证券历史行情数据
def tiqusinglestock(stock,fretemp):
aaa=get_price(stock,startdate,enddate, frequency=fretemp, fields=None, adjust_type='pre', skip_suspended=False)
aaa.dropna(axis=0, how='any', inplace=True)
if aaa is None:
print('-')
else:
aaa=aaa.reset_index(inplace=False)
aaa['code']=stock
aaa['name']=instruments(stock).symbol
return aaa
计算某证券之前x天动量(涨跌)和之后x天动量(涨跌):
def cal_dongliang(aaa,time1ptemp,time2ptemp):
aaa['t1dongliang']=NaN
aaa['dleffect']=NaN
length=len(aaa)
co=aaa.columns.get_loc('close')
c1=aaa.columns.get_loc('t1dongliang')
c2=aaa.columns.get_loc('dleffect')
aaa.iloc[time1ptemp:length,c1]=aaa.iloc[time1ptemp:length,co].values/aaa.iloc[0:(length-time1ptemp),co].values
aaa.iloc[0:(length-time2ptemp),c2]=aaa.iloc[time2ptemp:length,co].values/aaa.iloc[0:(length-time2ptemp),co].values
bbb=aaa[['date','code','name','close','t1dongliang','dleffect']]
return bbb
计算动量效应
def cal_effect(dataalltemp):
a=dataalltemp.date.drop_duplicates()
guocheng = pd.DataFrame()#
new_col = ['date','time1p','time2p','best1','best1r','worst1','worst1r','avrr','chaoeshouyi','chaoeshouyi2','chaoeshouyib','chaoeshouyiw','chaoeshouyiavrr']
#统计信息的格式
h=len(a.values)
x=0 #计数器
b=1 #最好值净值
w=1 #最差值净值
av=1 #平均值净值
while x<h:
date=a.values[x]
best1=dataalltemp[dataalltemp.date==date].head(headc).name.values[0] #当天动量最好证券名称
best1r=dataalltemp[dataalltemp.date==date].head(headc).dleffect.values.mean() #当天动量最好前x个证券之后x天持仓期动量平均值
worst1=dataalltemp[dataalltemp.date==date].tail(tailc).name.values[-1] #当天动量最差前x个证券名称
worst1r=dataalltemp[dataalltemp.date==date].tail(tailc).dleffect.values.mean() #当天动量最差前x个证券之后x天持仓期动量平均值
avrr=dataalltemp[dataalltemp.date==date].dleffect.mean() #全部证券之后x天持仓期动量平均值
b=b*best1r
w=w*worst1r
av=av*avrr
x=x+time2p #跳过之后x天持仓期
chaoeshouyi=best1r-avrr #收益是否跑赢平均值
chaoeshouyi2=b-av #相对收益累计绝对值
chaoeshouyib=best1r-1 #最好动量是否大于1
chaoeshouyiw=worst1r-1 #最差动量是否大于1
chaoeshouyiavrr=avrr-1 #同期均值动量是否大于1
sgl1=[[date,time1p,time2p,best1,best1r,worst1,worst1r,avrr,chaoeshouyi,chaoeshouyi2,chaoeshouyib,chaoeshouyiw,chaoeshouyiavrr]]
guocheng=guocheng.append(sgl1,ignore_index=True)
guocheng.columns = new_col
slav=len(guocheng[guocheng.chaoeshouyi>0])/len(guocheng)
slb=len(guocheng[guocheng.chaoeshouyib>0])/len(guocheng)
slw=len(guocheng[guocheng.chaoeshouyiw<0])/len(guocheng)
sla=len(guocheng[guocheng.chaoeshouyiavrr<0])/len(guocheng)
tongji=[[time1p,time2p,b,w,av,slav,slb,slw,sla]]
return guocheng,tongji
主程序运行:
plguocheng = pd.DataFrame()
pltongji = pd.DataFrame()
count=1
for time1p in range(1,61): #动量效应参数(前)
for time2p in range(1,61): #动量效应参数(后)
print('进度:'+str(count/3600)) #显示下进度免得着急
count=count+1
#-------------------------------------------------------------------
dataall = pd.DataFrame()
for x in biaodichi:
a=tiqusinglestock(x,frequency) #提取原始数据
c=cal_dongliang(a,time1p,time2p) #计算动量
dataall=dataall.append(c,ignore_index=True) #结果合并
dataall.sort_values(by=['date','t1dongliang'],inplace=True,ascending=[True,False]) #数据排序,先按时间从低到高,再按照前期动量由高到低
dataall= dataall.reset_index(drop=True) #重置索引
dataall.dropna(axis=0, how='any', inplace=True) #丢掉Nan
a1,a2=cal_effect(dataall) #计算动量效应
plguocheng=plguocheng.append(a1,ignore_index=True) #计算动量效应结果添加
pltongji=pltongji.append(a2,ignore_index=True) #计算动量效应结果添加
#-------------------------------------------------------------------
输出结果
new_col = ['time1p','time2p','b','w','av','slav','slb','slw','sla']
pltongji.columns = new_col
pltongji.to_excel('统计-'+str(ticks)+'-.xlsx',encoding="utf_8")
plguocheng.to_excel('过程-'+str(ticks)+'-.xlsx',encoding="utf_8")
结果分析:
动量效应确实存在。