- 今天,银行股全线飘红,银行ETF领涨,相关基本面逻辑这里不讨论;
- 银行股之间的统计套利,又称pair trading;
- 配对交易策略:配对交易策略的基本原理是基于两个相关性较高的股票或者其他证券,如果在未来时期保持着良好的相关性,一旦两者之间出现了背离的走势,且这种背离在未来是会得到纠正的,那么就可能产生套利的机会。对于配对交易的实践而言,如果两个相关性较高的股票或者其他证券之间出现背离,就应该买进表现相对较差的,卖出表现相对较好的。当未来两者之间的背离得到纠正,那么可以进行相反的平仓操作来获取利润。
策略
基于配对交易原理,从银行板块筛选出2017-2018年度相关性大于0.95的三支股票(农业银行、工商银行和建设银行)进行统计套利,满足一定条件做空做多相应的股票从而获取更高收益。这里定义了一个函数secID_list(),帮助自己快速筛选名字中含有“银行”的股票,返回含有secID的list。
import numpy as np
import pandas as pd
import seaborn as sns
def secID_list(name):
import datetime
import time
if time.strftime('%A') =='Sunday':
Date=(datetime.date.today()- datetime.timedelta(days=2)).strftime('%Y%m%d')
elif time.strftime('%A') =='Saturday':
Date=(datetime.date.today()- datetime.timedelta(days=1)).strftime('%Y%m%d')
else:
Date=time.strftime("%Y%m%d") #确定最近的一个交易日日期
dt=DataAPI.MktEqudGet(tradeDate=Date,pandas="1")
stocks=[]
for i in range(len(dt)):
if dt.loc[i].secShortName.find(name) is not (-1):
stocks.append(dt.loc[i].secID)
return stocks
print secID_list('银行')
[‘000001.XSHE’, ‘002142.XSHE’, ‘002807.XSHE’, ‘600000.XSHG’, ‘600015.XSHG’, ‘600016.XSHG’, ‘600036.XSHG’, ‘600908.XSHG’, ‘600919.XSHG’, ‘600926.XSHG’, ‘601009.XSHG’, ‘601128.XSHG’, ‘601166.XSHG’, ‘601169.XSHG’, ‘601229.XSHG’, ‘601288.XSHG’, ‘601328.XSHG’, ‘601398.XSHG’, ‘601818.XSHG’, ‘601838.XSHG’, ‘601939.XSHG’, ‘601988.XSHG’, ‘601997.XSHG’, ‘601998.XSHG’, ‘603323.XSHG’]
首先是数据调用和清洗,调取去年银行股的收盘价,并整合进closetable中。
closetable=DataAPI.MktEqudGet(tradeDate=u"",secID='000001.XSHE',ticker=u"",beginDate=u"20170101",endDate=u"20180101",isOpen="",field=u"tradeDate,closePrice",pandas="1")
closetable.index=pd.to_datetime(closetable.tradeDate)
del closetable['tradeDate']
closetable.columns=['000001.XSHE']
for i in ['002142.XSHE', '002807.XSHE', '600000.XSHG', '600015.XSHG', '600016.XSHG', '600036.XSHG', '600908.XSHG', '600919.XSHG', '600926.XSHG', '601009.XSHG', '601128.XSHG', '601166.XSHG', '601169.XSHG', '601229.XSHG', '601288.XSHG', '601328.XSHG', '601398.XSHG', '601818.XSHG', '601838.XSHG', '601939.XSHG', '601988.XSHG', '601997.XSHG', '601998.XSHG', '603323.XSHG']:
dt=DataAPI.MktEqudGet(tradeDate=u"",secID=i,ticker=u"",beginDate=u"20170101",endDate=u"20180101",isOpen="",field=u"tradeDate,closePrice",pandas="1")
dt.index=pd.to_datetime(dt.tradeDate)
closetable[i]=dt.closePrice
closetable.head()

这里只展示前几只标的
其次,求出各银行股收盘价之间的相关系数,相关性差异较大,其中成都银行601838.XSHG的数据未调取成功。筛选出相关系数大于0.95的银行股,可以发现,农业银行601288.XSHG,工商银行601398.XSHG,建设银行601939.XSHG三只股票的收盘价两两之间的相关系数均大于0.95,有较强的相关性。
corr=closetable.corr()
sns.heatmap(corr,vmax=1,vmin=-1,linewidth=0.5)
for i in ['000001.XSHE', '002142.XSHE', '002807.XSHE', '600000.XSHG', '600015.XSHG', '600016.XSHG', '600036.XSHG', '600908.XSHG', '600919.XSHG', '600926.XSHG', '601009.XSHG', '601128.XSHG', '601166.XSHG', '601169.XSHG', '601229.XSHG', '601288.XSHG', '601328.XSHG', '601398.XSHG', '601818.XSHG', '601939.XSHG', '601988.XSHG', '601997.XSHG', '601998.XSHG', '603323.XSHG']:
for j in ['000001.XSHE', '002142.XSHE', '002807.XSHE', '600000.XSHG', '600015.XSHG', '600016.XSHG', '600036.XSHG', '600908.XSHG', '600919.XSHG', '600926.XSHG', '601009.XSHG', '601128.XSHG', '601166.XSHG', '601169.XSHG', '601229.XSHG', '601288.XSHG', '601328.XSHG', '601398.XSHG', '601818.XSHG', '601939.XSHG', '601988.XSHG', '601997.XSHG', '601998.XSHG', '603323.XSHG']:
if corr[i][j]>0.95 and i!=j:
print [i,j]
closetable[['601288.XSHG','601398.XSHG','601939.XSHG']].plot(figsize=(8,6))
得到,相关系数图和收盘价如下:

接着,这里通过协整将非平稳的时间序列变为平稳的时间序列,white_noise符合正态分布并构造统计量x,y,z,当满足一定条件时做空做多股票,一些参数可以调整,最终年化利率26.7%,若分别满仓农业银行、工商银行、建设银行的年化利率为14.5%、22.4%、21.7%。由此可见,通过统计套利,最终收益有所提高,pair trading较趋势跟踪而言不能获得较大收益,但收益相对比价平稳,风险较小。
start='2016-01-01'
end='2018-01-01'
universe= ['601288.XSHG','601398.XSHG','601939.XSHG']
benchmark='HS300'
freq='d'
refresh_rate= 1
max_history_window=250
accounts={'security_account':AccountConfig(account_type='security',capital_base=100000,commission=Commission(buycost=0.001,sellcost=0.002,unit='perValue'),slippage=Slippage(value=0.01,unit='perShare'))}
def initialize(context):
context.longterm=244
def handle_data(context):
account = context.get_account('security_account')
universe = context.get_universe('stock',exclude_halt=False)
data_day = context.history(universe, time_range=context.longterm, attribute='closePrice', freq='d',style='sat', retype='frame')
[a1,b1]=np.polyfit(data_day['601288.XSHG'].closePrice,data_day['601398.XSHG'].closePrice,1)
[a2,b2]=np.polyfit(data_day['601288.XSHG'].closePrice,data_day['601939.XSHG'].closePrice,1)
[a3,b3]=np.polyfit(data_day['601398.XSHG'].closePrice,data_day['601939.XSHG'].closePrice,1)
white_noise1=data_day['601398.XSHG'].closePrice-data_day['601288.XSHG'].closePrice*a1-b1
white_noise2=data_day['601939.XSHG'].closePrice-data_day['601288.XSHG'].closePrice*a2-b2
white_noise3=data_day['601939.XSHG'].closePrice-data_day['601398.XSHG'].closePrice*a3-b3
x=(white_noise1-white_noise1.mean())/white_noise1.std()
y=(white_noise2-white_noise2.mean())/white_noise2.std()
z=(white_noise3-white_noise3.mean())/white_noise3.std()
button1=1
if x[-1]<-button1 or y[-1]<-button1:
account.order_pct('601288.XSHG',-0.1)
if x[-1]>button1 or z[-1]<-button1:
account.order_pct('601398.XSHG',-0.1)
if y[-1]>button1 or z[-1]>button1:
account.order_pct('601939.XSHG',-0.1)
button2=1.5
if x[-1]>button2 or y[-1]>button2:
account.order_pct('601288.XSHG',0.1)
if x[-1]<-button2 or z[-1]>button2:
account.order_pct('601398.XSHG',0.1)
if y[-1]<-button2 or z[-1]<-button2:
account.order_pct('601939.XSHG',0.1)
最后,回测得到:

发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/321262
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!