生活随笔
收集整理的這篇文章主要介紹了
CTP接口python实现跨品种套利策略源码
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原理
什么是套利?
套利是指在買入或賣出一種金融資產(chǎn)的同時(shí)賣出或買入另一種相關(guān)的金融資產(chǎn)從中利用價(jià)差獲得套利的過程。
什么是跨品種套利?
當(dāng)兩個(gè)合約有很強(qiáng)的相關(guān)性時(shí),可能存在相似的變動(dòng)關(guān)系,兩種合約之間的價(jià)差會(huì)維持在一定的水平上。當(dāng)市場出現(xiàn)變化時(shí),兩種合約之間的價(jià)差會(huì)偏離均衡水平。此時(shí),可以買入其中一份合約同時(shí)賣出其中一份合約,當(dāng)價(jià)差恢復(fù)到正常水平時(shí)平倉,獲取收益。
以大商所玉米和淀粉為例,合約分別為c1801和cs1801。二者之間相關(guān)性為0.7333,價(jià)差處于相對(duì)穩(wěn)定合理區(qū)間。如圖所示。
二者價(jià)差整體處于250-350之間。當(dāng)價(jià)差偏離此區(qū)間時(shí),可以進(jìn)行跨品種套利。
跨品種套利有以下幾個(gè)特點(diǎn):
1.套利的兩種資產(chǎn)必須有一定的相關(guān)性。2.兩種合約標(biāo)的不同,到期時(shí)間相同。3.兩種資產(chǎn)之間的價(jià)差呈現(xiàn)一定規(guī)律。
怎樣確定合約之間有相關(guān)性?
最常用的方法是利用EG兩步法對(duì)兩個(gè)序列做協(xié)整檢驗(yàn),判斷兩個(gè)序列是否平穩(wěn)。只有單整階數(shù)相同,二者才有可能存在一定的關(guān)系。
以大豆和豆粕為例,選取其在2017年1月1日至2018年1月1日的主力合約價(jià)格時(shí)間序列,利用statsmodels包進(jìn)行協(xié)整檢驗(yàn)。
檢驗(yàn)結(jié)果為:焦炭的t = -1.7886,1%置信區(qū)間的臨界值為-3.4576,說明該序列在99%的置信水平下平穩(wěn)。焦煤的t = -2.0500,1%置信區(qū)間的臨界值為-3.4576,說明該序列在99%的置信水平下平穩(wěn)。
因此,二者都為平穩(wěn)序列。
利用OLS回歸檢殘差序列是否平穩(wěn),殘差的t=-2.3214,臨界值為-3.4577,說明殘差平穩(wěn)。因此,可以認(rèn)為二者之間存在一定的關(guān)系。
回歸后的殘差圖如下:
對(duì)殘差進(jìn)行ks檢驗(yàn),檢驗(yàn)結(jié)果p=0,說明殘差分布為正態(tài)分布。
策略設(shè)計(jì)
傳統(tǒng)利用價(jià)差進(jìn)行跨品種套利的方法是計(jì)算出均值和方差,設(shè)定開倉、平倉和止損閾值。當(dāng)新的價(jià)格達(dá)到閾值時(shí),進(jìn)行相應(yīng)的開倉和平倉操作。
應(yīng)該怎樣確定均值?
均值的選取主要有兩種方法,第一種方法是固定均值。先按歷史價(jià)格計(jì)算相應(yīng)的閾值(比如利用2017年2月-2017年6月的數(shù)據(jù)計(jì)算閾值,在2019年7月進(jìn)行套利),再用最新價(jià)差進(jìn)行比較,會(huì)發(fā)現(xiàn)前后均值差異很大。如圖所示。
因此,常用變動(dòng)的均值設(shè)定閾值。即用過去N天兩個(gè)標(biāo)的之間差值的均值和方差。
策略思路
第一步:選擇相關(guān)性較高的兩個(gè)合約,本例選擇大商所的焦炭和焦煤。第二步:以過去30個(gè)的1d頻率bar的均值正負(fù)0.75個(gè)標(biāo)準(zhǔn)差作為開倉閾值,以正負(fù)2個(gè)標(biāo)準(zhǔn)差作為止損閾值。第三步:最新價(jià)差上穿上界時(shí)做空價(jià)差,回歸到均值附近平倉;下穿下界時(shí)做多價(jià)差,回歸到均值附近平倉。設(shè)定止損點(diǎn),觸發(fā)止損點(diǎn)則全部平倉。
策略代碼
"""
關(guān)注: Ctp接口量化"""
from _ctp
import *
from Config
import Config
import numpy
as np
class Arbitrage_Strategy(Strategy
):def __init__(self
):super().__init__
()self
.symbol_lsit
= ['j1901', 'jm1901']self
.bar_time
= BarType
.Min self
.StrategyType
= StrategyType
.Bar
def on_trade(self
, trade
):print(trade
)def on_tick(self
, tick
=None):print(tick
.InstrumentID
,tick
.LastPrice
) def on_bar(self
, tick
=None, Bar
=None):symbol
= tick
.InstrumentID
print(self
.GetData
(symbol
)) j_close
= self
.GetData
(self
.symbol_lsit
[0])jm_close
= self
.GetData
(self
.symbol_lsit
[1])new_price
= j_close
[-1] - jm_close
[-1]spread_history
= j_close
[:-2] - jm_close
[:-2]self
.spread_history_mean
= np
.mean
(spread_history
)self
.spread_history_std
= np
.std
(spread_history
)self
.up
= self
.spread_history_mean
+ 0.75 * self
.spread_history_stdself
.down
= self
.spread_history_mean
- 0.75 * self
.spread_history_stdself
.up_stoppoint
= self
.spread_history_mean
+ 2 * self
.spread_history_stdself
.down_stoppoint
= self
.spread_history_mean
- 2 * self
.spread_history_std
print(self
.Get_Position
(self
.symbol_lsit
[0])) print(self
.Get_Position
(self
.symbol_lsit
[1])) position_j_long
= self
.GetPosition
(self
.symbol_lsit
[0],"Long") position_j_short
= self
.GetPosition
(self
.symbol_lsit
[0],"Short") position_jm_long
= self
.GetPosition
(self
.symbol_lsit
[1],"Long") position_jm_short
= self
.GetPosition
(self
.symbol_lsit
[1],"Short") if not position_jm_short
and not position_jm_long
:if new_price
> self
.up
:print('做空價(jià)差組合')self
.send
(self
.symbol_lsit
[0], DirectionType
.Sell
, OffsetType
.Open
, j_close
[-1], 1, OrderType
.Limit
) self
.send
(self
.symbol_lsit
[1], DirectionType
.Buy
, OffsetType
.Open
, jm_close
[-1], 1, OrderType
.Limit
) if new_price
< self
.down
:print('做多價(jià)差組合')self
.send
(self
.symbol_lsit
[0], DirectionType
.Buy
, OffsetType
.Open
, j_close
[-1], 1, OrderType
.Limit
) self
.send
(self
.symbol_lsit
[1], DirectionType
.Sell
, OffsetType
.Open
, jm_close
[-1], 1, OrderType
.Limit
) if position_jm_long
:if new_price
>= self
.spread_history_mean
:print('價(jià)差回歸到均衡水平,平倉')self
.send
(self
.symbol_lsit
[0], DirectionType
.Sell
, OffsetType
.Close
, j_close
[-1], position_j_long
["總持倉"], OrderType
.Limit
) self
.send
(self
.symbol_lsit
[1], DirectionType
.Buy
, OffsetType
.Close
, jm_close
, position_jm_long
["總持倉"], OrderType
.Limit
)if new_price
< self
.down_stoppoint
:print('價(jià)差超過止損點(diǎn),平倉止損')self
.send
(self
.symbol_lsit
[0], DirectionType
.Sell
, OffsetType
.Close
, j_close
[-1], position_j_long
["總持倉"], OrderType
.Limit
) self
.send
(self
.symbol_lsit
[1], DirectionType
.Buy
, OffsetType
.Close
, jm_close
[-1], position_jm_long
["總持倉"], OrderType
.Limit
)if position_jm_short
:if new_price
<= self
.spread_history_mean
:print('價(jià)差回歸到均衡水平,平倉')self
.send
(self
.symbol_lsit
[0], DirectionType
.Buy
, OffsetType
.Close
, j_close
[-1], position_j_short
["總持倉"], OrderType
.Limit
) self
.send
(self
.symbol_lsit
[1], DirectionType
.Sell
, OffsetType
.Close
, jm_close
[-1], position_jm_short
["總持倉"], OrderType
.Limit
)if new_price
> self
.up_stoppoint
:print('價(jià)差超過止損點(diǎn),平倉止損')self
.send
(self
.symbol_lsit
[0], DirectionType
.Buy
, OffsetType
.Close
, j_close
[-1], position_j_short
["總持倉"], OrderType
.Limit
) self
.send
(self
.symbol_lsit
[1], DirectionType
.Sell
, OffsetType
.Close
, jm_close
[-1], position_jm_short
["總持倉"], OrderType
.Limit
)
if __name__
== '__main__':t
= CTP
(Arbitrage_Strategy
())t
.Login
(Config
)
注:此策略只用于學(xué)習(xí)、交流、演示,不構(gòu)成任何投資建議。
總結(jié)
以上是生活随笔為你收集整理的CTP接口python实现跨品种套利策略源码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。