python实现量化交易策略

1 前言

相信大家都听说过股票,很羡慕那些炒股大佬,觉得量化投资非常高深,本文教大家用python实现简单的量化交易策略。在这强调一下,本文仅供交流学习参考,不构成任何投资建议。炒股有风险,投资需谨慎。

2 构建策略

炒股是一个概率游戏,强如巴菲特也没办法保证这只股票一定能涨。我们能做的是买入上涨概率高的股票,不碰那些下跌概率高的股票。在股票市场中有很多上市公司,有些公司是领导者,有些是追随者,比如白酒行业中贵州茅台(600519)、新能源概念中宁德时代(300750)等都是领导者。我们可以观察这些股票的走势,来判断同行业同概念中其他公司股票价格的走势。基于这种思想,我们用相关性来构建策略。
本文用沪深300成分股构建股票池,样本期是2020年1月1日到2020年12月31日,数据来源于tushare数据库,官网链接:https://tushare.pro。

import tushare as tsimport pandas as pdimport numpy as npimport copypro = ts.pro_api('你的token')#1 获取沪深300成分股日线行情数据def hqsj_hs():df1 = pro.index_weight(index_code='399300.SZ', trade_date='20201231')df=pd.DataFrame()for i in range(len(df1)):df2 = pro.daily(ts_code=df1.iloc[i,1], start_date='20200101', end_date='20201231')df=pd.concat([df,df2],axis=0)df.to_excel('股票数据.xlsx',index=False)hqsj_hs()

这里得到了沪深300成分股的日线行情数据,需要手动将excel表按股票代码和交易日期升序。有些股票在样本期某天停牌,需要剔除该股票数据。这里用A股票当天收益率和其他股票昨天收益率计算相关性。

#2 计算相关性def xgx():df=pd.read_excel('股票数据.xlsx',engine='openpyxl')result={}for i in range(len(df)):key=df.iloc[i,0]if result.get(key,False):result[key].append(df.iloc[i,-3])else:result[key] = [df.iloc[i,-3]]result1=copy.deepcopy(result)for i in result:if len(result[i])!=243:del result1[i]for i in result1:result1[i].append([result1[i][1:],result1[i][:-1]])result2={}for i in result1:aa = {}now=pd.Series(result1[i][-1][0])for j in result1:pre=pd.Series(result1[j][-1][1])xgx=now.corr(pre)aa[j]=abs(xgx)result2[i]=aa#print(result2)result3={}for i in result2:result3[i]={max(zip(result2[i].values(), result2[i].keys()))[1]:max(zip(result2[i].values(), result2[i].keys()))[0]}xxx=[]for i in result3:for j in result3[i]:xxx.append(result3[i][j])b=sorted(xxx,reverse = True)[:1] #取相关性最大的result4={}for i in result3:for j in result3[i]:for x in b:if x==result3[i][j]:result4[i]={j:x}print(result4)return result4

我们取相关性最大的股票组,得到结果是上海临港(600848)和民生银行(600016),相关性为0.4156。也就是说民生银行(600016)今天跌了,那么上海临港(600848)明天大概率要跌。我们可以在尾盘观察民生银行(600016),如果涨了,则买入上海临港(600848)。到这里就构建了我们的策略。

3 买股方案

前文根据2020年1月1日到2020年12月31日的数据构建策略,用于2021年1月1日到2021年3月31日交易。

#3 获取21年数据def test_data():result4=xgx()ts_code=[]for i in result4:for j in result4[i]:ts_code.append(j)df = pd.DataFrame()for i in ts_code:df1 = pro.daily(ts_code=i, start_date='20210101', end_date='20210331')df = pd.concat([df, df1], axis=0)df.to_excel('股票数据1.xlsx', index=False)test_data()#4 买股方案def mgfa():df=pd.read_excel('股票数据1.xlsx',engine='openpyxl')timeseries=df['trade_date'].tolist()timetime=list(set(timeseries))timetime1=sorted(timetime)result4=xgx()ts1=[] #昨天ts2=[] #今天for i in result4:ts2.append(i)for j in result4[i]:ts1.append(j)result1={}for i in range(len(df)):time=df.iloc[i,1]if result1.get(time,False):aa.append(df.iloc[i,-3])else:aa=[]aa.append(df.iloc[i,-3])result1[time]=aaresult2={}for i in result1:if i!=20210331:aaa=[]for j in result1[i]:if j >0:aaa.append(ts2[result1[i].index(j)])result2[timetime1[timetime1.index(i)+1]]=aaaprint(result2)return result2mgfa()

我们得到了2021年1月1日到2021年3月31日的买股方案,结果为2021年1月5日空仓,2021年1月6日空仓,2021年1月7日买入上海临港(600848)等等。

4 评估策略

上文我们得到了买股方案,最后需要进行回测,我们用收益率,夏普率,最大回撤等指标来评估策略的优劣性,收益率和夏普率越大越好,最大回撤越小越好。

#5 获取测试数据def cssj():result4=xgx()ts_code=[]for i in result4:ts_code.append(i)df = pd.DataFrame()for i in ts_code:df1 = pro.daily(ts_code=i, start_date='20210101', end_date='20210331')df = pd.concat([df, df1], axis=0)df.to_excel('股票数据2.xlsx', index=False)cssj()#6 评估策略def jssy():result2=mgfa()result4=xgx()df=pd.read_excel('股票数据2.xlsx',engine='openpyxl')zdf=[]for i in result2:if len(result2[i]) == 1:for j in result2[i]:for x in range(len(df)):if df.iloc[x, 0] == j and df.iloc[x, 1] == i:zdf.append(df.iloc[x, -3])else:zdf.append(0)bbb=1for i in zdf:bbb=bbb*(1+i/100)bb=(bbb-1)*100print('总收益率/%:',bb)print('夏普率:', np.mean(zdf)/np.std(zdf,ddof=1))ccc=1hc=1max_hc=[]for i in zdf:kk=ccc*(1+i/100)if kk<ccc:hc=hc*(1+i/100)else:hc=(hc-1)*100max_hc.append(hc)hc=1ccc=copy.deepcopy(kk)print('最大回撤/%:',abs(min(max_hc)))jssy()

得到结果是收益率5.858%,夏普率0.108,最大回撤2.26%。与沪深300指数相比,2021年1月1日到2021年3月31日沪深300的收益率是-3.13%,可以看出,策略收益领先沪深300指数。

5 总结

本文用相关性构建一个简单的交易策略,但还有许多工作没有完成,有兴趣的读者可以进行改善。比如调参,本文用1年数据来测试1个季度,读者们可以用2年数据测试1个季度,用1年数据测试1个月等等。或者用今天和前天数据计算相关性,或者用所有上市公司代替沪深300,或者取相关性最大的5组股票等等。一个好的策略是需要不断调参不断测试的。本文的策略虽然在2020年第一季度中收益率为5.858%,但没有考虑交易费用,实际收益大约4%。再次强调,本文仅供交流学习参考,不构成任何投资建议。炒股有风险,投资需谨慎。

完整代码

import tushare as tsimport pandas as pdimport numpy as npimport copypro = ts.pro_api('你的token')#1 获取沪深300成分股日线行情数据def hqsj_hs():df1 = pro.index_weight(index_code='399300.SZ', trade_date='20201231')df=pd.DataFrame()for i in range(len(df1)):df2 = pro.daily(ts_code=df1.iloc[i,1], start_date='20200101', end_date='20201231')df=pd.concat([df,df2],axis=0)df.to_excel('股票数据.xlsx',index=False)hqsj_hs()#股票数据.xlsx需要手动将excel表按股票代码和交易日期升序#2 计算相关性def xgx():df=pd.read_excel('股票数据.xlsx',engine='openpyxl')result={}for i in range(len(df)):key=df.iloc[i,0]if result.get(key,False):result[key].append(df.iloc[i,-3])else:result[key] = [df.iloc[i,-3]]result1=copy.deepcopy(result)for i in result:if len(result[i])!=243:del result1[i]for i in result1:result1[i].append([result1[i][1:],result1[i][:-1]])result2={}for i in result1:aa = {}now=pd.Series(result1[i][-1][0])for j in result1:pre=pd.Series(result1[j][-1][1])xgx=now.corr(pre)aa[j]=abs(xgx)result2[i]=aa#print(result2)result3={}for i in result2:result3[i]={max(zip(result2[i].values(), result2[i].keys()))[1]:max(zip(result2[i].values(), result2[i].keys()))[0]}xxx=[]for i in result3:for j in result3[i]:xxx.append(result3[i][j])b=sorted(xxx,reverse = True)[:1] #取相关性最大的result4={}for i in result3:for j in result3[i]:for x in b:if x==result3[i][j]:result4[i]={j:x}print(result4)return result4#3 获取21年数据def test_data():result4=xgx()ts_code=[]for i in result4:for j in result4[i]:ts_code.append(j)df = pd.DataFrame()for i in ts_code:df1 = pro.daily(ts_code=i, start_date='20210101', end_date='20210331')df = pd.concat([df, df1], axis=0)df.to_excel('股票数据1.xlsx', index=False)test_data()#4 买股方案def mgfa():df=pd.read_excel('股票数据1.xlsx',engine='openpyxl')timeseries=df['trade_date'].tolist()timetime=list(set(timeseries))timetime1=sorted(timetime)result4=xgx()ts1=[] #昨天ts2=[] #今天for i in result4:ts2.append(i)for j in result4[i]:ts1.append(j)result1={}for i in range(len(df)):time=df.iloc[i,1]if result1.get(time,False):aa.append(df.iloc[i,-3])else:aa=[]aa.append(df.iloc[i,-3])result1[time]=aaresult2={}for i in result1:if i!=20210331:aaa=[]for j in result1[i]:if j >0:aaa.append(ts2[result1[i].index(j)])result2[timetime1[timetime1.index(i)+1]]=aaaprint(result2)return result2mgfa()#5 获取测试数据def cssj():result4=xgx()ts_code=[]for i in result4:ts_code.append(i)df = pd.DataFrame()for i in ts_code:df1 = pro.daily(ts_code=i, start_date='20210101', end_date='20210331')df = pd.concat([df, df1], axis=0)df.to_excel('股票数据2.xlsx', index=False)cssj()#6 评估策略def jssy():result2=mgfa()result4=xgx()df=pd.read_excel('股票数据2.xlsx',engine='openpyxl')zdf=[]for i in result2:if len(result2[i]) == 1:for j in result2[i]:for x in range(len(df)):if df.iloc[x, 0] == j and df.iloc[x, 1] == i:zdf.append(df.iloc[x, -3])else:zdf.append(0)bbb=1for i in zdf:bbb=bbb*(1+i/100)bb=(bbb-1)*100print('总收益率/%:',bb)print('夏普率:', np.mean(zdf)/np.std(zdf,ddof=1))ccc=1hc=1max_hc=[]for i in zdf:kk=ccc*(1+i/100)if kk<ccc:hc=hc*(1+i/100)else:hc=(hc-1)*100max_hc.append(hc)hc=1ccc=copy.deepcopy(kk)print('最大回撤/%:',abs(min(max_hc)))jssy()