配對交易是指八十年代中期華爾街著名投行Morgan Stanley的數量交易員Nunzio Tartaglia成立的一個數量分析團隊提出的一種市場中性投資策略,
在實際操作中,其執行程序可以簡單地描述為:投資者首先選擇相互匹配的兩個資產,當配對資產價格差異增加的時候,做多價格偏低的資產,同時做空價格偏高的資產,而當價格差異減小的時候,則結束頭寸,完成交易;同時,為了控制風險,當價差進一步擴大時,需要在適當的止損點結束頭寸,
所以,想開發一個配對交易的策略,核心有兩個步驟:
1.找到待交易的標的,
比如說兩個走勢非常類似的股票或者其他證券,
2.對兩者的價差建模,
假設是兩者的價差會在一個穩定的區間波動(均值回歸),
————————————————
在以往的研究中,配對交易的標的的篩選方法有很多種,歸納起來大致有這兩種:
-
最小化偏差平方和法則(最小距離法)
-
協整理論方法
今天,我們以ETF為例,
首先獲取深交所的所有交易標的,剔除掉在今年才上市和已經退市的,篩選出深交所的所有ETF基金,然后通過相關性檢驗取出相關系數最強的一對cp進行配對交易,
具體執行如下:
1.先獲取深交所的所有交易標的,
import numpy as np
import pandas as pd
from gm.api import *
import matplotlib.pyplot as plt
set_token('xxxxxxxxxxxx')
#獲取深圳交易所全部標的
data1=get_instruments(exchanges='SZSE',df=True)
#剔除掉在今年才上市的標的
data1=data1[data1['listed_date']<'2020-12-30']
#剔除掉今天之前退市的標的
data1=data1[data1['delisted_date']>'2021-08-30']
data1.index=range(len(data1))
data1
2.取出ETF基金,
b=pd.DataFrame()
symbol=[]
for i in range(len(data1)):
if 'ETF' in data1['sec_name'][i]:
print(data1['sec_name'][i])
symbol.append(data1['symbol'][i])
if len(b)==0:
b=data1[data1['sec_name']==str(""+data1['sec_name'][i]+"")]
else:
b=b.append(data1[data1['sec_name']==str(""+data1['sec_name'][i]+"")])
b
獲取的部分ETF如下,一共114支,

3.獲取這114支ETF的最近半年的歷史資料代碼,
這里理論上應該獲取回測時間點前半年的資料出來研究,但這里暫且用今年前半年多的資料來研究,讀者可以自行修改資料的時間引數,
data2=pd.DataFrame()
for i in b['symbol']:
history_data = history(symbol=i, frequency='1d', start_time='2021-01-28',end_time='2021-07-30', fields='close', adjust=ADJUST_PREV, df= True)
data2["'"+i+"'"]=history_data['close']
最侄訓取的資料如下,一共122個交易日,114支ETF,

4.由于資料量太大,這里取出前六支ETF,計算相關系數并畫出熱力圖,如下所示:

5.根據相關系數進行排序,取出相關系數最強的十組進行“強行cp”,結果如下所示:

最終,根據數值選出的最佳配對為:SZSE.159801(廣發國證半導體芯片ETF) 和SZSE.159995(華夏國證半導體芯片ETF),其收盤價資料變化對比如下:

經計算,兩者在過去半年中的相關系數為99.99%,已是相當高了,我們接著再用配對交易的一般策略驗證這對標的進行配對交易的成效,
————————————————
策略思想:
獲取兩支ETF基金交易情況,如果停牌,則跳過,
計算前五分鐘,兩者收盤價差值,并計算差值的方差及平均值,
依據以上資料,構造差值的布林通道,
當價差上破布林上軌,做空價差(半倉),
當價差下破布林下軌,做多價差(半倉),
回測引數均設定為:
時間:2021-01-01至2021-08-10
調倉頻率:1天
基準指數:滬深300指數(SHSE.000300)
標的:SZSE.159801(廣發國證半導體芯片ETF)、SZSE.159995(華夏國證半導體芯片ETF)
滑點:0.0001
手續費:0.0001
策略收益概況:

(本次回測由掘金量化提供)
注:配對交易還有很多策略思想,市場中還有很多標的可以構建cp,此處拋磚引玉,僅供參考,
附錄:
# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
import numpy as np
#本策略基于掘金量化交易平臺 網址:www.myquant.cn
def init(context):
#獲得N根基金Bar資料
context.N=5
#選擇一對基金
context.stock=['SZSE.159801','SZSE.159995']
# 每個交易日的09:40 定時執行algo任務
schedule(schedule_func=algo, date_rule='1d', time_rule='09:40:00')
def algo(context):
# 獲取上一個交易日的日期
last_day = get_previous_trading_date(exchange='SZSE', date=context.now)
# 獲取當天有交易的基金
not_suspended = get_history_instruments(symbols=context.stock, start_date=last_day, end_date=last_day)
# 計算當天有交易非停牌的基金個數
a = len([item['symbol']for item in not_suspended if not item['is_suspended']])
#如果有一支停牌,就跳過
if a<2:
return
#獲得歷史交易資料
prices1 = history_n(symbol=context.stock[0], frequency='300s', count=context.N, end_time=last_day, fields='close',skip_suspended=True,adjust=ADJUST_PREV,df=True)
prices2 = history_n(symbol=context.stock[1], frequency='300s', count=context.N, end_time=last_day, fields='close',skip_suspended=True,adjust=ADJUST_PREV,df=True)
p1=list(prices1['close'])
p2=list(prices2['close'])
spread = np.array(p1[:-1]) - np.array(p2[:-1])
# 計算布林帶的上下軌
up = np.mean(spread) + 2 * np.std(spread)
down = np.mean(spread) - 2 * np.std(spread)
# 計算最新價差
spread_now = p1[-1] - p2[-1]
# 無交易時若價差上(下)穿布林帶上(下)軌則做空(多)價差
position_s1_long = context.account().position(symbol=context.stock[0], side=PositionSide_Long)
position_s2_long = context.account().position(symbol=context.stock[1], side=PositionSide_Long)
if not position_s1_long and not position_s2_long:
if spread_now > up:
order_target_percent(symbol=context.stock[1], percent=0.5, order_type=OrderType_Market,
position_side=PositionSide_Long)
print(context.stock[1],'價差上穿布林帶,做多價差')
if spread_now < down:
order_target_percent(symbol=context.stock[0], percent=0.5, order_type=OrderType_Market,
position_side=PositionSide_Long)
print(context.stock[0],'價差下穿布林帶,做空價差')
# 價差回歸時平倉
elif position_s2_long:
if spread_now <= up:
order_close_all()
print('價差回歸時平倉')
elif position_s1_long:
if spread_now >= down:
order_close_all()
print('價差回歸時平倉')
if __name__ == '__main__':
'''
strategy_id策略ID,由系統生成
filename檔案名,請與本檔案名保持一致
mode實時模式:MODE_LIVE回測模式:MODE_BACKTEST
token系結計算機的ID,可在系統設定-密鑰管理中生成
backtest_start_time回測開始時間
backtest_end_time回測結束時間
backtest_adjust股票復權方式不復權:ADJUST_NONE前復權:ADJUST_PREV后復權:ADJUST_POST
backtest_initial_cash回測初始資金
backtest_commission_ratio回測傭金比例
backtest_slippage_ratio回測滑點比例
'''
run(strategy_id='xxxxxxxxxxxxxxxxxxx',
filename='qixi.py',
mode=MODE_BACKTEST,
token='xxxxxxxxxxxxxxxxxxx',
backtest_start_time='2021-01-01 08:00:00',
backtest_end_time='2021-08-10 16:00:00',
backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)
宣告:本內容僅供學習、交流、演示之用,不構成任何投資建議!如需轉載請聯系掘金小Q(myquant2018)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/298428.html
標籤:區塊鏈
