天天看點

用趨勢突破政策回測CTA

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