以下是小哥用趨勢突破政策回測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 %