螺纹钢热轧卷板跨品种对冲模型

2022-10-31  本文已影响0人  bb0de211fbcc

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

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

策略逻辑

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

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

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

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

策略代码实现

'''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次对冲操作,并且成功平仓。跨品种对冲也不失为一种交易思路,主要目的是程序化监控差价,捕捉行情剧烈波动时的异常差价进行对冲。具体效果好坏与差价趋势的判断有很大关系,需要长期观察市场行情,了解一定基本面信息,才能做到对差价变动趋势、回归胸有成竹。

本代码仅仅为学习的一个简单模型,有兴趣可以扩展优化,实盘慎用。

上一篇下一篇

猜你喜欢

热点阅读