以下是小哥用趋势突破策略回测CTA的代码和结果,错误的地方还请大家提出来。
标的是螺纹钢的主力连续合约
#%% 趋势突破策略
# 导入包
import pandas as pd
import matplotlib.pyplot as plt
#%% 导入和清洗数据
RBL=pd.read_excel('H:/RBL8.xlsx')
RBL.index=pd.to_datetime(RBL.iloc[:,0])
RBL=RBL['2014':'2017']
RBL=RBL.iloc[:,1:5]
RBL.columns=('Open','High','Low','Close')
#%% 策略
#输入收盘价
#输出交易信号和仓位
def dt(tsc):
ma5=pd.Series(0,index=tsc.index[19:])
ma15=pd.Series(0,index=tsc.index[19:])
ma20=pd.Series(0,index=tsc.index[19:])
Signal=pd.Series(0,index=tsc.index[19:]) #信号
Case=pd.Series(0,index=tsc.index[19:]) #仓位
#计算MA
for i in range(len(tsc)-19):
ma5[i]=tsc[i+15:i+20].mean()
ma15[i]=tsc[i+5:i+20].mean()
ma20[i]=tsc[i:i+20].mean()
#画出MA曲线
plt.figure('MA曲线')
plt.plot(tsc[19:],label='Close')
plt.plot(ma5,label='MA5')
plt.plot(ma20,label='MA20')
plt.legend()
#写出策略
for i in range(len(Signal)-1):
Case[i+1]=Case[i]
if ma5[i]>ma20[i] and Case[i]<1:
Signal[i]=1
Case[i+1]=1
elif ma5[i]<ma20[i] and Case[i]>-1:
Signal[i]=-1
Case[i+1]=-1
return Signal,Case
#%% 回测
[sig,ca]=dt(RBL['Close'])
#%% 输出收盘价、交易信号、持仓情况
plt.figure('输出收盘价、交易信号、持仓情况')
plt.subplot(3,1,1)
plt.plot(RBL['Close'])
plt.title('收盘价')
plt.subplot(3,1,2)
plt.plot(sig)
plt.title('交易信号')
plt.subplot(3,1,3)
plt.plot(ca)
plt.title('持仓情况')
#%% 指标评价
# 累计收益、年化收益率、标的收益率、胜率、持仓时间、交易次数、最大回撤
#累计收益率
def all_re(tsc,Case):
re=tsc.diff().dropna() #以收盘价衡量的每日收益
day_profit=pd.Series(index=Case.index) #持仓后每日的收益
for i in range(len(Case)):
day_profit[i]=Case.iloc[i]*re[Case.index[i]]*5
#累计收益
acc_profit=day_profit.cumsum()
#保证金,以持仓初始日的保证金为本金买入一手
insur=tsc[Case.index[0]]*0.05+10000
#年化收益:日收益率的平均值做成年化
day_rate=acc_profit[-1]/(insur*len(acc_profit))
anual_rate=day_rate*250
#标的收益率
bid_re=tsc[-1]/(insur*len(tsc))
return acc_profit+insur,anual_rate,bid_re
#%% 交易次数、多头次数、空头次数
def trade_num(sig):
return len(sig[sig!=0]),len(sig[sig==1]),len(sig[sig==-1])
#%% 持仓时间
def in_case(case):
return len(case[case!=0])
#%% 回撤、最大回撤
def tradeback(tsc,Case):
tb=pd.Series(0,index=Case.index)
re=tsc.diff().dropna() #以收盘价衡量的每日收益
day_profit=pd.Series(index=Case.index) #持仓后每日的收益
for i in range(len(Case)):
day_profit[i]=Case.iloc[i]*re[Case.index[i]]*5
insur=tsc[Case.index[0]]*0.05+10000
#累计收益
acc_profit=day_profit.cumsum()+insur
#回撤率
for i in range(10,len(tb)-1):
if acc_profit[i]>0:
tb.iloc[i]=abs((max(acc_profit[:i+1])-acc_profit[i+1])/max(acc_profit[:i+1]))
#返回回撤率、最大回撤率
return tb,max(tb)
#%%计算胜率
def victor(tsc,Case):
ca_re=pd.Series(0,index=Case.index)
re=tsc.diff().dropna()
for i in range(len(Case)):
ca_re.iloc[i]=Case.iloc[i]*re[Case.index[i]]
vi=len(ca_re[ca_re>0])/len(Case)
return vi
#%% 输出累计收益率,回撤
plt.figure('累计收益、回撤')
plt.subplot(2,1,1)
plt.plot(all_re(RBL['Close'],ca)[0])
plt.title('累计收益')
plt.subplot(2,1,2)
plt.plot(tradeback(RBL['Close'],ca)[0]*100)
plt.title('回撤')
#%% 各项指标
print('年化收益率:',all_re(RBL['Close'],ca)[1]*100,'%')
print('\n标的收益率:',all_re(RBL['Close'],ca)[2]*100,'%')
print('\n交易次数:',trade_num(sig)[0],'\n多头次数:',trade_num(sig)[1],\
'\n空头次数:',trade_num(sig)[2])
print('\n胜率:',victor(RBL['Close'],ca))
print('\n持仓时间:',in_case(ca))
print('\n最大回撤:',tradeback(RBL['Close'],ca)[1]*100,'%')
年化收益率: 19.2994218941 %
标的收益率: 0.0382150782476 %
交易次数: 43
多头次数: 21
空头次数: 22
胜率: 0.5005224660397074
持仓时间: 956
最大回撤: 38.5974300685 %