python统计套利_基于python的统计套利实战(四)之策略实现
一、交易對象選取
我們以商品期貨市場的螺紋鋼品種的跨期套利為例,選取兩組不同到期月份的同種商品期貨合約作為交易對象。
相關性檢驗
通過新浪財經的期貨數據接口爬取螺紋鋼rb1903到rb1908的六組數據,先看一下它們的走勢:
import?pandas?as?pd
import?numpy?as?np
import?matplotlib.pyplot?as?plt
import?seaborn?as?sns
import?urllib.request?as?urllib2
import?json
def?findPairs():
ids?=?['rb1903',?'rb1904',?'rb1905',?'rb1906',?'rb1907',?'rb1908']
url_5m?=?'http://stock2.finance.sina.com.cn/futures/api/json.php/IndexService.getInnerFuturesMiniKLine5m?symbol='
result?=?[]
for?id?in?ids:
url?=?url_5m?+?id
req?=?urllib2.Request(url)
rsp?=?urllib2.urlopen(req)
res?=?rsp.read()
res_json?=?json.loads(res)
result.append(res_json)
close_result?=?[]
for?instrument?in?result:
oneDay_list?=?[]
for?oneDay?in?instrument:
oneDay_list.append(float(oneDay[-2]))
close_result.append(np.array(oneDay_list))
close_result?=?np.array(close_result)
close_result?=?close_result.T
df?=?pd.DataFrame(data=close_result,?columns=ids)
df.plot()
plt.show()
從價格的走勢圖中,可以看出 rb1903 和 rb1904 以及 rb1908 和 rb1907 的走勢上存在很強的相關性,下面畫出它們之間的相關矩陣。
sns.heatmap(df.corr(),?annot=True,?square=True)
plt.show()
正如我們所推斷的, rb1903 和 rb1904 以及 rb1908 和 rb1907這兩組之間具有很強的相關性,其中,rb1907 和 rb1908 之間的相關程度最大,所以下面我們將選取 rb1907 和 rb1908作為配對交易的品種。
ADF檢驗
下面對這兩組數據進行平穩性檢驗。
from?statsmodels.tsa.stattools?import?adfuller
def?check():
df?=?pd.read_csv('./data.csv')
price_A?=?df['rb1907'].values
price_B?=?df['rb1908'].values
result_A?=?adfuller(price_A)
result_B?=?adfuller(price_B)
print(result_A)
print(result_B)
結果如下:
(-1.7605803524947852,?0.4002005032657946,?3,?238,?{'1%':?-3.458128284586202,?'5%':?-2.873761835239286,?'10%':?-2.5732834559706235},?1750.3205777927317)
(-1.6918211072949225,?0.4353313388810546,?2,?239,?{'1%':?-3.458010773719797,?'5%':?-2.8737103617125186,?'10%':?-2.5732559963936206},?1776.486392805771)
從結果可以看出 t-statistic 的值要大于10%,所以說無法拒絕原假設,也就是原數據都是非平穩的。
下面進行一階差分之后檢查一下:
def?check():
df?=?pd.read_csv('./data.csv')
price_A?=?df['rb1907'].values
price_B?=?df['rb1908'].values
price_A?=?np.diff(price_A)
price_B?=?np.diff(price_B)
result_A?=?adfuller(price_A)
result_B?=?adfuller(price_B)
print(result_A)
print(result_B)
結果如下:
(-7.519664365222082,?3.820429924735319e-11,?2,?238,?{'1%':?-3.458128284586202,?'5%':?-2.873761835239286,?'10%':?-2.5732834559706235},?1744.3991445433894)
(-9.917570016245815,?3.051148786023717e-17,?1,?239,?{'1%':?-3.458010773719797,?'5%':?-2.8737103617125186,?'10%':?-2.5732559963936206},?1770.1154237195128)
結果可以看出,一階差分之后的數據是平穩的,也就是說原數據是一階單整的,滿足協整關系的前提,所以下一步我們對這兩組數據進行協整檢驗,來探究兩者是否是協整的。
協整檢驗
from?statsmodels.tsa.stattools?import?coint
def?check():
df?=?pd.read_csv('./data.csv')
price_A?=?df['rb1907'].values
price_B?=?df['rb1908'].values
print(coint(price_A,?price_B))
(-3.6104387172088277,?0.02378223384906601,?array([-3.94246081,?-3.36160059,?-3.06209517]))
結果看出 t-statistic 小于5%,所以說有95%的把握說兩者具有協整關系。
二、主體策略
下面將構建配對交易的策略,統計套利的關鍵是要保證策略的市場中性,也就是說無論市場的趨勢是上升還是下降,都要使策略或者預期的收益為正。
投資組合的構建
配對交易主要分析的對象是兩個品種價格之間的偏離,由均值回歸理論知,在股票、期貨或者其他金融衍生品的交易市場中,無論高于或低于價值中樞(或均值)都有很高的概率向價值中樞回歸的趨勢。所以說,在具有協整關系的這兩組數據中,當它們兩者的價差高與均值時則會有向低走的趨勢,價差低于均值時則會有向高走的趨勢。
下面得到去中心化后的價差序列:
def?strategy():
df?=?pd.read_csv('./data.csv')
price_A?=?df['rb1907'].values
price_B?=?df['rb1908'].values
spread?=?price_A?-?price_B
mspread?=?spread?-?np.mean(spread)
fig?=?plt.figure()
ax?=?fig.add_subplot(111)
ax.plot(range(len(mspread)),?mspread)
ax.hlines(0,?0,?len(mspread))
plt.show()
注意這里直接研究的是 A、B 價格差值,統計套利策略中通常會將 B 價格乘以一個協整系數,研究的對象是它們的殘差,由于協整檢驗后可以知道它們的殘差具有平穩性,所以更好的應用均值回歸的理論。
設置開倉和止損的閾值
為了使開倉和止損的閾值更好地比較,所以就將開倉閾值設置為窗口內數據的兩倍標準差,止損設置為三倍標準差。這個標準差的倍數可以通過調參來不斷調優,標準差的設置也可以通過 GARCH 等模型擬合的自回歸條件異方差類似的時變標準差來代替。
def?strategy():
df?=?pd.read_csv('./data.csv')
price_A?=?df['rb1907'].values
price_B?=?df['rb1908'].values
spread?=?price_A?-?price_B
mspread?=?spread?-?np.mean(spread)
sigma?=?np.std(mspread)
fig?=?plt.figure()
ax?=?fig.add_subplot(111)
ax.plot(range(len(mspread)),?mspread)
ax.hlines(0,?0,?len(mspread))
ax.hlines(2?*?sigma,?0,?len(mspread),?colors='b')
ax.hlines(-2?*?sigma,?0,?len(mspread),?colors='b')
ax.hlines(3?*?sigma,?0,?len(mspread),?colors='r')
ax.hlines(-3?*?sigma,?0,?len(mspread),?colors='r')
plt.show()
三、歷史回測
下面就以樣本內數據進行回測一下:
def?strategy():
df?=?pd.read_csv('./data.csv')
price_A?=?df['rb1907'].values
price_B?=?df['rb1908'].values
spread?=?price_A?-?price_B
mspread?=?spread?-?np.mean(spread)
sigma?=?np.std(mspread)
open?=?2?*?sigma
stop?=?3?*?sigma
profit_list?=?[]
hold?=?False
hold_price_A?=?0
hold_price_B?=?0
hold_state?=?0???#?1?(A:long?B:short)???-1?(A:short?B:long)
profit?=?0
for?i?in?range(len(price_A)):
if?hold?==?False:
if?mspread[i]?>=?open:
hold_price_A?=?price_A[i]
hold_price_B?=?price_B[i]
hold_state?=?-1
hold?=?True
elif?mspread[i]?<=?-open:
hold_price_A?=?price_A[i]
hold_price_B?=?price_B[i]
hold_state?=?-1
hold?=?True
else:
if?mspread[i]?>=?stop?and?hold_state?==?-1?:
profit?=?(hold_price_A?-?price_A[i])?+?(price_B[i]?-?hold_price_B)
hold_state?=?0
hold?=?False
if?mspread[i]?<=?-stop?and?hold_state?==?1?:
profit?=?(price_A[i]?-?hold_price_A)?+?(hold_price_B?-?price_B[i])
hold_state?=?0
hold?=?False
if?mspread[i]?<=?0?and?hold_state?==?-1:
profit?=?(hold_price_A?-?price_A[i])?+?(price_B[i]?-?hold_price_B)
hold_state?=?0
hold?=?False
if?mspread[i]?>=?0?and?hold_state?==?1:
profit?=?(price_A[i]?-?hold_price_A)?+?(hold_price_B?-?price_B[i])
hold_state?=?0
hold?=?False
profit_list.append(profit)
print(profit_list)
fig?=?plt.figure()
ax?=?fig.add_subplot(111)
ax.plot(range(len(profit_list)),?profit_list)
plt.show()
收益結果如下:
可以看出回測結果是很不盡人意的,因為我們并沒有對參數進行調優,從前面可以知道統計套利單次的收益是比較薄弱的,主要原因不僅僅是價差帶來的這種相對收益本來就比較低,還有就是止損閾值設置的問題,有時一次止損就會cover掉之前所有的收益。所以說在統計套利中,閾值的設置是非常重要的。
四、注意
1、為了方便操作,以上實驗的策略構建以及歷史回測都是樣本內進行測試的,真正的策略回測要劃分訓練數據和測試數據,進行樣本外測試。
2、在選擇配對數據的品種時,除了要考慮配對品種的相關性之外,還要考慮品種的市場流動性等因素。
3、歷史回測時,還需要將手續費、滑點等因素考慮進去。
總結
以上是生活随笔為你收集整理的python统计套利_基于python的统计套利实战(四)之策略实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器人门禁控制盒怎么接线方法_机器人自助
- 下一篇: java odbc 实现access连接