[原创] 商品期货跨品种套利模型

大宗商品期货市场中除了跨期套利,也可以进行跨品种套利。对于跨品种套利来说螺纹钢和热卷是最好的两个合约品种了。由于rb(螺纹钢)和hc(热卷)每张合约都是代表10吨货物,并且生产成本、原料等因素导致这两个品种价格相关性是很强的。当价格差出现异常时,是可以进行对冲套利的。

那么本篇我们就使用Python语言,在FMZ量化上用很简单、简短的代码来实现一个rb和hc的跨品种对冲模型,可以用于回测或者实盘(实盘需要继续优化)。

策略逻辑

套利品种:热卷 (hc), 螺纹 (rb)
套利原理:价差定义:Price(hc) - Price(rb)

正套:价差大于阈值 A 时 , 做空热卷,做多螺纹
反套:价差小于阈值 B 时 , 做多热卷,做空螺纹

止盈:
正套;价差小于阈值 C 时,止盈。
反套;价差大于阈值 D 时,止盈。

止损:
正套;价差大于阈值 E时,止损。
反套;价差小于阈值 F时,止损。

策略代码实现

为了方便策略编写设计,策略使用了两个FMZ的模版类库:

这些模版类库在FMZ上都是开源的,可以直接在FMZ的策略广场复制完整的模版,获取到。然后在自己的策略编写设计页面的模版栏就可以看到这些复制过来的模版类库了,勾选就可以引用。

'''backtest
start: 2022-09-01 09:00:00
end: 2022-09-09 15:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
mode: 1
'''

p = ext.NewPositionManager()
def onTick():
    global maxDiff, minDiff
    # 获取合约A行情数据
    infoA = exchange.SetContractType(symbolA)
    tickA = exchange.GetTicker()
    recordsA = exchange.GetRecords()
    
    # 获取合约B行情数据
    infoB = exchange.SetContractType(symbolB)
    tickB = exchange.GetTicker()
    recordsB = exchange.GetRecords()
    
    if not tickA or not tickB or not recordsA or not recordsB:
        return
    
    # 分析持仓
    pos = exchange.GetPosition()
    if pos is None:
        return 
    longPosOfSymbolA = p.GetPosition(symbolA, PD_LONG)
    shortPosOfSymbolA = p.GetPosition(symbolA, PD_SHORT)
    longPosOfSymbolB = p.GetPosition(symbolB, PD_LONG)
    shortPosOfSymbolB = p.GetPosition(symbolB, PD_SHORT)
    
    # 计算价差
    diff = tickA["Last"] - tickB["Last"]
    # Log("diff:", diff) # 测试
    
    if not longPosOfSymbolA and not shortPosOfSymbolA and not longPosOfSymbolB and not shortPosOfSymbolB:
        if diff > maxDiff:
            # 空A合约,多B合约
            Log("空A合约:", symbolA, ",多B合约:", symbolB, ", diff:", diff, ", maxDiff:", maxDiff, "#FF0000")
            p.OpenShort(symbolA, 1)
            p.OpenLong(symbolB, 1)
        elif diff < minDiff:
            # 多A合约,空B合约
            Log("多A合约:", symbolA, ",空B合约:", symbolB, ", diff:", diff, ", minDiff:", minDiff, "#FF0000")
            p.OpenLong(symbolA, 1)
            p.OpenShort(symbolB, 1)
    
    if longPosOfSymbolA and shortPosOfSymbolB and not shortPosOfSymbolA and not longPosOfSymbolB:
        # 持有A多头、B空头
        if diff > (longPosOfSymbolA["Price"] - shortPosOfSymbolB["Price"]) + stopProfit:
            # 止盈
            Log("持有A多头、B空头,止盈。", "diff:", diff, "持有差价:", (longPosOfSymbolA["Price"] - shortPosOfSymbolB["Price"]))
            p.Cover(symbolA)
            p.Cover(symbolB)
        elif diff < (longPosOfSymbolA["Price"] - shortPosOfSymbolB["Price"]) - stopLoss:
            # 止损
            Log("持有A多头、B空头,止损。", "diff:", diff, "持有差价:", (longPosOfSymbolA["Price"] - shortPosOfSymbolB["Price"]))
            p.Cover(symbolA)
            p.Cover(symbolB)
    elif shortPosOfSymbolA and longPosOfSymbolB and not longPosOfSymbolA and not shortPosOfSymbolB:
        # 持有A空头、B多头
        if diff < (shortPosOfSymbolA["Price"] - longPosOfSymbolB["Price"]) - stopProfit:
            # 止盈
            Log("持有A空头、B多头,止盈。", "diff:", diff, "持有差价:", (shortPosOfSymbolA["Price"] - longPosOfSymbolB["Price"]))
            p.Cover(symbolA)
            p.Cover(symbolB)
        elif diff > (shortPosOfSymbolA["Price"] - longPosOfSymbolB["Price"]) + stopLoss:
            # 止损
            Log("持有A空头、B多头,止损。", "diff:", diff, "持有差价:", (shortPosOfSymbolA["Price"] - longPosOfSymbolB["Price"]))
            p.Cover(symbolA)
            p.Cover(symbolB)
    
    
    # 画图
    ext.PlotLine("差价", diff)

def main():
    while True:
        if exchange.IO("status"):
            onTick()
            LogStatus(_D(), "已连接")
        else:
            LogStatus(_D(), "未连接")
        Sleep(500)

策略参数:

回测测试

我们使用tick实盘级别回测。

由于实盘级别回测数据量很大,时间范围有限。并且策略参数对冲阈值触发的差价设置的很大,设置了100时才触发。所以只触发了2次对冲交易,并且成功止盈。跨品种对冲也不失为一种交易思路,主要目的是程序化监控差价,捕捉行情剧烈波动时的异常差价进行套利。具体效果好坏与差价趋势的判断有很大关系,需要长期观察市场行情,了解一定基本面信息,才能做到对差价变动趋势、回归胸有成竹。

策略地址:https://www.fmz.cn/strategy/373508
本代码仅仅为FMZ平台上学习的一个简单模型,有兴趣可以扩展优化,实盘慎用。

免责声明:信息仅供参考,不构成投资及交易建议。投资者据此操作,风险自担。
如果觉得文章对你有用,请随意赞赏收藏
相关推荐
相关下载
登录后评论
Copyright © 2019 宽客在线