【转】期限结构Carry收益 期货多品种对冲模型

期限结构与carry大致定义

简单来说,展期收益就是不同月间合约的价差。这种收益也被称为carry收益,一般意义上的carry是指票息所得和资金成本之间的差。举例说,如果你借钱5%成本买企业债并收到了利息7%,债券利息比借贷利息高的部分,就是一种低风险收益。所以当你看准机会时,展期收益是一种相对低风险的收益,也是和趋势交易几乎完全无关的收益。

螺纹钢各期合约价格.png
通过上图看出,螺纹的远期合约价格更低

carry展期收益是一种重要的收益来源,你可以按照字面理解就是持有它,在很多市场carry都会产生收益。在固定收益领域有句话:Carry is the king。Total Return = Carry Mark to Market P&L(总回报=Carry 市值),其中Carry = 票息 – 融资成本。

QQ图片20181228204004.png
公式来自:Carry Ralph S.J. Koijen Tobias J.Moskowitz Lasse Heje Pedersen Evert B. Vrugt November 2016

在商品期货领域期货和现货无风险套利的定义是:远期合约和近期合约,存在套利机会,期货合约到期日之前,期货与现货除受供需影响外,亦受持有成本(cost of carry)的影响。由此可以理解carry收益,由期货的两个特性决定——期限性和收敛性。

今天的文章在聚宽平台上,我们就简单实现这个策略的多品种对冲效果。虽然之前有很多人推荐继续写时间序列策略,但是考虑到聚宽大神太多,我写一两个害怕被看出来水平太菜,所以留个诸位自行发挥吧,我们搞点别的。

2.png

远期和近期合约由于交割时间不同,市场需求不同,产生了价差。远期升水Contango的情况较多,因为有资金利息和仓储成本的影响。期货贴水backward也会发生,由于短期供需缺口和产期经济前景看淡,会造成远期合约价格较低。

比如我在2018年12月28日,以3868元平仓1手螺纹钢1901合约多单,然后以3399元买入1手1905合约多单,我的持仓量始终都是1手,但是我降低了持有成本3868 - 3399元,此时可以认为我的展期收益 = 01新合约 - 05老合约 = 469元,全段展期收益率 = 14.04%,折合每月展期收益率 = 14.04% / 4(两个合约之间的相隔月数) = 3.51%。这种展期收益为正的结果叫做远月合约贴水,如果远月比近月贵,则叫做升水。

今天简单介绍一个标准的商品期货市场展期收益率模型,它通过做多贴水最多的合约,做空升水最多的合约,赌升贴水收敛,获得较为稳定的carry收益。

展期收益率解读

展期收益策略是商品期货特有的策略类型。逻辑上,展期收益策略与传统的趋势类策略相关性较差,有较好的互补性,因为他们从根源上不同源。

对于资产管理,商品配置一般不投资于实物商品,业内流行的方式是通过商品期货,然后滚动移仓,达到配置商品的目的。理论上,投资商品期货的收益可以分解成:

Futuresreturn = Spotreturn Rollreturn Collateralreturn

即期货投资收益由3部分构成:对应现货的收益、展期收益和现金收益。这里roll收益和carry收益相对应。

在商品期货市场,同一标的品种对应着不同交割日的期货合约,如螺纹钢每年有1月,5月,10月,这3个主力合约。

商品期货的现货价格(这里常用近月合约代替现货价格)与不同交割月期货合约交易价格之间的价格差,即商品期货的期限结构。若现货价格大于期货价格,或近月合约的期货价格大于远月合约的期货价格,称为期货贴水backward,或现货升水;若现货价格小于期货价格,或近月合约的期货价格小于远月合约的期货价格,称为期货升水Contango,或现货贴水。

我们一般说升贴水,都是针对远期合约。

展期收益率特指两个合约之间的收益差额,它属于期限结构的研究范围内,期限结构是某一个特定品种的期货所有合约的价格按时间排列构成的曲线,如下图:

AL.jpg
AL铝期货期限结构(多期合约价格)

RB.jpg
螺纹钢期限结构(多期合约价格)

在聚宽研究平台获取价格和绘图代码如下:

import matplotlib.pyplot as plt
import pandas as pd
symbolList = get_future_contracts('RB')
PriceList  = []
SymList = []
for i in symbolList:
    SymList.append(i)
    PriceList.append(attribute_history(i,1,'1d',['close'])['close'][-1])
s_1 = pd.Series(SymList, name='Symbol')
s_2 = pd.Series(PriceList, name="Price")
df = pd.concat([s_1, s_2], axis=1)
df=df.set_index("Symbol")  

plt.figure(figsize=(15, 7))
plt.plot(df)
plt.show()

我们可以通过计算不同标的物的展期收益率来度量不同标的的现货溢价幅度,并根据不同标的之间展期收益率的高低来构建交易策略。

假设 Pt,n 是 t 时刻近月合约的价格,Pt,d 是 t 时刻远月合约的价格,Nt,n 是近月合约在 t 时刻距离交割日的天数,Nt,n 是远月合约在 t 时刻距离交割日的天数。则展期收益率 Rt为:

QQ图片20181228204309.png

当 Rt 为正,即近月合约价格大于远月合约价格,当 Rt 为负,即近月合约价格小于远月合约价格。对同一横截面的所有品种来说,最大的 Rt,即对所有品种来说,该标的的近月合约对远月合约涨幅最大,最小的 Rt,即对所有品种来说,该标的的近月合约对远月合约跌幅最大。

按照渤海证券的交易逻辑:若不同合约的展期收益率排名可在一定程度上体现“多强空弱”中的“强”、“弱”概念,即可根据展期收益率排名构建交易策略,从而在展期收益率的角度做到“顺势而为”。

绘制展期收益率的代码如下:

# 以螺纹钢1901 1905合约为例
PriceList1901 = attribute_history('RB1901.XSGE',120,'1d',['close'])
PriceList1905 = attribute_history('RB1905.XSGE',120,'1d',['close'])
df = pd.concat([PriceList1901, PriceList1905], axis=1)
df.columns= ['RB1901.XSGE','RB1905.XSGE']
# 计算展期收益率
df['RY:RB'] = df.apply(lambda x: (x[0] / x[1]-1)*3, axis=1)
plt.figure(figsize=(15, 7))
plt.plot(df['RY:RB'])
plt.legend(['RY:RB'])
plt.show()

webwxgetmsgimg (1).jpg
螺纹展期收益率

webwxgetmsgimg (2).jpg
沪铝展期收益率

由于展期收益率的计算不涉及到指数合约,都是在两个相邻的真实合约之间进行,所以我们首先人工写出了历史上的大部分期货品种的主力合约,如这样。

# 历史上的每个合约主力月份
    g.domMonth = {
        'MA': ['01', '05', '09'],
        'IC':['01','02','03','04','05','06','07','08','09','10','11','12'],
        'IF':['01','02','03','04','05','06','07','08','09','10','11','12'],
        'IH':['01','02','03','04','05','06','07','08','09','10','11','12'],
        'TF':['03','06','09','12'],
        'T':['03','06','09','12'],
        'CU':['01','02','03','04','05','06','07','08','09','10','11','12'],
        'AL':['01','02','03','04','05','06','07','08','09','10','11','12'],
        'ZN':['01','02','03','04','05','06','07','08','09','10','11','12'],
        'PB':['01','02','03','04','05','06','07','08','09','10','11','12'],
        'NI':['01', '05', '09'],
        'SN':['01', '05', '09'],
        'AU':['06', '12'],
        'AG':['06', '12'],
        'RB':['01', '05', '10'],
        'HC':['01', '05', '10'],
        'BU':['06', '09', '12'],
        'RU':['01', '05', '09'],
        'M':['01', '05', '09'],
        'Y':['01', '05', '09'],
        'A':['01', '05', '09'],
        'P':['01', '05', '09'],
        'C':['01', '05', '09'],
        'CS':['01', '05', '09'],
        'JD':['01', '05', '09'],
        'L':['01', '05', '09'],
        'V':['01', '05', '09'],
        'PP':['01', '05', '09'],
        'J':['01', '05', '09'],
        'JM':['01', '05', '09'],
        'I':['01', '05', '09'],
        'SR':['01', '05', '09'],
        'CF':['01', '05', '09'],
        'ZC':['01', '05', '09'],
        'FG':['01', '05', '09'],
        'TA':['01', '05', '09'],
        'MA':['01', '05', '09'],
        'OI':['01', '05', '09'],
        'RM':['01', '05', '09'],
        'SF':['01', '05', '09'],
        'SM':['01', '05', '09'],
        'AP':['01', '05', '10'],
    }

然后我们撰写了一个函数,来获取当时的远月合约名称,该函数大家可以直接使用:

# 获得当前远月合约
def get_nextDom(context,ins):
    # 获取当月主力合约
    dom = get_dominant_future(ins)
    if dom !='':
        # 获取合约交割月份时间,如['1601'] 
        YD = re.findall(r"\d \d*",dom)
        try:
            # 获取远月合约——读取“历史上的每个合约主力月份”,读取月份后两位,往后移一位
            nextDomMonth = g.domMonth[ins][g.domMonth[ins].index(YD[0][-2:]) 1]
            # 替换远月合约日期,合成远月合约名,如['RB1601.XSGE'] 
            g.MappingNext[ins]=dom.replace(YD[0][-2:],nextDomMonth)
        except:
            nextDomMonth = g.domMonth[ins][0]
            nextDom = dom.replace(YD[0][:2],str(int(YD[0][:2]) 1))
            g.MappingNext[ins] = nextDom.replace(YD[0][-2:],g.domMonth[ins][0])
    else:
        pass

交易规则方面,我们考虑一定要尽可能简单,我们计算商品池内所有商品的ts(展期收益率)因子,将因子值大于0的商品归为远期贴水backward组,将因子小于0的商品归为远期升水contango组;

因为我们约定常用远期合约描述升水贴水,所以近期比远期高,是远期贴水,近期升水,属于contango。反之,属于backward。

这里的升和贴,和展期收益率的大小,是相反的,这里是比较绕的一点。

# 展期收益率
g.RY[ins] = (g.PriceCurrent-g.PriceNext)/g.PriceNext/g.DM
# 分为远期升水RYS,远期贴水RYB,两组
if g.RY[ins] < 0:
    g.RYS[ins] = g.RY[ins]
elif g.RY[ins] > 0:
    g.RYB[ins] = g.RY[ins]

按照“多强空弱”中的理念,我们做多展期收益率最高的品种,做空展期收益率最低的品种。这里你可以按照某些研报上所说,在两组内再做一个强度区分,比如只做每一组的前50%的品种。当然也可以全部做,我建议在测试模型时,全部交易。

## 交易模块 
def Trade(context):
    # 多头部分的品种,展期收益率大于0
    a = sorted(g.RYB.items(), key=lambda x: x[1],reverse = True)
    # 空头部分的品种,展期收益率小于0
    b = sorted(g.RYS.items(), key=lambda x: x[1],reverse = False)

大家可以看到我们在初始设置里,对于手续费的设定是比较严格的,这个手续费做中长期模型是肯定够用了,如果你担心手续费低,就再加上一倍的冲击成本我也没意见:

# 期货类每笔交易时的手续费是:买入时万分之1,卖出时万分之1,平今仓为万分之1
    set_order_cost(OrderCost(open_commission=0.0001, close_commission=0.0001,close_today_commission=0.0001), type='index_futures')
    # 设定保证金比例
    set_option('futures_margin_rate', 0.15)
    # 设置滑点(单边万5,双边千1)
    set_slippage(PriceRelatedSlippage(0.001),type='future')

期限结构Carry收益性能测试和分析

模型我们最初采用了月度调仓方案,获得如下绩效:

QQ截图20181228205136.png

然后我们尝试,对所做的合约进行筛选,比如说,我只做多展期收益率为正的且最高的前50%,做空为负且最低的后50%,在代码这里做调整:

# 将字典进行排序,各买入50%,或者全部交易
    for i in range(int(len(a)*1)):
        BuyList.append(a[i][0])
    for i in range(int(len(b)*1)):
        SellList.append(b[i][0])

我们分别测试了25% 50%和75%,得到这样的绩效:

25.png

我感觉这样的测试不利于得到稳定的测试结论,所以还是选择全做了。

在全部交易的时候,我截取了一天的持仓,大家可以看细节:

QQ截图20181228205810.png

可以看到,持仓是相对均衡的,也就是说,它基本上实现了多品种多空对冲。这就是Carry收益的策略。

再次总结,它获取的是和趋势完全不相关的收益,通过远期近期合约的收益率差异,计算升贴水,然后全市场分析升贴水率(展期收益率)。做多展期收益率更高(近期比远期更强)的品种,做空展期收益率更低(近期比远期更弱)的品种。

Carry展期收益是有一定风险的,要做好风险控制,在做期货趋势的同时搭配这套模型,综合曲线可能会更好。

412431.png

最后,我们还测试了周度调仓上图,结果较为理想,回撤控制确实满意。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值