跨期套利策略

策略想法:选取某一期货品种的主力合约和次主力合约,得到两个合约价格的价差,运用布林带指标,取前20分钟和2倍标准差,如果价差在布林带之外,入场,回到均值出场。

如下为策略代码:

#选取zn1701和zn1702合约的11月份交易分钟数据
#数据经过excel处理,两个合约数据按时间合并
#设置手续费和滑点为10元(两个合约买卖一次),平仓时扣除,
import pandas as pd
from pandas import Series,DataFrame
import numpy as np
import matplotlib.pyplot as plt
from numpy import nan
data=pd.read_excel('zn01_zn02.xlsx')
data['spread']=data['ZN01']-data['ZN02']
T=len(data.index)
#记录每次交易收益率
minute_return=[]
up_cross_up_limit=False
down_cross_down_limit=False
result_up= DataFrame(columns=['ZN01', 'ZN02', 'spread', 'ZN01买卖方向', 'ZN01开平', 'ZN02买卖方向', 'ZN02开平'])
result_down= DataFrame(columns=['ZN01', 'ZN02', 'spread', 'ZN01买卖方向', 'ZN01开平', 'ZN02买卖方向', 'ZN02开平'])
total_mean_line=[]
total_up_line=[]
total_down_line=[]
#生成T-20个元素为0列表,
a=[0]*(T-20)
for i in range(20,T):
#得到第i个spread前20个数据,并计算均值、方差、up_line、down_line
#计算结果均为整数
data_spread=data.iloc[i-20:i,2].values
# print(data_spread)
mean_20day_spread=data_spread.mean()
total_mean_line.append(mean_20day_spread)
# print(mean_20day_spread)
std_20day_spread=data_spread.std()
up_line=mean_20day_spread+2*std_20day_spread
total_up_line.append(up_line)
down_line=mean_20day_spread-2*std_20day_spread
total_down_line.append(down_line)
#将第i个spread与前20个spread得到up_line比较,决定是否开仓
if data.iloc[i,2]>up_line and not up_cross_up_limit:
up_open=data.iloc[i:i+1,:]
up_open = DataFrame(up_open,columns=['ZN01', 'ZN02', 'spread', 'ZN01买卖方向', 'ZN01开平', 'ZN02买卖方向', 'ZN02开平'])
up_open['ZN01买卖方向'] = '卖出'
up_open['ZN01开平'] = '开仓'
up_open['ZN02买卖方向'] = '买入'
up_open['ZN02开平'] = '开仓'
#汇总
result_up=pd.concat([result_up,up_open])
#得到开仓spread
hold_spread = data.iloc[i, 2]
up_cross_up_limit=True
#i从20开始
a[i-20]=1
# 将第i个spread与前20个spread得到mean_20day_spread比较,决定是否平仓
elif data.iloc[i,2]<=mean_20day_spread and up_cross_up_limit:
down_close=data.iloc[i:i+1,:]
down_close = DataFrame(down_close,columns=['ZN01', 'ZN02', 'spread', 'ZN01买卖方向', 'ZN01开平', 'ZN02买卖方向', 'ZN02开平'])
down_close['ZN01买卖方向'] = '买入'
down_close['ZN01开平'] = '平仓'
down_close['ZN02买卖方向'] = '卖出'
down_close['ZN02开平'] = '平仓'
result_up=pd.concat([result_up,down_close])
profit_yield = (hold_spread - data.iloc[i, 2] - 20) / (data.iloc[i, 0] + data.iloc[i, 1])
minute_return.append(profit_yield)
up_cross_up_limit=False
a[i-20] = 1
# 将第i个spread与前20个spread得到down_line比较,决定是否开仓
elif data.iloc[i,2]<down_line and not down_cross_down_limit:
down_open=data.iloc[i:i+1,:]
down_open = DataFrame(down_open,columns=['ZN01', 'ZN02', 'spread', 'ZN01买卖方向', 'ZN01开平', 'ZN02买卖方向', 'ZN02开平'])
down_open['ZN01买卖方向'] = '买入'
down_open['ZN01开平'] = '开仓'
down_open['ZN02买卖方向'] = '卖出'
down_open['ZN02开平'] = '开仓'
#汇总
result_down=pd.concat([result_down,down_open])
hold_spread = data.iloc[i, 2]
down_cross_down_limit=True
a[i-20] = 1
# 将第i个spread与前20个spread得到down_line比较,决定是否平仓
elif data.iloc[i,2]>=mean_20day_spread and down_cross_down_limit:
up_close=data.iloc[i:i+1,:]
up_close = DataFrame(up_close,columns=['ZN01', 'ZN02', 'spread', 'ZN01买卖方向', 'ZN01开平', 'ZN02买卖方向', 'ZN02开平'])
up_close['ZN01买卖方向'] = '卖出'
up_close['ZN01开平'] = '平仓'
up_close['ZN02买卖方向'] = '买入'
up_close['ZN02开平'] = '平仓'
result_down=pd.concat([result_down,up_close])
profit_yield = (data.iloc[i, 2] - hold_spread - 20)/ (data.iloc[i, 0] + data.iloc[i, 1])
minute_return.append(profit_yield)
down_cross_down_limit=False
a[i-20] = 1
print('-------------')
transation=pd.concat([result_up,result_down]).sort_index()
# transation.to_csv('transation_detail.csv')

#计算sharpe
#计算总回报
total_return=np.expm1(np.log1p(minute_return).sum())
#计算年化回报
annual_return=(1+total_return)**(365/30)-1
risk_free_rate=0.015
std=np.array(minute_return).std()
volatility=std*(len(minute_return)**0.5)
annual_factor=12
annual_volatility=volatility*((annual_factor)**0.5)
sharpe=(annual_return-risk_free_rate)/annual_volatility
# print(total_return,annual_return,std,volatility,annual_volatility,sharpe)
print('夏普比率:{}'.format(sharpe))

#计算最大回撤
#计算
df_cum=np.exp(np.log1p(minute_return).cumsum())
max_return=np.maximum.accumulate(df_cum)
max_drawdown=((max_return-df_cum)/max_return).max()
print('-----------------')
print('最大回撤: {}'.format(max_drawdown))

#计算盈亏比plr
from collections import Counter
# win_times=Counter(x>0 for x in minute_return)
# loss_times=Counter(x<0 for x in minute_return)
win_times=sum(x>0 for x in minute_return)
loss_times=sum(x<0 for x in minute_return)
plr=win_times/loss_times
print('----------------------------')
print('盈利次数:{}'.format(win_times))
print('亏损次数:{}'.format(loss_times))
print('盈亏比:{}'.format(plr))

#画出净值走势图
fig=plt.figure()
ax1=fig.add_subplot(2,1,1)
cum_net_worth,=plt.plot(df_cum,label='cum_net_worth')
plt.legend([cum_net_worth],['cum_net_worth'])
ax2=fig.add_subplot(2,1,2)
spread=data.iloc[20:,2].values
plt.plot(total_mean_line)
plt.plot(total_up_line)
plt.plot(total_down_line)
plt.plot(spread)
#标记进场、出场位置,先将格式转换为list
spread_mark=spread.tolist()
for i in range(T-20):
if a[i]==0:
spread_mark[i]=nan
elif a[i]==1:
spread_mark[i]=spread_mark[i]
plt.plot(spread_mark,'*')
plt.show()



下面为运行结果图:

 进场出场放大图:







原文地址:https://www.cnblogs.com/bawu/p/6789402.html