一個思路,利用T檢驗去尋找量化交易CTA趨勢

張國平發表於2019-12-19


經過一段時間學習和實踐,感覺對於期貨擇時交易,跟隨趨勢基本上可以被認為是不二途徑。那麼對於CTA交易策略來說,及早發現趨勢是非常重要。尋找趨勢的方法很多,經典的比如均線快慢線交叉,布林帶還有其他各種時序動量指標,這裡推薦看看公眾號刀疤連的一邊大作‘和趨勢做純純的朋友’,有非常全面分析。


在實踐中,發現經常陷入一個兩難局面,一方面是希望及時發現趨勢,這樣不可避免就是的判定閾值變得敏感;往往就是敏感的指標被市場白噪聲和某些蓄意大寶劍圖形(針對趨勢交易者的迅速拉昇然後砸下來圖形)觸發,被來回打臉,連續虧損。另一個方面為了避免被來回打臉,調高觸發指標,又會導致錯失趨勢。


之前一直嘗試用流水線質檢的方法去尋找趨勢策略, 和分析時序序列有點相似。質檢時候,要及時發現產出是否有生產線問題,如果晚了,大量殘次品出來;如果太敏感,把個體隨機問題認為是生產問題,又會因為生產線停機檢修造成損失。之前用的CUSUM就是這個方法。


最近有一個思路,嘗試用T 檢驗這個方法去發現趨勢。關於T 檢驗現在也廣泛用在質量檢測,藥效測試。這裡面還有個典故,T檢驗是戈斯特為了觀測釀酒質量而發明的。戈斯特在位於都柏林的健力士釀酒廠擔任統計學家。戈斯特於1908年在Biometrika上公佈T檢驗,但因其老闆認為其為商業機密而被迫使用筆名(學生),所以有時候也叫學生檢驗。


這裡不準備講解具體檢驗數學邏輯,具體可以搜尋之,這裡只是說說應用;因為也是邊學邊用,有錯漏這出。

T檢驗有三種主要型別:

1.獨立樣本t檢驗:比較兩組獨立樣本平均值的方法,這裡要求兩組樣本 方差相等,即具有方差齊性。

2.配對樣本t檢驗:比較同一組中不同時間(例如,相隔一年)平均值的方法。

3.單一樣本t檢驗:檢驗單個組的平均值對照一個已知的平均值。


python的庫stats已經提供T檢驗,就是stats.ttest_ind/ stats.ttest_rel/ stats.test_1samp 方法, 示例程式碼如下:

這裡生成兩個正態分佈佇列,方法很簡單,返回T值,和P值;T值越接近0,則可認為假設可成立,如果T值離0值越遠,比如[1,-1]之外,則假設不成立,正均值想上,小於0均值向下。

import numpy as np
import numpy.matlib
a1 = np.random.normal(0,0.1,30) #均值為0,標準差為0.1的30個佇列
b1 = np.random.normal(1,0.2,30)  #均值為1,標準差為0.2的30個佇列
t2, p2= stats.ttest_rel(a1, b1) #配對T檢驗,a1比b1,如果t值為負,p值小於0.05,說明均值a1小於b1,a1和b1同一個佇列假設不成立
print("t2 = " + str(t2))
print("p2 = " + str(p2))
t4, p4= stats.ttest_1samp(a1, 0) #樣本T檢驗,a1對比0,如果t只在1,-1之間,說明a1均值為0,假設成立
print("t4 = " + str(t4))
print("p4 = " + str(p4))
t5, p5= stats.ttest_1samp(b1, 0) #樣本T檢驗,b1對比0,如果t值不在1,-1之間,說明b1均值為0,假設不成立
print("t5 = " + str(t5))
print("p5 = " + str(p5))



這裡還有個前提,就是樣本是來自正態分佈總體的隨機樣本。而我們日常所用的期貨價格分佈並不是正態分佈,就像CUSUM裡面用的,這裡使用時段(5分鐘)的對數收益率,顯示為近似正態分佈,均值近似為0。可以考慮是否去極值,就是計算出標準差,然後將其中大於 u+3σ 的置換為u+3σ,將小於u-3σ 的置換為u-3σ,消除跳開的衝擊。

下圖為示意圖,從close轉為對數收益率,和對數收益率分佈。


在CTA趨勢發現時候, 這裡使用主要是 配對樣本t檢驗和單一樣本t檢驗。

配對樣本t檢驗:是按照時段進行對比,這裡可以有相互部分覆蓋的時段序列對比,比如 [t-30, t-10]和[t-20,t]對比,中間可以有10個時段相互覆蓋。如果前後兩個時間佇列的T檢驗發現T值為正且大於1則,相對過往時段有趨勢向上;反正向下。

單一樣本t檢驗,用一段時間段和均值0對比,如果值在[-1.1]之間,可以認為其實沒有趨勢,如果大於1或者小於-1,則可以認為有向上或向下趨勢。


簡單程式碼檢測, 是用5分鐘對數收益率進行配對和樣本T檢測,如果連續3個配對樣本的T值都大於1,或都小於-1,則去向上或向下。

from scipy import stats
from scipy.stats import norm,t
import matplotlib.pyplot as plt
logdata = pd.DataFrame()
logdata['close'] = np.log(dfrb5min['close'])   # 對數化傳入5分鐘close佇列dfrb5min['close']
logdata['closeIndexDiff_1'] = logdata['close'].diff()  # 1階差分處理,求出對數收益率
t = 40
for i in range(t,len(logdata['close'])):
    #求出配對T檢測t4
    t4, p4= stats.ttest_rel(logdata['closeIndexDiff_1'][i-20+1:i+1],logdata['closeIndexDiff_1'][i-30+1:i-10+1])
    #求出樣本T檢測p0
    t0, p0 = stats.ttest_1samp(logdata['closeIndexDiff_1'][i-15+1:i+1],0)
    logdata.loc[i,'t'] = t4
    logdata.loc[i,'t1samp'] = t0
    
    #如果絕對值大於0,則使用
    if abs(t0) > 1.0:
        logdata.loc[i,'t0Index'] = t0
    else:
        logdata.loc[i,'t0Index'] = 0
        
    if abs(t4) > 1.0:
        logdata.loc[i,'tIndex'] = t4
    else:
        logdata.loc[i,'tIndex'] = 0
#csv輸出   
logdata.to_csv("C:\\Project\\MA8888va1min5v3.csv", index=True, header=True)
closeArray = np.array(dfrb5min['close'])
listup,listdown = [],[]
for i in range(1,len(logdata['closeO'])):
    if logdata.loc[i-1,'tIndex'] >1 and logdata.loc[i,'tIndex']>1 and logdata.loc[i-1,'t0Index'] >1 and logdata.loc[i,'t0Index']>1 and logdata.loc[i-2,'tIndex']>1 and logdata.loc[i-2,'t0Index'] >1 :
        listup.append(i)
    elif (logdata.loc[i,'tIndex'] < -1 and logdata.loc[i-1,'tIndex'] <-1) and (logdata.loc[i,'t0Index'] < -1 and logdata.loc[i-1,'t0Index'] <-1) and logdata.loc[i-2,'tIndex']<-1 and logdata.loc[i-2,'t0Index'] <-1 :
        listdown.append(i) 
fig=plt.figure(figsize=(18,6))
plt.plot(closeArray, color='y', lw=2.)
plt.plot(closeArray, '^', markersize=5, color='r', label='UP signal', markevery=listup)
plt.plot(closeArray, 'v', markersize=5, color='g', label='DOWN signal', markevery=listdown)
plt.legend()
plt.show()


從示例圖來看,有一定趨勢發現能力,但是還是陷入短趨勢困境,這個是時序佇列長度選取,t值都有關係,還是要進一步最佳化。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22259926/viewspace-2669415/,如需轉載,請註明出處,否則將追究法律責任。

相關文章