螺纹钢热轧卷板跨品种对冲模型
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次对冲操作,并且成功平仓。跨品种对冲也不失为一种交易思路,主要目的是程序化监控差价,捕捉行情剧烈波动时的异常差价进行对冲。具体效果好坏与差价趋势的判断有很大关系,需要长期观察市场行情,了解一定基本面信息,才能做到对差价变动趋势、回归胸有成竹。
本代码仅仅为学习的一个简单模型,有兴趣可以扩展优化,实盘慎用。