精华内容
下载资源
问答
  • 交易期
    千次阅读
    2020-01-14 09:59:04

    跨期套利是指在同一市场同时买入、卖出同一期货品种的不同交割月份的期货合约,以期在有利时机同时将这些期货合约对冲平仓获利。跨期套利与现货市场价格无关,只与期货可能发生的升水和贴水有关。在实际操作中,根据套利者对不同合约月份中近月合约与远月合约买卖方向的不同,跨期套利可分为牛市套利、熊市套利和蝶式套利。

    1.牛市套利(Bull Spread)

    牛市套利的判断依据一般是市场供给不足,现货需求相对旺盛,临近月份合约价格的上升幅度大于远期月份合约,或者临近月份合约价格的下降幅度小于远期月份合约,此时套利方向就是看多近月合约,看空远月合约。

    正向市场中的牛市套利预期基差(近月价格减去远月价格)从负值收敛到零,反向市场中的牛市套利预期基差从正值发散到更大的负值,因此正向市场中的牛市套利属于无风险套利,而反向市场中的牛市套利属于对近月合约的相对上涨趋势套利。

    2.熊市套利(Bear Spread)

    熊市套利的判断依据一般是市场供给过剩,需求相对不足,则会导致近期月份合约价格的上升幅度小于远期月份合约,或者近期月份合约价格的下降幅度大于远期月份合约,交易者可以通过做空近月合约的同时做多远月合约而进行熊市套利。

    正向市场中的熊市套利预期基差(近月价格减去远月价格)从负值发散到更大的负值,反向市场中的熊市套利预期基差从正值收敛到零值,因此正向市场中的熊市套利属于对近月合约的相对下跌趋势套利,而反向市场中的熊市套利属于无风险套利。

    跨期套利策略详解

    3.蝶式套利

    蝶式套利是跨期套利中的又一种常见的形式。它是由两个方向相反、共享居中交割月份的跨期套利组成。蝶式套利的具体操作方法是:买入(或卖出)近期月份合约,同时卖出(或买人)居中月份合约,并买入(或卖出)远期月份合约,其中,居中月份合约的数量等于近期月份和远期月份数量之和。

    看多居中合约的蝶式套利,属于一个近月熊市套利加一个远月牛市套利,在近月反向市场加远月正向市场中属于无风险套利;而看空居中合约的蝶式套利,属于一个近月牛市套利加一个远月熊市套利,在近月正向市场加远月反向市场中属于无风险套利。

     

    近月反向市场的看多居中合约蝶式套利是无风险套利,恰似“蝴蝶放下翅膀,一切归于正常”;反之,蝴蝶煽动翅膀价差发散。

    拓展阅读:

    1.一个量化策略师的自白(好文强烈推荐)

    2.市面上经典的量化交易策略都在这里了!(源码)

    3.期货/股票数据大全查询(历史/实时/Tick/财务等)

    4.干货| 量化金融经典理论、重要模型、发展简史大全

    5.从量化到高频交易,不可不读的五本书

    6.高频交易四大派系大揭秘

    更多相关内容
  • 量化投资实战(二)之配对交易策略---最短距离法

    千次阅读 多人点赞 2020-11-20 09:54:26
    配对交易策略实战—最短距离法 基本流程 配对组合 --> 计算价差 --> 决策标准 --> 确定头寸 --> 平仓获利 一、股票对的选取 读取数据 import pandas as pd sh = pd.read_csv('sh50_stock_data....

    点赞、关注再看,养成良好习惯
    Life is short, U need Python
    初学量化投资实战,[快来点我吧]

    在这里插入图片描述

    配对交易策略实战—最短距离法

    基本流程

    配对组合 --> 计算价差 --> 决策标准 --> 确定头寸 --> 平仓获利

    一、股票对的选取

    • 读取数据
    import pandas as pd
    
    sh = pd.read_csv('sh50_stock_data.csv',index_col='Trddt')     # 读取上证板块收盘价数据
    
    • 数据预处理
    # 将stock转换成时间序列类型
    sh.index = pd.to_datetime(sh.index)
    
    # 定义配对形成期
    formStart = '2014-01-01'
    formEnd = '2015-01-01'
    
    # 形成期数据
    sh_form = sh[formStart:formEnd]
    
    sh_form.head()
    
    600000600010600015600016600018600028600030600036600048600050...601688601766601800601818601857601901601985601988601989601998
    Trddt
    2014-01-028.3072.3606.3716.1835.0314.11712.2889.7195.1563.146...8.5344.8693.7812.3837.2455.91-2.3335.6173.634
    2014-01-038.1382.5946.1876.0874.9064.04311.9379.5205.1123.088...8.2934.7913.7252.3567.2175.91-2.2895.5173.578
    2014-01-068.1822.4396.0415.9114.5814.13611.9379.4754.8223.000...8.4384.6063.632.327.3395.91-2.2625.1983.521
    2014-01-078.1382.3806.0185.8474.9454.06211.7519.5294.7783.010...8.3314.5383.6592.327.3115.91-2.2535.1483.512
    2014-01-088.1912.2956.1495.8634.7064.05211.7919.6294.7342.971...8.364.4413.642.327.2175.91-2.2445.1383.521

    5 rows × 50 columns

    结论:发现有空缺值(标记为‘-’)。

    sh_form = sh_form.drop(['600958','601211','601985'], axis=1)   # 删除空缺值
    
    sh_form = sh_form.astype(float)    # 转换为浮点值
    
    # 提取中国银行(601988)A和浦发银行(600000)B股票的调整后的收盘价格数据
    P_zhonghang_f = sh_form['601988']
    P_pufa_f = sh_form['600000']
    
    # 合并数据形成DataFrame数据
    pair_form = pd.concat([P_zhonghang_f,P_pufa_f],axis =1,join='outer')
    
    • 数据可视化
    # 股票对价格历史走势图
    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif'] = ['SimHei']   
    
    plt.figure(figsize=(10,4))
    ax = plt.subplot()
    
    ax.plot(pair_form['601988'], label='中国银行')
    ax.plot(pair_form['600000'], label='浦发银行')
    plt.title('图1 中国银行 vs 浦发银行(收盘价)',fontsize=15)
    ax.set_xlabel('日期', fontsize=14)
    ax.set_ylabel('收盘价', fontsize=14)
    ax.legend()
    
    plt.show()
    

    在这里插入图片描述

    # 计算 A、B 收益率
    return_zhonghang = (P_zhonghang_f - P_zhonghang_f.shift(1)) / P_zhonghang_f.shift(1)[1:]    
    return_pufa = (P_pufa_f - P_pufa_f.shift(1)) /P_pufa_f.shift(1)[1:]   
    
    # 股票对价格历史走势图
    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif'] = ['SimHei'] 
    import matplotlib
    matplotlib.rcParams['axes.unicode_minus']=False    # 负号显示问题
    
    plt.figure(figsize=(10,4))
    ax = plt.subplot()
    
    ax.plot(return_zhonghang, label='中国银行')
    ax.plot(return_pufa, label='浦发银行')
    plt.title('图2 中国银行 vs 浦发银行(收益率)',fontsize=15)
    ax.set_xlabel('日期', fontsize=14)
    ax.set_ylabel('收益率', fontsize=14)
    ax.legend()
    
    plt.show()
    

    在这里插入图片描述

    # 计算 A、B 累计收益率
    cum_return_zhonghang = (1 + return_zhonghang).cumprod()     
    cum_return_pufa = (1 + return_pufa).cumprod()
    
    # 股票对累计收益率历史走势图
    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif'] = ['SimHei']   
    
    plt.figure(figsize=(10,4))
    ax = plt.subplot()
    
    ax.plot(cum_return_zhonghang, label='中国银行')
    ax.plot(cum_return_pufa, label='浦发银行')
    plt.title('图3 中国银行 vs 浦发银行(累计收益率)',fontsize=15)
    ax.set_xlabel('日期', fontsize=14)
    ax.set_ylabel('累计收益率', fontsize=14)
    ax.legend()
    
    plt.show()
    

    在这里插入图片描述

    • 构造最小距离函数–SSD()
    ## 构造SSD距离函数(累计收益率偏差)
    import numpy as np
    
    def SSD(priceX,priceY): 
        returnX = (priceX - priceX.shift(1)) / priceX.shift(1)[1:]    # 计算 X 收益率
        returnY = (priceY - priceY.shift(1)) / priceY.shift(1)[1:]    # 计算 Y 收益率
        
        standardX = (returnX + 1).cumprod()                           # 累计求和‘.cumprod()’,即 X,Y 的累计收益率
        standardY = (returnY + 1).cumprod()
        
        SSD = np.sum((standardX - standardY) ** 2)                   # 计算累计收益率偏差
        
        return(SSD) 
    
    # 求中国银行和浦发银行价格距离
    dis = SSD(P_zhonghang_f,P_pufa_f)
    dis
    
    0.47481704588389073
    

    结论:

    将上证50板块的50只股票两两配对(共计1225对),形成期(Formation Period)为245天,则 X X X Y Y Y股票的价格距离为:

    S S D X , Y = ∑ t = 1 245 ( p ^ t X − p ^ t Y ) 2 SSD_{X, Y}=\sum_{t=1}^{245}\left(\hat{p}_{t}^{X}-\hat{p}_{t}^{Y}\right)^{2} SSDX,Y=t=1245(p^tXp^tY)2

    以此类推,可以计算出1225个SSD值,将这些值由小到大进行排序,然后从中选出前5组作为配对交易策略的5个股票对。

    • 计算上证50板块两两配对股票(1225 --》1081对)之间的距离
    lst = list(sh_form.columns)
    
    d = dict()
    for i in range(len(lst)):
        for j in range(i+1,len(lst)):
            P_zhonghang_f = sh_form[lst[i]]
            P_pufa_f = sh_form[lst[j]]
            dis = SSD(P_zhonghang_f,P_pufa_f)
            d[lst[i]+'-'+lst[j]] = dis
    
    # 按照‘值’排序,并挑出前5个最小距离股票对
    d_sort = sorted(d.items(),key=lambda x:x[1])
    d_sort[:5]
    
    [('600015-601166', 0.24566159437495438),
     ('601288-601398', 0.246846282979896),
     ('600050-601288', 0.27890721330378976),
     ('601166-601288', 0.2920160356208131),
     ('601398-601857', 0.3299872459845748)]
    

    二、配对交易策略的制定

    运用最小距离法可以挑选出股票对,计算形成期(Formation Period)内标准化的价格序列差 p ^ t X − p ^ t Y \hat{p}_t^X - \hat{p}_t^Y p^tXp^tY 的平均值 μ \mu μ 和标准差 σ \sigma σ。然后,选定交易期(Trading Period )进行交易。

    Gatev等学者运用最小距离法选出股票对,设定交易信号触发点为 μ ± 2 σ \mu \pm 2\sigma μ±2σ,交易期的适用期限为6个月。当交易期超过6个月以后,重新设定形成期和选取股票对。此处,由于浦发银行与中国银行同为银行业股票,且银行业股票股价比较稳定,因此我们设定交易期内价差超过 μ + 1.2 σ \mu + 1.2\sigma μ+1.2σ 或者 μ − 1.2 σ \mu - 1.2\sigma μ1.2σ 时,将触发交易信号进行交易。

    当交易期的标准化价差又回复到均值 μ \mu μ 附近时,反向操作平仓,从而赚取价差收益。

    • (1)在形成期中计算浦发银行与中国银行股票标准化价格序列差 SSD-pair,并求出价差的平均值 meanSSD-pair 和标准差 sdSSD-pair,并设定开仓、平仓条件(如图4所示)。
    # 中国银行标准化价格
    standard_zhonghang = (1 + return_zhonghang).cumprod()
    # 浦发银行标准化价格
    standard_pufa = (1 + return_pufa).cumprod()
    
    # 求中国银行A与浦发银行B标准化价格序列的价差 
    SSD_pair = standard_pufa - standard_zhonghang   
    
     ############  (1.1)计算形成期标准化价格差序列的均值和方差   ############
    meanSSD_pair = np.mean(SSD_pair)
    sdSSD_pair = np.std(SSD_pair)
    
    ############ (1.2)设置交易期交易信号触发点:mu +- 1.2sigma   ############
    thresholdUp = meanSSD_pair + 1.2 * sdSSD_pair
    thresholdDown = meanSSD_pair - 1.2 * sdSSD_pair
    
    # 可视化
    plt.figure(figsize=(12,6))
    
    SSD_pair.plot()
    
    plt.title('图4 中国银行与浦发银行标准化价差序列(形成期)',loc='center',fontsize=16) 
    
    plt.axhline(y=meanSSD_pair,color='black')
    plt.axhline(y=thresholdUp,color='green')
    plt.axhline(y=thresholdDown,color='green') 
    
    plt.show()
    

    在这里插入图片描述

    • (2)设定交易期(Trading Period )时间,选取交易期数据,寻找配对交易开仓和平仓位点。当价差上穿 μ + 1.2 σ \mu + 1.2\sigma μ+1.2σ 线时,反向开仓,当价差线回复到均线附近(可以给出阈值进行度量)时,进行平仓。当价差线下穿 μ − 1.2 σ \mu - 1.2\sigma μ1.2σ 线时正向开仓,当价差线再次回复到均线附近时平仓。
         ################### 设定交易期时间,选取交易期数据,寻找配对交易开仓和平仓点位(2.1)  ###################
    tradStart = '2015-01-01'
    tradEnd = '2015-06-30'
    
    P_zhonghang_t = sh.loc[tradStart:tradEnd, '601988']
    P_pufa_t = sh.loc[tradStart:tradEnd, '600000']
    
    # 定义价差函数
    def spreadCal(x,y):
        retx = (x-x.shift(1)) / x.shift(1)[1:]
        rety = (y-y.shift(1)) / y.shift(1)[1:]
        
        standardX = (1+retx).cumprod()
        standardY = (1+rety).cumprod()
        
        spread = standardX-standardY
        
        return(spread)
    
    # 计算标准价差
    TradSpread = spreadCal(P_pufa_t,P_zhonghang_t).dropna()
    
    # 可视化
    plt.figure(figsize=(12,6))
    
    TradSpread.plot()
    
    plt.title('图5  中国银行与浦发银行股票价差序列(交易期)',loc='center',fontsize=16)
    
    plt.axhline(y=meanSSD_pair, color='black')
    plt.axhline(y=thresholdUp, color='green')
    plt.axhline(y=thresholdDown, color='green') 
    
    plt.show()
    

    在这里插入图片描述

    结论:如图5所示,价差序列多在1.2倍标准差范围内,从2015年1月1日至2015年6月30日,价差序列向上突破1.2倍标准差线3次,向下突破1.2倍标准差线3次,共有6次开仓机会,且价差序列比较稳定,开仓后均有平仓机会。
    :(1)均值附近平仓的度量: μ ± 0.2 σ \mu \pm 0.2\sigma μ±0.2σ;(2)控制风险平仓的度量: μ ± 2.0 σ \mu \pm 2.0\sigma μ±2.0σ

    三、构建PairTrading类

    Python是一种面向对象的语言,我们可以构建各种各样的类来完成我们所需要的任务。对于上文中进行配对的代码,我们可以将其编写为一个类。这样,在以后需要的时候,就可以随时调用该类,而不需要再重新编写上面的那些代码。

    import pandas as pd 
    import numpy as np 
    
    from arch.unitroot import ADF
    import statsmodels.api as sm
    
    # 构建类
    class PairTrading:
        
        def SSD(self,priceX,priceY):
            returnX = (priceX - priceX.shift(1)) / priceX.shift(1)[1:]
            returnY = (priceY - priceY.shift(1)) / priceY.shift(1)[1:]
            standardX = (returnX + 1).cumprod()
            standardY = (returnY + 1).cumprod()
            SSD = np.sum((standardY - standardX)**2)
            return(SSD)
        
        def SSD_Spread(self,priceX,priceY):
            priceX = np.log(priceX)
            priceY = np.log(priceY)
            retx = priceX.diff()[1:]
            rety = priceY.diff()[1:]
            standardX = (1 + retx).cumprod()
            standardY = (1 + rety).cumprod()
            spread = standardY - standardX
            return(spread)
    
            
        def SSD_Cal_Bound(self,priceX,priceY,width=1.5):
                
            spread = self.SSD_Spread(priceX,priceY)            
            mu = np.mean(spread)
            sd = np.std(spread)
            UpperBound = mu + width * sd
            LowerBound = mu - width * sd
            return(UpperBound,LowerBound)
    
    • 现在调用上述构建的类PairTrading,来快速计算中国银行与浦发银行的最小距离、价差序列以及交易期价差的阈值。
    # 读入数据
    sh = pd.read_csv('sh50_stock_data.csv',index_col='Trddt')
    sh.index = pd.to_datetime(sh.index)
    
    # 选取标的
    price_zhonghang = sh['601988']
    price_pufa = sh['600000']
    
    # 形成期价格
    price_zhonghang_form = price_zhonghang[formStart:formEnd]
    price_pufa_form = price_pufa[formStart:formEnd]
    
    # 交易期价格
    price_zhonghang_trade = price_zhonghang[tradStart:tradEnd]
    price_pufa_trade = price_pufa[tradStart:tradEnd]
    
    # 类的实例化
    pt = PairTrading()         # 调用类PairTrading()
    
    # 计算SSD
    SSD = pt.SSD(price_zhonghang_form,price_pufa_form)
    SSD
    
    0.47481704588389073
    
    # 形成期:SSDspread(价差序列)
    SSDspread = pt.SSD_Spread(price_zhonghang_form,price_pufa_form)
    
    # 根据形成期协整配对后价差序列得到的阈值1(开仓)
    bound_1 = pt.SSD_Cal_Bound(price_zhonghang,price_pufa,width=1.2)
    bound_1
    
    (0.07135801363557201, -0.1252480116392951)
    
    # 根据形成期协整配对后价差序列得到的阈值2(平仓)
    bound_2 = pt.SSD_Cal_Bound(price_zhonghang,price_pufa,width=0.2)
    bound_2
    
    (-0.010561163562289283, -0.04332883444143381)
    
    # 根据形成期协整配对后价差序列得到的阈值3(止损)
    bound_3 = pt.SSD_Cal_Bound(price_zhonghang,price_pufa,width=2.0)
    bound_3
    
    (0.13689335539386108, -0.19078335339758415)
    

    四、配对交易策略的回测(实测)

    接下来,运用中国银行和浦发银行股票的交易数据自行设计配对交易策略,这一次将2014年1月1日到2014年12月31日作为配对形成期,以及将2015年1月
    1日到2015年6月30日作为交易期。用Python实现配对交易策略大致有如下4个步骤。

    • (1) 在形成期内,计算中国银行和浦发银行两只股票价差序列的平均值( μ \mu μ)和标准差( σ \sigma σ)。
    • (2) 在交易期内,设定 μ \mu μ ± \pm ± 1.5 σ 1.5\sigma 1.5σ 为开仓阈值、 μ ± 0.2 σ \mu \pm 0.2\sigma μ±0.2σ 为平仓阈值,将 μ ± 2.5 σ \mu \pm 2.5\sigma μ±2.5σ 为止损阈值,具体交易规则如下:
      • 当价差上穿 μ + 1.5 σ \mu + 1.5\sigma μ+1.5σ 时,做空配对股票,反向建仓(即卖出浦发银行,买入中国银行,二者资金比值为 β \beta β);
      • 当价差下穿 μ + 0.2 σ \mu + 0.2\sigma μ+0.2σ 时,反向平仓;
      • 当价差下穿 μ − 1.5 σ \mu - 1.5\sigma μ1.5σ 时,做多配对股票,正向建仓(即买入浦发银行,卖出中国银行,二者资金比值为 β \beta β);
      • 当价差上穿 μ − 0.2 σ \mu - 0.2\sigma μ0.2σ 时,正向平仓;
      • 当价差突破 μ ± 2.5 σ \mu \pm 2.5\sigma μ±2.5σ 时,及时止损。
    • (3) 配对交易策略绩效评价

    接下来用Python编写代码,对浦发银行和中国银行股票进行从头到尾的配对交易策略实测。

    • (1) 获取数据,在形成期内,计算中国银行和浦发银行两只股票价差序列的平均值( μ \mu μ)和标准差( σ \sigma σ)。
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif'] = ['SimHei']   
    
    from arch.unitroot import ADF
    import statsmodels.api as sm
    
    # 读取数据
    sh = pd.read_csv('sh50_stock_data.csv',index_col='Trddt')
    sh.index = pd.to_datetime(sh.index)
    
    # 形成期:提取数据
    P_zhonghang = sh['601988']
    P_pufa = sh['600000']
    
    price_zhonghang_form = P_zhonghang[formStart:formEnd]
    price_pufa_form = P_pufa[formStart:formEnd]
    
    # 类的实例化
    pt = PairTrading()         # 调用类PairTrading()
    
    # 形成期:SSDspread(价差序列)
    SSD_spread_form = pt.SSD_Spread(price_zhonghang_form,price_pufa_form)
    
    # 计算均值、方差
    mu = np.mean(SSD_spread_form)
    sd = np.std(SSD_spread_form)
    
    • (2) 选取交易期价格数据,构造开仓平仓区间(如图6所示)。
    # 提取交易期数据
    price_zhonghang_trade = P_zhonghang[tradeStart:tradEnd]
    price_pufa_trade = P_pufa[tradeStart:tradEnd]
    
    # 交易期:SSDspread(价差序列)
    SSD_spread_trade = pt.SSD_Spread(price_zhonghang_trade,price_pufa_trade)
    
    # 绘制价格区间图
    plt.figure(figsize=(12,8))
    
    SSD_spread_trade.plot()
    
    plt.title('图6 价差序列(协整配对)(交易期)',loc='center', fontsize=16)
    
    plt.axhline(y=mu,color='black')
    plt.axhline(y=mu+0.2*sd,color='blue',ls='-',lw=2)
    plt.axhline(y=mu-0.2*sd,color='blue',ls='-',lw=2)
    plt.axhline(y=mu+2.0*sd,color='green',ls='--',lw=2.5)
    plt.axhline(y=mu-2.0*sd,color='green',ls='--',lw=2.5)
    plt.axhline(y=mu+3.5*sd,color='red',ls='-.',lw=3) 
    plt.axhline(y=mu-3.5*sd,color='red',ls='-.',lw=3) 
    
    plt.show()
    

    在这里插入图片描述

    • (4) 根据开仓平仓点制定交易策略,并模拟交易账户(如图7所示)。
    # 设置信号触发点
    level = (float('-inf'),mu-3.5*sd,mu-2.0*sd,mu-0.2*sd,mu+0.2*sd,mu+2.0*sd,mu+3.5*sd,float('inf'))
    
    prcLevel = pd.cut(SSD_spread_trade,level,labels=False) - 3         #剪切函数pd.cut()
    
    • 构造交易信号函数(以上述levels为例)
    # 构造交易信号函数
    def TradeSig(prcLevel):
        n = len(prcLevel)
        signal = np.zeros(n)
        
        for i in range(1,n):
            if prcLevel[i-1] == 1 and prcLevel[i] == 2:           #价差从1区上穿2区,反向建仓
                signal[i] = -2
            elif prcLevel[i-1] == 1 and prcLevel[i] == 0:        #价差从1区下穿0区,平仓
                signal[i] = 2
            elif prcLevel[i-1] == 2 and prcLevel[i] == 3:        #价差从2区上穿3区,即突破3区,平仓
                signal[i] = 3
            elif prcLevel[i-1] == -1 and prcLevel[i] == -2:     #价差从-1区下穿-2区,正向建仓
                signal[i] = 1
            elif prcLevel[i-1] == -1 and prcLevel[i] == 0:      #价差从-1区上穿0区,平仓
                signal[i] = -1
            elif prcLevel[i-1] == -2 and prcLevel[i] == -3:     #价差从-2区下穿-3区,即突破-3区,平仓
                signal[i] = -3
        return(signal)
    
    signal = TradeSig(prcLevel)
    
    # 设置买卖条件(信号)
    position = [signal[0]]
    ns = len(signal)
    
    for i in range(1,ns):
        position.append(position[-1])
        if signal[i] == 1:
            position[i] = 1
        elif signal[i] == -2:
            position[i] = -1
        elif signal[i] == -1 and position[i-1] == 1:
            position[i] = 0
        elif signal[i] == 2 and position[i-1] == -1:
            position[i] = 0
        elif signal[i] == 3:
            position[i] = 0
        elif signal[i] == -3:
            position[i]=0
    
    # 计算交易信号
    position = pd.Series(position, index=SSD_spread_trade.index)
    
    # 构造交易模拟函数
    def TradeSim(priceX,priceY,position):
        n = len(position)
        size = 1000
        beta = 1                  # 确定交易头寸:等权重;delta对冲;资金比例
        shareY = size * position
        shareX = [(-beta) * shareY[0] * priceY[0] / priceX[0]]
        cash = [2000]            # 1000股浦发大概15000元左右,10%保障金大概1500元!所以,取2000元初始金!!
        
        for i in range(1,n):
            shareX.append(shareX[i-1])
            cash.append(cash[i-1])
            if position[i-1] == 0 and position[i] == 1:
                shareX[i] = (-beta) * shareY[i] * priceY[i] / priceX[i]
                cash[i] = cash[i-1] - (shareY[i] * priceY[i] + shareX[i] * priceX[i])
            elif position[i-1] == 0 and position[i ]== -1:
                shareX[i] = (-beta) * shareY[i] * priceY[i] / priceX[i]
                cash[i] = cash[i-1] - (shareY[i] * priceY[i] + shareX[i] * priceX[i])
            elif position[i-1] == 1 and position[i] == 0:
                shareX[i] = 0
                cash[i] = cash[i-1] + (shareY[i-1] * priceY[i] + shareX[i-1] * priceX[i])
            elif position[i-1] == -1 and position[i] == 0:
                shareX[i] = 0
                cash[i] = cash[i-1] + (shareY[i-1] * priceY[i] + shareX[i-1] * priceX[i])
                
        cash = pd.Series(cash,index=position.index)
        shareY = pd.Series(shareY,index=position.index)
        shareX = pd.Series(shareX,index=position.index)
        asset = cash + shareY * priceY + shareX * priceX
        account = pd.DataFrame({'Position':position,'ShareY':shareY,'ShareX':shareX,'Cash':cash,'Asset':asset})
        return(account)
    
    account = TradeSim(price_zhonghang_trade,price_pufa_trade,position)
    
    account.iloc[:, [1,2,3,4]].plot(style=['--','--','-',':'], color=['red','blue','yellow','green'],figsize=(16,8))
    
    plt.title('图7  配对交易账户',loc='center', fontsize=16) 
    
    plt.show()
    

    在这里插入图片描述

    • ShareX、ShareY单位:股数(正代表买入,负代表卖出)
    • Cash、Asset单位:元
    参考资料:
    • 蔡立耑. 量化投资以Python为工具[M]. 北京:电子工业出版社,2017.
    数据下载
    • 请在留言区留下您的邮箱(其实任何其他标的的数据都可以替代)!

    • 写作不易,切勿白剽
    • 博友们的点赞关注就是对博主坚持写作的最大鼓励
    • 持续更新,未完待续…
    展开全文
  • 综合交易平台交易功能特别说明.pdf
  • 下单,需要配置CTP快期交易软件后台,键盘快捷下单
  • 第五章--择外汇交易与掉期外汇交易(PPT44页).ppt
  • 【量化笔记】配对交易

    千次阅读 2019-08-23 17:54:35
    配对交易的步骤 1. 如何挑选进行配对的股票 2. 挑选好股票对以后,如何制定交易策略,开仓点如何设计 3. 开仓是,两只股票如何进行多空仓对比 股票对的选择 1. 行业内匹配 2. 产业链配对 3. 财务管理配对 最小距离法...

    配对交易的步骤

    1. 如何挑选进行配对的股票
    2. 挑选好股票对以后,如何制定交易策略,开仓点如何设计
    3. 开仓是,两只股票如何进行多空仓对比

    股票对的选择

    1. 行业内匹配
    2. 产业链配对
    3. 财务管理配对

    最小距离法

    配对交易需要对股票价格进行标准化处理。假设 P t i ( t = 0 , 1 , 2 , . . . , T ) P_t^i(t=0,1,2,...,T) Pti(t=0,1,2,...,T)表示股票i在第t天的价格,那么股票i在第t天的单期收益率可以表达为:
    r t i = P t i − P t − 1 i P t − 1 i , t = 1 , 2 , 3 , . . . , T r_t^i=\frac{P_t^i-P_{t-1}^{i}}{P_{t-1}^{i}},t=1,2,3,...,T rti=Pt1iPtiPt1i,t=1,2,3,...,T

    p ^ t i \hat{p}_t^i p^ti 表示股票i在第t天的标准化价格,学界和业界认为 p ^ t i \hat{p}_t^i p^ti可以有这t天内的累计收益率来计算:
    p ^ t i = ∏ τ = 1 t ( 1 + r τ i ) \hat{p}^i_t=\prod_{\tau=1}^t (1+r_\tau^i) p^ti=τ=1t(1+rτi)

    假设有股票X,Y,则我们可以计算二者之间的标准化价差之平方和 S S D X , Y SSD_{X,Y} SSDX,Y

    S S D X , Y = ∑ t = 1 T ( p ^ t X − p ^ t Y ) 2 \\ SSD_{X,Y}=\sum_{t=1}^T (\hat{p}_t^X-\hat{p}_t^Y)^2 SSDX,Y=t=1T(p^tXp^tY)2

    下面使用python计算SSD

    import pandas as pd
    
    sh=pd.read_csv('sh50p.csv',index_col='Trddt')
    
    sh.index=pd.to_datetime(sh.index)
    
    sh.head()
    
    600000600010600015600016600018600028600030600036600048600050...601688601766601800601818601857601901601985601988601989601998
    Trddt
    2010-01-049.9972.2606.5414.6274.7758.44517.92713.1746.4436.703...-4.991--11.284--3.0554.5916.498
    2010-01-0510.0722.2506.7064.7084.7838.49418.80413.1886.2436.937...-4.982--11.499--3.0904.5736.578
    2010-01-069.8742.2556.4614.6154.7338.31118.58612.9136.2376.787...-4.947--11.342--3.0554.6276.393
    2010-01-079.6522.2016.3284.4934.6028.09118.13312.5786.2406.590...-4.875--11.267--2.9984.5736.176
    2010-01-089.7612.2116.3704.5394.6188.00518.48312.5786.3226.674...-4.902--11.135--3.0124.5256.232

    5 rows × 50 columns

    # 定义配对形成期
    formStart='2014-01-01'
    formEnd='2015-01-01'
    
    # 形成期数据
    shform=sh[formStart:formEnd]
    
    shform.head(2)
    
    600000600010600015600016600018600028600030600036600048600050...601688601766601800601818601857601901601985601988601989601998
    Trddt
    2014-01-028.3072.3606.3716.1835.0314.11712.2889.7195.1563.146...8.5344.8693.7812.3837.2455.91-2.3335.6173.634
    2014-01-038.1382.5946.1876.0874.9064.04311.9379.5205.1123.088...8.2934.7913.7252.3567.2175.91-2.2895.5173.578

    2 rows × 50 columns

    # 提取中国银行 601988 的收盘价数据
    PAf=shform['601988']
    
    # 提取浦发银行 600000 的收盘价数据
    PBf = shform['600000']
    
    #合并两只股票
    pairf=pd.concat([PAf,PBf],axis=1)
    
    len(pairf)
    
    245
    
    import numpy as np
    
    # 构造标准化价格之差平方累计SSD函数
    def SSD(priceX,priceY):
        if priceX is None or priceY is None:
            print('缺少价格序列')
        returnX = (priceX-priceX.shift(1))/priceX.shift(1)[1:]
        returnY = (priceY-priceY.shift(1))/priceY.shift(1)[1:]
        standardX=(returnX+1).cumprod()
        standardY=(returnY+1).cumprod()
        SSD = np.sum((standardX-standardY)**2)
        return SSD
    
    dis=SSD(PAf,PBf)
    
    dis
    
    0.47481704588389073
    
    SSD_rst=[]
    for i in shform.columns:
        for j in shform.columns:
            if i==j:
                continue;
            A=shform[i]
            B=shform[j]
            try:
                num=SSD(A,B)
            except:
                continue
            # print(i,j,num)
            try:
                lst=[i,j,num]
            except:
                continue
            SSD_rst.append(lst)
    
    SSDdf=pd.DataFrame(SSD_rst)
    
    SSDdf.head()
    
    012
    06000006000107.366730
    16000006000150.668806
    26000006000162.563524
    36000006000187.823916
    46000006000283.976679
    SSDdf.sort_values(by=2)
    
    012
    1026000156011660.245662
    9776011666000150.245662
    14356018576013980.329987
    12446013986018570.329987
    3876000506019880.422743
    14526019886000500.422743
    9846011666000500.446014
    3756000506011660.446014
    14436019886000000.474817
    366000006019880.474817
    3006000366013180.485505
    10996013186000360.485505
    14456019886000150.519690
    1146000156019880.519690
    9826011666000360.533362
    2976000366011660.533362
    3536000506000150.545751
    866000156000500.545751
    10116011666019880.546044
    14686019886011660.546044
    10026011666013180.568370
    11176013186011660.568370
    3036000366013980.653760
    12166013986000360.653760
    9486010886001110.656164
    4916001116010880.656164
    786000156000000.668806
    16000006000150.668806
    3816000506013980.704233
    12186013986000500.704233
    ............
    47960011160010964.595128
    44060010960011164.595128
    143460185760139065.941405
    120560139060185765.941405
    94760108860010967.396051
    45260010960108867.396051
    118660139060058571.932721
    65360058560139071.932721
    120460139060176672.876730
    139560176660139072.876730
    117460139060001873.037316
    18560001860139073.037316
    68960063760118675.475072
    107060118660063775.475072
    67460063760010978.702164
    44560010960063778.702164
    96560108860139079.636906
    119460139060108879.636906
    118260139060011181.322417
    49760011160139081.322417
    80960088760139082.309679
    119060139060088782.309679
    106760118660051887.971590
    57260051860118687.971590
    44260010960051896.995893
    55760051860010996.995893
    69260063760139097.687461
    118760139060063797.687461
    1184601390600518111.693514
    575600518601390111.693514

    1560 rows × 3 columns

    协整模型

    协整模型指如果X股票的对数价格是非平稳时间序列,且对数价格的差分序列是平稳的,责成X股票的对数价格是一阶单整序列。
    l o g ( P t X ) − l o g ( P t − 1 X ) = l o g ( P t X P t − 1 X ) = l o g ( 1 + r t X )   = r t X log(P_t^X)-log(P_{t-1}^X)=log(\frac{P_t^X}{P_{t-1}^X}) \\=log(1+r_t^X) \\~=r_t^X log(PtX)log(Pt1X)=log(Pt1XPtX)=log(1+rtX) =rtX

    下面计算中国银行和浦发银行是否是一阶单整序列

    from arch.unitroot import ADF
    
    import numpy as np
    
    PAf.head()
    
    Trddt
    2014-01-02    2.333
    2014-01-03    2.289
    2014-01-06    2.262
    2014-01-07    2.253
    2014-01-08    2.244
    Name: 601988, dtype: float64
    
    PAflog=np.log(PAf)
    
    adfA=ADF(PAflog)
    
    print(adfA.summary().as_text())
    
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                  3.409
    P-value                         1.000
    Lags                               12
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
    

    统计量较大,我们接受原假设,原序列存在单位根,所以中国银行的收盘价的对数序列是非平稳序列

    #对数差分
    retA=PAflog.diff()[1:]
    
    retA.head()
    
    Trddt
    2014-01-03   -0.019040
    2014-01-06   -0.011866
    2014-01-07   -0.003987
    2014-01-08   -0.004003
    2014-01-09   -0.004019
    Name: 601988, dtype: float64
    
    adfretA=ADF(retA)
    
    print(adfretA.summary().as_text())
    
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                 -4.571
    P-value                         0.000
    Lags                               11
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
    

    统计量较小,所以我们拒绝原假设,对数差分序列没有单位根,所以中国银行的对数差分序列是平稳序列

    由此说明中国银行的对数价格序列是一阶单整序列

    # 对浦发银行进行检验
    PBflog=np.log(PBf)
    
    adfB=ADF(PBflog)
    
    print(adfB.summary().as_text())
    
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                  2.392
    P-value                         0.999
    Lags                               12
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
    

    统计量较大,我们接受原假设,原序列存在单位根,所以浦发银行的收盘价的对数序列是非平稳序列

    #对数差分序列
    retB = PBflog.diff()[1:]
    
    adfretB=ADF(retB)
    
    print(adfretB.summary().as_text())
    
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                 -3.888
    P-value                         0.002
    Lags                               11
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
    

    统计量较小,所以拒绝原假设,不存在单位根,所以浦发银行的对数差分序列是平稳序列

    由此说明浦发银行的对数序列是一阶单整序列

    #绘制对数时序图
    import matplotlib.pyplot as plt
    
    PAflog.plot(label='ZGYH',style='--')
    PBflog.plot(label='PFYH',style='-')
    plt.legend(loc='upper left')
    plt.title("中国银行和浦发银行的对数价格时序图")
    
    Text(0.5, 1.0, '中国银行和浦发银行的对数价格时序图')
    

    在这里插入图片描述

    retA.plot(label='ZGYH')
    retB.plot(label='PFYH')
    plt.legend(loc='lower left')
    
    <matplotlib.legend.Legend at 0x1c238d0eb8>
    

    在这里插入图片描述

    检验两个对数序列的协整性

    方式是对两个序列进行线性拟合,对残差进行检验,如果残差序列是平稳的,说明两个对数序列具有协整性

    import statsmodels.api as sm
    
    model=sm.OLS(PBflog,sm.add_constant(PAflog))
    
    /Users/yaochenli/anaconda3/lib/python3.7/site-packages/numpy/core/fromnumeric.py:2389: FutureWarning: Method .ptp is deprecated and will be removed in a future version. Use numpy.ptp instead.
      return ptp(axis=axis, out=out, **kwargs)
    
    results=model.fit()
    
    print(results.summary())
    
                                OLS Regression Results                            
    ==============================================================================
    Dep. Variable:                 600000   R-squared:                       0.949
    Model:                            OLS   Adj. R-squared:                  0.949
    Method:                 Least Squares   F-statistic:                     4560.
    Date:                Fri, 23 Aug 2019   Prob (F-statistic):          1.83e-159
    Time:                        17:40:05   Log-Likelihood:                 509.57
    No. Observations:                 245   AIC:                            -1015.
    Df Residuals:                     243   BIC:                            -1008.
    Df Model:                           1                                         
    Covariance Type:            nonrobust                                         
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    const          1.2269      0.015     83.071      0.000       1.198       1.256
    601988         1.0641      0.016     67.531      0.000       1.033       1.095
    ==============================================================================
    Omnibus:                       19.538   Durbin-Watson:                   0.161
    Prob(Omnibus):                  0.000   Jarque-Bera (JB):               13.245
    Skew:                           0.444   Prob(JB):                      0.00133
    Kurtosis:                       2.286   Cond. No.                         15.2
    ==============================================================================
    
    Warnings:
    [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
    

    结果比较显著

    对残差进行平稳性检验

    #提取回归截距
    alpha=results.params[0]
    
    beta =results.params[1]
    
    spread=PBflog-beta*PAflog-alpha
    
    spread.head()
    
    Trddt
    2014-01-02   -0.011214
    2014-01-03   -0.011507
    2014-01-06    0.006511
    2014-01-07    0.005361
    2014-01-08    0.016112
    dtype: float64
    
    spread.plot()
    
    <matplotlib.axes._subplots.AxesSubplot at 0x1c23a44470>
    

    在这里插入图片描述

    # 价差序列单位根检验
    # 因为残差的均值是0,所以trend设为nc
    adfSpread=ADF(spread,trend='nc')
    
    print(adfSpread.summary().as_text())
    
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                 -3.199
    P-value                         0.001
    Lags                                0
    -------------------------------------
    
    Trend: No Trend
    Critical Values: -2.57 (1%), -1.94 (5%), -1.62 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
    

    统计量较小,所以拒绝原假设,认为残差是平稳的

    配对交易策略的制定

    最小距离法

    计算形成期内标准化的价格序列差 P ^ t X − P ^ t Y \hat{P}^X_t-\hat{P}^Y_t P^tXP^tY的平均值 μ \mu μ和标准差 σ \sigma σ,设定交易信号出发点为 μ + − 2 σ \mu+-2\sigma μ+2σ交易期为6个月。由于浦发银行和中国银行为银行业股票,价格比较稳定,因此我们设定交易期内价差超过 μ + − 1.2 σ \mu+-1.2\sigma μ+1.2σ时触发交易信号。

    #最短距离法交易策略
    #中国银行的标准化价格
    standardA=(1+retA).cumprod()
    
    #浦发银行的标准化价格
    standardB=(1+retB).cumprod()
    
    #标准价差
    SSD_pair=standardB-standardA
    
    SSD_pair.head()
    
    Trddt
    2014-01-03   -0.001514
    2014-01-06    0.015407
    2014-01-07    0.013962
    2014-01-08    0.024184
    2014-01-09    0.037629
    dtype: float64
    
    meanSSD_pair = np.mean(SSD_pair)
    
    sdSSD_pair=np.std(SSD_pair)
    
    thresholdUP=meanSSD_pair+1.2*sdSSD_pair
    
    thresholdDOWN=meanSSD_pair-1.2*sdSSD_pair
    
    SSD_pair.plot()
    plt.axhline(y=meanSSD_pair,color='black')
    plt.axhline(y=thresholdUP,color='blue')
    plt.axhline(y=thresholdDOWN,color='red')
    
    <matplotlib.lines.Line2D at 0x1c24027860>
    

    在这里插入图片描述

    在交易期当价差上穿阀值的时候反向开仓,回归平均线左右的时候平仓,当价差下穿阀值线的时候正向开仓,在价差回归平均线左右的时候平仓。

    #交易期
    tradStart='2015-01-01'
    
    tradEnd='2015-06-30'
    
    PAt=sh.loc[tradStart:tradEnd,'601988']
    PBt=sh.loc[tradStart:tradEnd,'600000']
    
    def spreadCal(x,y):
        retx=(x-x.shift(1))/x.shift(1)[1:]
        rety=(y-y.shift(1))/y.shift(1)[1:]
        standardX=(1+retx).cumprod()
        standardY=(1+rety).cumprod()
        spread=standardY-standardX
        return spread
    
    TradSpread=spreadCal(PAt,PBt).dropna()
    
    TradSpread.describe()
    
    count    118.000000
    mean       0.001064
    std        0.054323
    min       -0.127050
    25%       -0.028249
    50%        0.005682
    75%        0.041375
    max        0.100249
    dtype: float64
    
    TradSpread.plot()
    plt.axhline(y=meanSSD_pair,color='black')
    plt.axhline(y=thresholdUP,color='blue')
    plt.axhline(y=thresholdDOWN,color='red')
    
    <matplotlib.lines.Line2D at 0x1c240f9a58>
    

    在这里插入图片描述

    协整模型

    构建PairTrading类

    import re
    import pandas as pd
    import numpy as np
    from arch.unitroot import ADF
    import statsmodels.api as sm
    class PairTrading:
        #计算两个股票之间的距离
        def SSD(self,priceX,priceY):
            if priceX is None or priceY is None:
                print('缺少价格序列')
                return
            returnX=(priceX-priceX.shift(1))/priceX.shift(1)[1:]
            returnY=(priceY-priceY.shift(1))/priceY.shift(1)[1:]
            standardX=(1+returnX).cumprod()
            standardY=(1+returnY).cumprod()
            SSD=np.sum((standardY-standardX)**2)
            return SSD
        
        #计算标准价差序列
        def SSDSpread(self,priceX,priceY):
            if priceX is None or priceY is None:
                print('缺少价格徐磊')
                return
            returnX=(priceX-priceX.shift(1))/priceX.shift(1)[1:]
            returnY=(priceY-priceY.shift(1))/priceY.shift(1)[1:]
            standardX=(1+returnX).cumprod()
            standardY=(1+returnY).cumprod()
            spread=standardY-standardX
            return spread
        
        #判断是否是协整序列,并返回协整序列的线性回归参数
        def cointegration(self,priceX,priceY):
            if priceX is None or priceY is None:
                print('缺少价格序列.')
            priceX=np.log(priceX)
            priceY=np.log(priceY)
            results=sm.OLS(priceY,sm.add_constant(priceX)).fit()
            resid=results.resid
            adfSpread=ADF(resid)
            if adfSpread.pvalue>=0.05:
                print('''交易价格不具有协整关系.
                P-value of ADF test: %f
                Coefficients of regression:
                Intercept: %f
                Beta: %f
                 ''' % (adfSpread.pvalue, results.params[0], results.params[1]))
                return(None)
            else:
                print('''交易价格具有协整关系.
                P-value of ADF test: %f
                Coefficients of regression:
                Intercept: %f
                Beta: %f
                 ''' % (adfSpread.pvalue, results.params[0], results.params[1]))
                return(results.params[0], results.params[1])
        #计算协整序列差
        def CointegrationSpread(self,priceX,priceY,formPeriod,tradePeriod):
            if priceX is None or priceY is None:
                print('缺少价格序列.')
            if not (re.fullmatch('\d{4}-\d{2}-\d{2}:\d{4}-\d{2}-\d{2}',formPeriod)
                    or re.fullmatch('\d{4}-\d{2}-\d{2}:\d{4}-\d{2}-\d{2}',tradePeriod)):
                print('形成期或交易期格式错误.')
            formX=priceX[formPeriod.split(':')[0]:formPeriod.split(':')[1]]
            formY=priceY[formPeriod.split(':')[0]:formPeriod.split(':')[1]]
            coefficients=self.cointegration(formX,formY)
            if coefficients is None:
                    print('未形成协整关系,无法配对.')
            else:
                spread=(np.log(priceY[tradePeriod.split(':')[0]:tradePeriod.split(':')[1]])
                -coefficients[0]-coefficients[1]*np.log(priceX[tradePeriod.split(':')[0]:tradePeriod.split(':')[1]]))
                return(spread)
        #计算边界
        def calBound(self,priceX,priceY,method,formPeriod,width=1.5):
            if not (re.fullmatch('\d{4}-\d{2}-\d{2}:\d{4}-\d{2}-\d{2}',formPeriod)
                    or re.fullmatch('\d{4}-\d{2}-\d{2}:\d{4}-\d{2}-\d{2}',tradePeriod)):
                print('形成期或交易期格式错误.')
            if method=='SSD':
                spread=self.SSDSpread(priceX[formPeriod.split(':')[0]:formPeriod.split(':')[1]],
                                      priceY[formPeriod.split(':')[0]:formPeriod.split(':')[1]])            
                mu=np.mean(spread)
                sd=np.std(spread)
                UpperBound=mu+width*sd
                LowerBound=mu-width*sd
                return(UpperBound,LowerBound)
            elif method=='Cointegration':
                spread=self.CointegrationSpread(priceX,priceY,formPeriod,formPeriod)
                mu=np.mean(spread)
                sd=np.std(spread)
                UpperBound=mu+width*sd
                LowerBound=mu-width*sd
                return(UpperBound,LowerBound)
            else:
                print('不存在该方法. 请选择"SSD"或是"Cointegration".')
    
    formPeriod='2014-01-01:2015-01-01'
    tradePeriod='2015-01-01:2015-06-30'
    
    priceA=sh['601988']
    priceB=sh['600000']
    priceAf=priceA[formPeriod.split(':')[0]:formPeriod.split(':')[1]]
    priceBf=priceB[formPeriod.split(':')[0]:formPeriod.split(':')[1]]
    priceAt=priceA[tradePeriod.split(':')[0]:tradePeriod.split(':')[1]]
    priceBt=priceB[tradePeriod.split(':')[0]:tradePeriod.split(':')[1]]
    
    pt=PairTrading()
    SSD=pt.SSD(priceAf,priceBf)
    SSD
    
    0.47481704588389073
    
    SSDspread=pt.SSDSpread(priceAf,priceBf)
    SSDspread.describe()
    SSDspread.head()
    
    Trddt
    2014-01-02         NaN
    2014-01-03   -0.001484
    2014-01-06    0.015385
    2014-01-07    0.013946
    2014-01-08    0.024184
    dtype: float64
    
    coefficients=pt.cointegration(priceAf,priceBf)
    coefficients
    
    交易价格具有协整关系.
                P-value of ADF test: 0.020415
                Coefficients of regression:
                Intercept: 1.226852
                Beta: 1.064103
                 
    
    
    
    
    
    (1.2268515742404387, 1.0641034525888144)
    
    CoSpreadF=pt.CointegrationSpread(priceA,priceB,formPeriod,formPeriod)
    CoSpreadF.head()
    
    交易价格具有协整关系.
                P-value of ADF test: 0.020415
                Coefficients of regression:
                Intercept: 1.226852
                Beta: 1.064103
                 
    
    
    
    
    
    Trddt
    2014-01-02   -0.011214
    2014-01-03   -0.011507
    2014-01-06    0.006511
    2014-01-07    0.005361
    2014-01-08    0.016112
    dtype: float64
    
    CoSpreadTr=pt.CointegrationSpread(priceA,priceB,formPeriod,tradePeriod)
    CoSpreadTr.describe()
    
    交易价格具有协整关系.
                P-value of ADF test: 0.020415
                Coefficients of regression:
                Intercept: 1.226852
                Beta: 1.064103
                 
    
    
    
    
    
    count    119.000000
    mean      -0.037295
    std        0.052204
    min       -0.163903
    25%       -0.063038
    50%       -0.033336
    75%        0.000503
    max        0.057989
    dtype: float64
    
    bound=pt.calBound(priceA,priceB,'Cointegration',formPeriod,width=1.2)
    bound
    
    交易价格具有协整关系.
                P-value of ADF test: 0.020415
                Coefficients of regression:
                Intercept: 1.226852
                Beta: 1.064103
                 
    
    
    
    
    
    (0.03627938704534019, -0.03627938704533997)
    
    #配对交易实测
    #提取形成期数据
    formStart='2014-01-01'
    formEnd='2015-01-01'
    PA=sh['601988']
    PB=sh['600000']
    
    PAf=PA[formStart:formEnd]
    PBf=PB[formStart:formEnd]
    
    #形成期协整关系检验
    #一阶单整检验
    log_PAf=np.log(PAf)
    adfA=ADF(log_PAf)
    print(adfA.summary().as_text())
    adfAd=ADF(log_PAf.diff()[1:])
    print(adfAd.summary().as_text())
    
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                  3.409
    P-value                         1.000
    Lags                               12
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                 -4.571
    P-value                         0.000
    Lags                               11
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
    
    log_PBf=np.log(PBf)
    adfB=ADF(log_PBf)
    print(adfB.summary().as_text())
    adfBd=ADF(log_PBf.diff()[1:])
    print(adfBd.summary().as_text())
    
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                  2.392
    P-value                         0.999
    Lags                               12
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                 -3.888
    P-value                         0.002
    Lags                               11
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
    
    #协整关系检验
    model=sm.OLS(log_PBf,sm.add_constant(log_PAf)).fit()
    model.summary() 
    
    OLS Regression Results
    Dep. Variable:600000 R-squared: 0.949
    Model:OLS Adj. R-squared: 0.949
    Method:Least Squares F-statistic: 4560.
    Date:Fri, 23 Aug 2019 Prob (F-statistic):1.83e-159
    Time:17:43:03 Log-Likelihood: 509.57
    No. Observations: 245 AIC: -1015.
    Df Residuals: 243 BIC: -1008.
    Df Model: 1
    Covariance Type:nonrobust
    coefstd errtP>|t|[0.0250.975]
    const 1.2269 0.015 83.071 0.000 1.198 1.256
    601988 1.0641 0.016 67.531 0.000 1.033 1.095
    Omnibus:19.538 Durbin-Watson: 0.161
    Prob(Omnibus): 0.000 Jarque-Bera (JB): 13.245
    Skew: 0.444 Prob(JB): 0.00133
    Kurtosis: 2.286 Cond. No. 15.2


    Warnings:
    [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
    alpha=model.params[0]
    alpha 
    
    1.2268515742404387
    
    beta=model.params[1]
    beta 
    
    1.0641034525888144
    
    #残差单位根检验
    spreadf=log_PBf-beta*log_PAf-alpha
    adfSpread=ADF(spreadf)
    
    print(adfSpread.summary().as_text())
    
       Augmented Dickey-Fuller Results   
    =====================================
    Test Statistic                 -3.193
    P-value                         0.020
    Lags                                0
    -------------------------------------
    
    Trend: Constant
    Critical Values: -3.46 (1%), -2.87 (5%), -2.57 (10%)
    Null Hypothesis: The process contains a unit root.
    Alternative Hypothesis: The process is weakly stationary.
    
    mu=np.mean(spreadf)
    sd=np.std(spreadf)
    
    #设定交易期
    
    tradeStart='2015-01-01'
    tradeEnd='2015-06-30'
    
    
    PAt=PA[tradeStart:tradeEnd]
    PBt=PB[tradeStart:tradeEnd]
    
    CoSpreadT=np.log(PBt)-beta*np.log(PAt)-alpha
    
    CoSpreadT.describe()
    
    count    119.000000
    mean      -0.037295
    std        0.052204
    min       -0.163903
    25%       -0.063038
    50%       -0.033336
    75%        0.000503
    max        0.057989
    dtype: float64
    
    CoSpreadT.plot()
    plt.title('交易期价差序列(协整配对)')
    plt.axhline(y=mu,color='black')
    plt.axhline(y=mu+0.2*sd,color='blue',ls='-',lw=2)
    plt.axhline(y=mu-0.2*sd,color='blue',ls='-',lw=2)
    plt.axhline(y=mu+1.5*sd,color='green',ls='--',lw=2.5)
    plt.axhline(y=mu-1.5*sd,color='green',ls='--',lw=2.5)
    plt.axhline(y=mu+2.5*sd,color='red',ls='-.',lw=3) 
    plt.axhline(y=mu-2.5*sd,color='red',ls='-.',lw=3)
    
    <matplotlib.lines.Line2D at 0x1c2431b470>
    

    在这里插入图片描述

    level=(float('-inf'),mu-2.5*sd,mu-1.5*sd,mu-0.2*sd,mu+0.2*sd,mu+1.5*sd,mu+2.5*sd,float('inf'))
    
    prcLevel=pd.cut(CoSpreadT,level,labels=False)-3
    
    prcLevel.head()
    
    Trddt
    2015-01-05   -1
    2015-01-06   -2
    2015-01-07   -3
    2015-01-08   -2
    2015-01-09   -3
    dtype: int64
    
    def TradeSig(prcLevel):
        n=len(prcLevel)
        signal=np.zeros(n)
        for i in range(1,n):
            #反向建仓
            if prcLevel[i-1]==1 and prcLevel[i]==2:
                signal[i]=-2
            #反向平仓
            elif prcLevel[i-1]==1 and prcLevel[i]==0:
                signal[i]=2
            #强制平仓
            elif prcLevel[i-1]==2 and prcLevel[i]==3:
                signal[i]=3
            #正向建仓
            elif prcLevel[i-1]==-1 and prcLevel[i]==-2:
                signal[i]=1
            #正向平仓
            elif prcLevel[i-1]==-1 and prcLevel[i]==0:
                signal[i]=-1
            #强制平仓
            elif prcLevel[i-1]==-2 and prcLevel[i]==-3:
                signal[i]=-3
        return(signal)
    
    signal=TradeSig(prcLevel)
    
    position=[signal[0]]
    ns=len(signal)
    
    for i in range(1,ns):
        position.append(position[-1])
        #正向建仓
        if signal[i]==1:
            position[i]=1
        #反向建仓
        elif signal[i]==-2:
            position[i]=-1
        #正向平仓
        elif signal[i]==-1 and position[i-1]==1:
            position[i]=0
        #反向平仓
        elif signal[i]==2 and position[i-1]==-1:
            position[i]=0
        #强制平仓
        elif signal[i]==3:
            position[i]=0
        elif signal[i]==-3:
            position[i]=0
    
    position=pd.Series(position,index=CoSpreadT.index)
    
    position.tail()
    
    Trddt
    2015-06-24    0.0
    2015-06-25    0.0
    2015-06-26    0.0
    2015-06-29    0.0
    2015-06-30    0.0
    dtype: float64
    
    def TradeSim(priceX,priceY,position):
        n=len(position)
        size=1000
        shareY=size*position
        shareX=[(-beta)*shareY[0]*priceY[0]/priceX[0]]
        cash=[2000]
        for i in range(1,n):
            shareX.append(shareX[i-1])
            cash.append(cash[i-1])
            if position[i-1]==0 and position[i]==1:
                shareX[i]=(-beta)*shareY[i]*priceY[i]/priceX[i]
                cash[i]=cash[i-1]-(shareY[i]*priceY[i]+shareX[i]*priceX[i])
            elif position[i-1]==0 and position[i]==-1:
                shareX[i]=(-beta)*shareY[i]*priceY[i]/priceX[i]
                cash[i]=cash[i-1]-(shareY[i]*priceY[i]+shareX[i]*priceX[i])
            elif position[i-1]==1 and position[i]==0:
                shareX[i]=0
                cash[i]=cash[i-1]+(shareY[i-1]*priceY[i]+shareX[i-1]*priceX[i])
            elif position[i-1]==-1 and position[i]==0:
                shareX[i]=0
                cash[i]=cash[i-1]+(shareY[i-1]*priceY[i]+shareX[i-1]*priceX[i])
        cash = pd.Series(cash,index=position.index)
        shareY=pd.Series(shareY,index=position.index)
        shareX=pd.Series(shareX,index=position.index)
        asset=cash+shareY*priceY+shareX*priceX
        account=pd.DataFrame({'Position':position,'ShareY':shareY,'ShareX':shareX,'Cash':cash,'Asset':asset})
        return(account)
    
    account=TradeSim(PAt,PBt,position)
    account.tail() 
    
    
    
    PositionShareYShareXCashAsset
    Trddt
    2015-06-240.00.00.05992.5145992.514
    2015-06-250.00.00.05992.5145992.514
    2015-06-260.00.00.05992.5145992.514
    2015-06-290.00.00.05992.5145992.514
    2015-06-300.00.00.05992.5145992.514
    account.iloc[:,[1,3,4]].plot(style=['--','-',':'])
    plt.title('配对交易账户') 
    
    Text(0.5, 1.0, '配对交易账户')
    

    在这里插入图片描述

    展开全文
  • 综合交易平台交易功能特别说明文.pdf
  • 数字交易平台系统操作指引.pdf
  • 外汇EA,经典EA源代码,供有兴趣的同学研究。
  • 交易情绪跟踪第124:消费与金融交易回暖.pdf
  • 东海潜龙高端交易平台交易策略说明书-跨套利稳健型.doc
  • 工行银转帐开户和交易流程.docx
  • 量化交易 如何建立自己的算法交易事业,金融数据分析的扛鼎之作,它的价值懂的自然懂!
  • 金融产品交易量跟踪报告第46.pdf
  • 金融产品交易量跟踪报告第44.pdf
  • 数字交易平台系统操作指引汇编.pdf
  • 网上项目交易平台系统一技术方案.doc
  • 关于期货异常交易行为风险揭示书(四交易所)doc-唐山.docx
  • 套利组合指令交易方法与策略.doc
  • 交易情绪跟踪第120:市场情绪继续回暖.pdf
  • 交易情绪跟踪第115:涨跌分化进一步收敛.pdf
  • 交易情绪跟踪第116:市场情绪或已触底.pdf
  • 美团技术沙龙-第50:外卖交易系统平台化建设之路 2-何轼《订单交易平台化建设实践》.pdf 介绍了美团订单交易平台化建设的细节,干货。 视频我也有,可私我或者评论中留下联系方式。
  • 交易情绪跟踪第119:利率悉数下行,情绪底部修复.pdf
  • 交易情绪跟踪第131:稳增长升温,情绪短期触底.pdf
  • 交易情绪跟踪第129:成交趋向均衡,分歧继续加大.pdf
  • xxxxxx交易中心数据仓库一项目技术标书(共30页).doc
  • 期货趋势多空交易指标文华财经指标公式期货软件指标公式赢顺赢智睿指标.doc

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 82,064
精华内容 32,825
关键字:

交易期