Pairs Trading,即配對交易策略。其基本原理就是找出兩只走勢相關(guān)的股票。這兩只股票的價(jià)格差距從長期來看在一個(gè)固定的水平內(nèi)波動(dòng),如果價(jià)差暫時(shí)性的超過或低于這個(gè)水平,就買多價(jià)格偏低的股票,賣空價(jià)格偏高的股票。等到價(jià)差恢復(fù)正常水平時(shí),進(jìn)行平倉操作,賺取這一過程中價(jià)差變化所產(chǎn)生的利潤。為了實(shí)現(xiàn)協(xié)整套利,首先要針對不同的股票時(shí)間序列進(jìn)行協(xié)整分析,找到價(jià)格走勢高度相關(guān)的股票對。(原文鏈接在此,不想復(fù)制代碼的小伙伴可以到這里直接克隆運(yùn)行) 在 Python 的 Statsmodels 包中,有直接用于協(xié)整關(guān)系檢驗(yàn)的函數(shù) coint,該函數(shù)包含于 statsmodels.tsa.stattools 中。
import numpy as np
import pandas as pd
import statsmodels.api as sm
import seaborn as sns
復(fù)制代碼 首先,我們構(gòu)造一個(gè)讀取股票價(jià)格,判斷協(xié)整關(guān)系的函數(shù)。該函數(shù)返回的兩個(gè)值分別為協(xié)整性檢驗(yàn)的 p 值矩陣以及所有傳入的參數(shù)中協(xié)整性較強(qiáng)的股票對。我們不需要在意 p 值具體是什么,可以這么理解它: p 值越低,協(xié)整關(guān)系就越強(qiáng);p 值低于 0.05 時(shí),協(xié)整關(guān)系便非常強(qiáng)。
def find_cointegrated_pairs(dataframe):
# 得到DataFrame長度
n = dataframe.shape[1]
# 初始化p值矩陣
pvalue_matrix = np.ones((n, n))
# 抽取列的名稱
keys = dataframe.keys()
# 初始化強(qiáng)協(xié)整組
pairs = []
# 對于每一個(gè)i
for i in range(n):
# 對于大于i的j
for j in range(i+1, n):
# 獲取相應(yīng)的兩只股票的價(jià)格Series
stock1 = dataframe[keys[i]]
stock2 = dataframe[keys[j]]
# 分析它們的協(xié)整關(guān)系
result = sm.tsa.stattools.coint(stock1, stock2)
# 取出并記錄p值
pvalue = result[1]
pvalue_matrix[i, j] = pvalue
# 如果p值小于0.05
if pvalue < 0.05:
# 記錄股票對和相應(yīng)的p值
pairs.append((keys[i], keys[j], pvalue))
# 返回結(jié)果
return pvalue_matrix, pairs
復(fù)制代碼 然后我們設(shè)置要協(xié)整分析的股票范圍和分析的起止時(shí)間范圍,我們可以選擇畫出協(xié)整檢驗(yàn)熱度圖,這里畫的是1-pvalues,顏色越紅表示對應(yīng)的股票對協(xié)整關(guān)系越穩(wěn)定。
instruments =D.instruments()[0:20]
# 確定起始時(shí)間
start_date = '2015-01-01'
# 確定結(jié)束時(shí)間
end_date = '2017-02-18'
# 獲取股票總市值數(shù)據(jù),返回DataFrame數(shù)據(jù)格式
prices_temp = D.history_data(instruments,start_date,end_date,
fields=['close'] )
prices_df=pd.pivot_table(prices_temp, values='close', index=['date'], columns=['instrument'])
pvalues, pairs = find_cointegrated_pairs(prices_df)
#畫協(xié)整檢驗(yàn)熱度圖,輸出pvalue < 0.05的股票對
#sns.heatmap(1-pvalues, xticklabels=instruments, yticklabels=instruments, cmap='RdYlGn_r', mask = (pvalues == 1))
#print(pairs)
復(fù)制代碼 我們對pvalue排序,較小的pvalue表示對應(yīng)的股票對的協(xié)整關(guān)系越穩(wěn)定。
df = pd.DataFrame(pairs, index=range(0,len(pairs)), columns=list(['Name1','Name2','pvalue']))
#pvalue越小表示相關(guān)性越大,按pvalue升序排名就是獲取相關(guān)性從大到小的股票對
df.sort_values(by='pvalue')
復(fù)制代碼 我們選擇協(xié)整關(guān)系最強(qiáng)的一組股票對,繪制走勢圖并進(jìn)行最小二乘回歸,獲取回歸系數(shù)。
x = prices_df["000012.SZA"]
y = prices_df["000017.SZA"]
plt=x.plot();
plt.plot(y);
X = sm.add_constant(x)
result = (sm.OLS(y,X)).fit()
print(result.summary())
plt.legend(["000012.SZA", "000017.SZA"],loc='best')
復(fù)制代碼
根據(jù)獲得的回歸系數(shù),構(gòu)造回歸方程 y=const+coef*x 也就得到y(tǒng)-coef*x這個(gè)價(jià)差平穩(wěn)序列,畫出這個(gè)平穩(wěn)序列可以看出,雖然價(jià)差上下波動(dòng),但都會(huì)回歸中間的均值。 接著我們構(gòu)造z-score函數(shù),計(jì)算時(shí)間序列偏離了其均值多少倍的標(biāo)準(zhǔn)差
def zscore(series):
return (series - series.mean()) / np.std(series)
復(fù)制代碼 計(jì)算價(jià)差的zscore函數(shù)序列并繪圖
XZ=zscore(0.2048*x-y)
plt=XZ.plot()
plt.axhline(1.0, color="red", linestyle="--")
plt.axhline(-1.0, color="green", linestyle="--")
plt.legend(["z-score", "mean", "+1", "-1"])
復(fù)制代碼 可以看出此序列基本在-1到1之間波動(dòng),當(dāng)兩這個(gè)序列的 z-score序列 突破 1 或者 ?1 時(shí),說明兩支股票的價(jià)差脫離了統(tǒng)計(jì)概念中的合理區(qū)間,如果它們的協(xié)整關(guān)系能夠保持,那么它們的價(jià)差應(yīng)該收斂 結(jié)合上圖,當(dāng) z-score 突破上方紅線時(shí),說明y-coef*x高估,推測此差值應(yīng)在未來降低到合理的波動(dòng)區(qū)間,因此可以賣空1份的y標(biāo)的,買入coef份的x標(biāo)的,等待y-coef*x回歸到0附近時(shí)平倉獲利;反之,當(dāng) z-score 突破下方綠線時(shí),說明y-coef*x低估,推測此差值應(yīng)在未來上升加到合理的波動(dòng)區(qū)間,因此可以買入1份的y標(biāo)的,賣空coef份的x標(biāo)的,等待y-coef*x回歸到0附近時(shí)平倉獲利。
|