加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

经典量化交易策略系列——配对交易策略(三)

(2017-01-07 20:09:33)


    配对交易(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


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有