# 10个套利对
pairs = {'0':['601328.SHA', "600000.SHA"],
'1':['600015.SHA', '601169.SHA'],
'2':['600015.SHA', '002142.SZA'],
'3':['600016.SHA', '601169.SHA'],
'4':['600036.SHA', '601169.SHA'],
'5':['601398.SHA', '601166.SHA'],
'6':['601328.SHA', '601398.SHA'],
'7':['601169.SHA', '002142.SZA'],
'8':['601328.SHA', '600000.SHA'],
'9':['600016.SHA', '600015.SHA'],
}
# 整理股票列表
all_instruments = []
for i in pairs.keys():
all_instruments = all_instruments+pairs[i]
all_instruments = list(set(all_instruments))
# 获取价格数据
start_date = '2015-01-01'
end_date = '2017-07-18'
prices_temp = D.history_data(all_instruments,start_date,end_date,
fields=['close'] )
prices_df=pd.pivot_table(prices_temp, values='close', index=['date'], columns=['instrument'])
import statsmodels.api as sm
# 计算z得分
def zscore(series):
return (series - series.mean()) / np.std(series)
# 将各个套利对的z得分汇总到一块
zscore_dict = {}
for key in pairs.keys():
stock_0 = pairs[key][0]
stock_1 = pairs[key][1]
x = prices_df[stock_0] # 这里传入每个套利对的单条腿
y = prices_df[stock_1]
X = sm.add_constant(x)
result = (sm.OLS(y,X)).fit()
stock_1 = result.params.index.values[1]
coef = result.params.ix[stock_1]
# T.plot(pd.DataFrame({'Stationary Series':0.8753*x-y, 'Mean':[np.mean(0.8753*x-y)]}), chart_type='line')
df = pd.DataFrame({'Stationary Series':y-coef*x, 'Mean':np.mean(y-coef*x)})
zscore_calcu = zscore(y-coef*x)
zscore_dict[key] = zscore_calcu
zscore_df = pd.DataFrame(zscore_dict)
交易信号: 当zscore大于1时,全仓买入交通银行,全仓卖出中信银行→做空价差 当zscore小于-1时,全仓卖出中信银行,全仓买入交通银行→做多价差
# 初始化账户和传入需要的变量
def initialize(context):
context.set_commission(PerDollar(0.0015)) # 手续费设置
context.zscore = zscore_df
context.pairs = pairs # 传入协整股票对
# 策略主题函数
def handle_data(context, data):
date = data.current_dt.strftime('%Y-%m-%d') # 运行到当根k线的日期
weight = 1/len(context.pairs)
for i in zscore_df.columns: # 对各个套利对循环
stock_1 = context.pairs[i][0] # 股票y
stock_2 = context.pairs[i][1] # 股票x
zscore = context.zscore[i].ix[date] # 当日的zscore
symbol_1 = context.symbol(stock_1) # 转换成回测引擎所需要的symbol格式
symbol_2 = context.symbol(stock_2)
# 持仓
cur_position_1 = context.portfolio.positions[symbol_1].amount
cur_position_2 = context.portfolio.positions[symbol_2].amount
# 交易逻辑
# 如果zesore大于上轨(>1),则价差会向下回归均值,因此需要买入股票x,卖出股票y
if zscore > 1 and cur_position_2 == 0 and data.can_trade(symbol_1) and data.can_trade(symbol_2):
context.order_target_percent(symbol_1, 0)
context.order_target_percent(symbol_2, 1*weight)
# 如果zesore小于下轨(<-1),则价差会向上回归均值,因此需要买入股票y,卖出股票x
elif zscore < -1 and cur_position_1 == 0 and data.can_trade(symbol_1) and data.can_trade(symbol_2):
context.order_target_percent(symbol_1, 1*weight)
context.order_target_percent(symbol_2, 0)
# 回测启动接口
m=M.trade.v2(
instruments=all_instruments,
start_date=start_date,
end_date=end_date,
initialize=initialize,
handle_data=handle_data,
order_price_field_buy='open',
order_price_field_sell='open',
capital_base=1000000,
benchmark='000300.INDX',
)