均值回归套利
基差套利,现货运用期权合成,与期货可以进行双方向套利
手续费按照3.5计算
读取数据
import pandas as pd
import numpy as np
import time
import datetime as dt
from datetime import date, datetime, timedelta
from math import exp
import matplotlib.pyplot as plt
from scipy.stats import norm
import seaborn as sns
df= pd.read_excel(r"C:\Users\zhang\Desktop\中泰证券\2021-07\基差套利\需要用到数据集_08013_new.xlsx",index_label=False)
#df = df_jc
df = df.dropna()
df.set_index(["Time"], inplace=True)
df.index = df.index.strftime('%Y-%m-%d %H:%M:%S')
df['jc'] = 0.0000
df['mspread'] = 0.0000
df['jz'] = 0
df['mavg4700'] = df['4700'].rolling(window=600, min_periods=600, center=False).mean()
df['mavg4800'] = df['4800'].rolling(window=600, min_periods=600, center=False).mean()
df['mavg4900'] = df['4900'].rolling(window=600, min_periods=600, center=False).mean()
df['mavg5000'] = df['5000'].rolling(window=600, min_periods=600, center=False).mean()
df['mavg5250'] = df['5250'].rolling(window=600, min_periods=600, center=False).mean()
df['ms4700'] = df['4700']-df['mavg4700']
df['ms4800'] = df['4800']-df['mavg4800']
df['ms4900'] = df['4900']-df['mavg4900']
df['ms5000'] = df['5000']-df['mavg5000']
df['ms5250'] = df['5250']-df['mavg5250']
df = df.dropna()
sigma = 1.3
#删除变动过大的异常值
df['diff'] = 0
df['diff'][1:len(df.index)] = np.diff(df['ms4700'])
df = df[abs(df['diff'])<5]
df['diff'][1:len(df.index)] = np.diff(df['ms4800'])
df = df[abs(df['diff'])<5]
df['diff'][1:len(df.index)] = np.diff(df['ms4900'])
df = df[abs(df['diff'])<5]
df['diff'][1:len(df.index)] = np.diff(df['ms5000'])
df = df[abs(df['diff'])<5]
df['diff'][1:len(df.index)] = np.diff(df['ms5250'])
df = df[abs(df['diff'])<5]
#mispread矩阵
df_ms = pd.DataFrame()
df_ms['4700'] = df['4700']-df['mavg4700']
df_ms['4800'] = df['4800']-df['mavg4800']
df_ms['4900'] = df['4900']-df['mavg4900']
df_ms['5000'] = df['5000']-df['mavg5000']
df_ms['5250'] = df['5250']-df['mavg5250']
计算基差
首先根据当前期货价格水平找到平值期权,计算合成现货,计算基差
画图看基差水平变化。
def findjz(F):
if F <4700:
jz = 4700
return 0
elif F <4800:
if F -4700 <4800-F :
jz = 4700
return 0
else:
jz = 4800
return 1
elif F <4900:
if F-4800 <4900-F :
jz = 4800
return 1
else:
jz = 4900
return 2
if F-4900 <5000-F :
jz = 4900
return 2
else:
jz = 5000
return 3
else:
if F-5000 <5250-F :
jz = 5000
return 3
else:
jz = 5250
return 4
for i in range(len(df.index)):
if df['F'][i] <4700:
df['jc'][i] = df['4700'][i]
df['jz'][i] = 4700
df['mspread'][i] = df['4700'][i] - df['mavg4700'][i]
elif df['F'][i] <4800:
if df['F'][i]-4700 <4800-df['F'][i] :
df['jc'][i] = df['4700'][i]
df['jz'][i] = 4700
df['mspread'][i] = df['4700'][i] - df['mavg4700'][i]
else:
df['jc'][i] = df['4800'][i]
df['jz'][i] = 4800
df['mspread'][i] = df['4800'][i] - df['mavg4800'][i]
elif df['F'][i] <4900:
if df['F'][i]-4800 <4900-df['F'][i] :
df['jc'][i] = df['4800'][i]
df['jz'][i] = 4800
df['mspread'][i] = df['4800'][i] - df['mavg4800'][i]
else:
df['jc'][i] = df['4900'][i]
df['jz'][i] = 4900
df['mspread'][i] = df['4900'][i] - df['mavg4900'][i]
elif df['F'][i] <5000:
if df['F'][i]-4900 <5000-df['F'][i] :
df['jc'][i] = df['4900'][i]
df['jz'][i] = 4900
df['mspread'][i] = df['4900'][i] - df['mavg4900'][i]
else:
df['jc'][i] = df['5000'][i]
df['jz'][i] = 5000
df['mspread'][i] = df['5000'][i] - df['mavg5000'][i]
else:
if df['F'][i]-5000 <5250-df['F'][i] :
df['jc'][i] = df['5000'][i]
df['jz'][i] = 5000
df['mspread'][i] = df['5000'][i] - df['mavg5000'][i]
else:
df['jc'][i] = df['5250'][i]
df['jz'][i] = 5250
df['mspread'][i] = df['5250'][i] - df['mavg5250'][i]
for i in range(len(df.index)):
if df['F'][i] <4700:
df['jc'][i] = df['4700'][i]
df['jz'][i] = 4700
df['std'] = df_ms['sigma4700']
elif df['F'][i] <4800:
if df['F'][i]-4700 <4800-df['F'][i] :
df['jc'][i] = df['4700'][i]
df['jz'][i] = 4700
df['std'] = df_ms['sigma4700']
else:
df['jc'][i] = df['4800'][i]
df['jz'][i] = 4800
df['std'] = df_ms['sigma4800']
elif df['F'][i] <4900:
if df['F'][i]-4800 <4900-df['F'][i] :
df['jc'][i] = df['4800'][i]
df['jz'][i] = 4800
df['std'] = df_ms['sigma4800']
else:
df['jc'][i] = df['4900'][i]
df['jz'][i] = 4900
df['std'] = df_ms['sigma4900']
elif df['F'][i] <5000:
if df['F'][i]-4900 <5000-df['F'][i] :
df['jc'][i] = df['4900'][i]
df['jz'][i] = 4900
df['std'] = df_ms['sigma4900']
else:
df['jc'][i] = df['5000'][i]
df['jz'][i] = 5000
df['std'] = df_ms['sigma5000']
else:
if df['F'][i]-5000 <5250-df['F'][i] :
df['jc'][i] = df['5000'][i]
df['jz'][i] = 5000
df['std'] = df_ms['sigma5000']
else:
df['jc'][i] = df['5250'][i]
df['jz'][i] = 5250
df['std'] = df_ms['sigma5250']
#df['mavg'] = df['jc'].mean()
#df['mavg'] = df['jc'].rolling(window=80, min_periods=20, center=False).mean()
#df['mspread'] = df['jc']-df['mavg']
#sigma = np.std(df['mspread'])
#观察异常值boxplot
pd.DataFrame(df['ms4700']).describe()
percentile = np.percentile(df['ms4900'],[0,5,50,95,100])
IQR = percentile[3]-percentile[1]
Uplimit = percentile[3]+IQR*3.5
Dowmlimit = percentile[1]-IQR*3.5
f,ax = plt.subplots(figsize=(10,8))
sns.boxplot(data =df['mspread'])
plt.show
'''
#删除变动过大的异常值
df['diff'] = 0
df['diff'][1:len(df.index)] = np.diff(df['mspread'])
df = df[abs(df['diff'])<5]
'''
b=2.5
s=2.5
df['jc'].plot(figsize=(12,8),label='rolling600')
plt.title('std_mean_revert',fontsize=15)
plt.plot(df.mavg4900, color='r',label='mean')
plt.plot(df.mavg4900+b, color='g',label='begin=1.5*sigma')
plt.plot(df.mavg4900-b, color='g')
plt.plot(df.mavg4900+s, color='b',label='stop=2.5*sigma')
plt.plot(df.mavg4900-s, color='b')
plt.legend()
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
plt.show()
df['jc'].plot()
策略
#%%梯度建仓
#超过3就建一个,5+再建一口。不留隔夜仓位
b = 2.5#开仓点
s = 2.5#平仓
b2 = 5#稳定能盈利的点位
h = 1.2#划价
def mrETF2(df, b, s, b2, h):
df['account'] = 0
open_4700 = []
open_4800 = []
open_4900 = []
open_5000 = []
open_5250 = []
open_list = [open_4700,open_4800,open_4900,open_5000,open_5250]
df['hold_state'] = 0
hold = 0
option = 0
for i in range(1,len(df.index)):
if hold == 0:
if i < len(df.index)-1:
if df['mspread'][i] >= b:
#在原有基础上空一手,空期货多现货
df.loc[df.index[i],'hold_state'] = df['hold_state'][i-1] - 1
#account去掉期货保证金+期权权利金+滑点/2
df['account'][i]= df['account'][i-1] - df['F'][i]*4.8/1000/365*300 - 30*10000*4.8/365/100*0.1 - 1.2*300 - df['F'][i]*0.23/10000*300
option = option + 1
hold = hold - 1
t = findjz(df['F'][i])
open_list[t].append(df_ms.iloc[i,t])#记录开仓时的基差
elif df['mspread'][i] <= -b:
#在原有基础上多一手,买期货空现货
df.loc[df.index[i],'hold_state'] = df['hold_state'][i-1] + 1
#account去掉期权保证金+滑点/2
df['account'][i]= df['account'][i-1] - 30*10000*4.8/365/100 - 1.2*300 - df['F'][i]*0.23/10000*300
t = findjz(df['F'][i])
open_list[t].append(df_ms.iloc[i,t])#记录开仓时的基差
hold = hold + 1
option = option + 1
else:
df.loc[df.index[i],'hold_state'] = df['hold_state'][i-1]
df['account'][i]= df['account'][i-1]
else:
df.loc[df.index[i],'hold_state'] = df['hold_state'][i-1]
df['account'][i]= df['account'][i-1]
elif hold < 0:
zongchange = 0
n = 0
#account去掉 期货手续费+滑点/2
for t in range(len(open_list)):
change = 300*(df.iloc[i,t]-df.iloc[i-1,t])*len(open_list[t])
n = n+len(open_list[t])
zongchange = change+zongchange
#平仓,基差减少止盈or换天清仓
if i < len(df.index)-1:
if (df['mspread'][i] <= -s)|(df['Date'][i] != df['Date'][i+1]):
df.loc[df.index[i],'account'] = df['account'][i-1] +(- 1.2*300 - df['F'][i]*3.45/10000*300)*n - zongchange
df.loc[df.index[i],'hold_state'] = 0
hold = 0
open_4700 = []
open_4800 = []
open_4900 = []
open_5000 = []
open_5250 = []
open_list = [open_4700,open_4800,open_4900,open_5000,open_5250]
#加仓,基差更大了,再空一手
elif df['mspread'][i] >= b2:
#在原有基础上空一手,空期货多现货
df.loc[df.index[i],'hold_state'] = df['hold_state'][i-1] - 1
#account去掉期货保证金+期权权利金
df['account'][i]= df['account'][i-1] - df['F'][i]*4.8/1000/365*300 - 30*10000*4.8/365/100*0.1 -1.2*300 - zongchange - df['F'][i]*0.23/10000*300
t = findjz(df['F'][i])
open_list[t].append(df_ms.iloc[i,t])#记录开仓时的点位
hold = hold - 1
option = option + 1
else:
df['account'][i] = df['account'][i-1]-zongchange
df.loc[df.index[i],'hold_state'] = df['hold_state'][i-1]
else:
df.loc[df.index[i],'account'] = df['account'][i-1] +(- 1.2*300 - df['F'][i]*3.45/10000*300)*n - zongchange
df.loc[df.index[i],'hold_state'] = 0
hold = 0
open_4700 = []
open_4800 = []
open_4900 = []
open_5000 = []
open_5250 = []
open_list = [open_4700,open_4800,open_4900,open_5000,open_5250]
elif hold > 0:#本身基差过小,多一手
zongchange = 0
n = 0
#account去掉 期货手续费+滑点/2
for t in range(len(open_list)):
change = 300*(df.iloc[i,t]-df.iloc[i-1,t])*len(open_list[t])
n = n+len(open_list[t])
zongchange = change+zongchange
if i < len(df.index)-1:
if (df['mspread'][i] >= s)|(df['Date'][i] != df['Date'][i+1]):
#account去掉 期货手续费+滑点/2
df.loc[df.index[i],'account'] = df['account'][i-1] - 1.2*300 - df['F'][i]*3.45/10000*300 + zongchange
df.loc[df.index[i],'hold_state'] = 0
hold = 0
open_4700 = []
open_4800 = []
open_4900 = []
open_5000 = []
open_5250 = []
open_list = [open_4700,open_4800,open_4900,open_5000,open_5250]
#加仓,基差更小了,再多一手
elif df['mspread'][i] <= -b2:
#在原有基础上多一手,买期货空现货
df.loc[df.index[i],'hold_state'] = df['hold_state'][i-1] + 1
df['account'][i]= df['account'][i-1] - 30*10000*4.8/365/100 - 1.2*300 + zongchange- df['F'][i]*0.23/10000*300
t = findjz(df['F'][i])
open_list[t].append(df['jc'][i])
hold = hold + 1
option = option+1
else:
df['account'][i] =df['account'][i-1]+zongchange
df.loc[df.index[i],'hold_state'] = df['hold_state'][i-1]
else:
df.loc[df.index[i],'account'] = df['account'][i-1] - 1.2*300 - df['F'][i]*3.45/10000*300 + zongchange
df.loc[df.index[i],'hold_state'] = 0
hold = 0
open_4700 = []
open_4800 = []
open_4900 = []
open_5000 = []
open_5250 = []
open_list = [open_4700,open_4800,open_4900,open_5000,open_5250]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(len(df['account'])), df['account'])
plt.show()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(len(df['account'])),df['hold_state'])
plt.show()
return (df['account'][-1], option)