配对交易(Pairs
Trading)起源于八十年代中期,是经典的统计套利策略之一。配对交易在《Pairs Trading: Quantitative
Methods and Analysis》一书中,被定义为两种类型:
1.基于统计套利的配对交易,即寻找两只股价具备均衡关系的股票进行配对,如果它们的价格走势偏离历史均值,做多股价较低的股票,做空近期相对的强势股,并期待它们的股价回归到长期均衡关系。
配对交易分以下几个步骤:
2.基于风险套利的配对交易,通常发生在两个公司兼并时,兼并协议确定了所涉兼并的两家公司,他们股票价值的严格平价关系。但是,有很多的不确定因素,如,竞争的投标人、代理战等,会发生在宣布兼并后到兼并成功之间,将这种不确定性视为风险,捕获价差,而基于风险套利的配对交易才会从中获利。
策略思路:我们需要一对走势相关且股价相近的股票,根据其价格变动买卖。
策略实现:1.历史前5天的Pearson相关系数如﹥给定的临界值
2.如两只股票走势趋同,买入(卖出)股票时则按照上涨(下跌)趋势;
3.如两只股票走势背离,则卖出上涨,买入下跌。
为了简单点,直接使用了一个2012年走势非常相似的000159和000967,通过复权收盘价曲线就可以验证。
df = DataAPI.MktEqudAdjGet(secID = '000159.XSHE', field =
'closePrice', beginDate = '20120101', endDate = '20130101')
df['000159'] = df['closePrice']
df = df.loc[:, ['000159']].reset_index()
df2 = DataAPI.MktEqudAdjGet(secID = '000967.XSHE', field =
'closePrice', beginDate = '20120101', endDate = '20130101')
df2['000967'] = df2['closePrice']
df2 = df2.loc[:, ['000967']].reset_index()
df = df.merge(df2, left_on=['index'],
right_on=['index'])
df = df.loc[:, ['000159', '000967']]
df.plot()
下面对2013年这两只股票进行配对交易策略的回测:
from scipy.stats.stats import pearsonr
start = '2013-01-01'
end = '2014-01-01'
benchmark = 'HS300'
universe = ['000159.XSHE', '000967.XSHE']
capital_base = 1000000
def initialize(account):
account.cutoff =
0.9
account.prev_prc1 =
0
account.prev_prc2 =
0
account.prev_prcb =
0
def handle_data(account):
if len(account.universe)
< 2: return
clsp =
account.get_attribute_history('closePrice', 5)
stk1, stk2 =
universe
px1, px2 = clsp[stk1],
clsp[stk2]
prc1, prc2 = px1[-1],
px2[-1]
prcb =
account.get_symbol_history('benchmark', 1)['return'][0]
if account.prev_prc1 ==
0:
account.prev_prc1 = prc1
account.prev_prc2 = prc2
account.prev_prcb = prcb
return
corval, pval =
pearsonr(px1, px2)
if abs(corval) <
account.cutoff:
return
mov1, mov2 = adj(prc1,
prc2, prcb, account.prev_prc1, account.prev_prc2,
account.prev_prcb)
amount = 100000 / prc2
if mov1 > 0:
order(stk2, amount)
elif mov1 < 0:
if account.valid_secpos.get(stk2, 0) >
amount:
order(stk2, -amount)
else:
order_to(stk2, 0)
amount = 100000 /
prc1
if mov2 > 0:
order(stk1, amount)
elif mov2 < 0:
if account.valid_secpos.get(stk1, 0) >
amount:
order(stk1, -amount)
else:
order_to(stk1, 0)
account.prev_prc1 =
prc1
account.prev_prc2 =
prc2
account.prev_prcb =
prcb
def adj(x, y, base, prev_x, prev_y, prev_base):
dhs = base / prev_base -
1
dx = x / prev_x - 1 -
dhs
dy = y / prev_y - 1 -
dhs
return dx, dy
bt
加载中,请稍候......