套利与常用示例

套利是期货量化的高频需求,极智量化在这方面提供了灵活的支持:既兼容交易所标准套利合约,也能自由组合多腿自定义套利。本章把套利、止损止盈、参数优化这些实战常用模式一次讲清。

两种套利思路

类型做法关键点
交易所标准套利订阅极星 SPD 套利合约行情,对交易所标准套利合约下单无法直接取标准套利行情,须先订阅对应 SPD 行情驱动逻辑
自定义套利分别订阅每腿合约,自己算价差、自己决定两腿下单最灵活,可做跨期、跨品种、内外盘

交易所标准套利

标准套利要先订阅 SPD 套利合约行情作为触发源,再对交易所标准套利合约下单。以 TA107/TA109 套利为例:

import talib

g_params['p1'] = 5          # 短周期
g_params['p2'] = 15         # 长周期
g_params['dot'] = 1         # 突破点位

spd  = 'SPD|s|TA|107|109'           # 极星SPD套利合约(驱动行情)
code = 'ZCE|S|TA|107|109'           # 交易所标准套利合约(下单标的)

def initialize(context):
    SetBarInterval(spd, 'M', 1, 2000)    # 订阅策略触发行情
    SetBarInterval(code, 'M', 1, 2000)   # 必须订阅下单合约行情,否则下单失败

def handle_data(context):
    if context.contractNo() != spd:      # 只在SPD行情触发时执行
        return
    if CurrentBar() < g_params['p2']:
        return
    _close = Close(spd, 'M', 1)
    ma1 = talib.MA(_close, g_params['p1'])[-1]
    ma2 = talib.MA(_close, g_params['p2'])[-1]
    dot  = g_params['dot'] * PriceTick('ZCE|F|TA|107')
    if ma1 - ma2 > dot and BuyPosition(code) == 0:
        Buy(1, _close[-1], code)
    elif ma2 - ma1 > dot and SellPosition(code) == 0:
        SellShort(1, _close[-1], code)

注意两点:触发合约判断用 context.contractNo() != spd;下单合约的行情必须订阅,否则会下单失败。

自定义跨期套利

自定义套利最自由——订阅每一腿,自己构造价差序列,再对两腿分别下单。下面是一个简洁的双均线价差套利(TA105 与 TA109):

import talib
import numpy as np

code1 = "ZCE|F|TA|105"
code2 = "ZCE|F|TA|109"
p1, p2, dot, qty = 5, 20, 1, 1

spds = []                          # 全局价差序列

def initialize(context):
    SetBarInterval(code1, 'M', 1, 2000)
    SetBarInterval(code2, 'M', 1, 2000)
    SetOrderWay(2)

def handle_data(context):
    prc1 = Close(code1, 'M', 1)
    prc2 = Close(code2, 'M', 1)
    if len(prc1) == 0 or len(prc2) == 0:
        return

    global spds
    spd_c = prc1[-1] - prc2[-1]            # 当根价差
    if len(prc1) > len(spds):              # 新Bar:追加
        spds.append(spd_c)
    else:                                   # 同Bar:更新末尾
        spds[-1] = spd_c
    if len(spds) < p2:
        return

    sma1 = talib.MA(np.array(spds), p1)
    sma2 = talib.MA(np.array(spds), p2)
    tick = dot * PriceTick()

    if sma1[-1] > sma2[-1] + tick and MarketPosition(code1) <= 0:
        Buy(qty, prc1[-1], code1)
        SellShort(qty, prc2[-1], code2)     # 做强腿、做空弱腿
    elif sma1[-1] < sma2[-1] - tick and MarketPosition(code1) >= 0:
        SellShort(qty, prc1[-1], code1)
        Buy(qty, prc2[-1], code2)

    PlotNumeric("sma1", sma1[-1], 0x0000FF, False)
    PlotNumeric("sma2", sma2[-1], 0xFF0000, False)
    PlotNumeric("fit", NetProfit() - TradeCost(), RGB_Purple(), False, True)

价差序列的维护是一个通用技巧:用「新 Bar 追加、同 Bar 更新」的模式保持一根 Bar 一个值。把均线换成布林带(talib.BBANDS)就是布林带套利,换成唐奇安通道就是海龟式突破,思路完全一致。

止损止盈

极智量化支持三种内置止盈止损,在 initialize 里设置,触发时自动平仓:

函数含义
SetStopPoint(n)固定点止损:价格跌破开仓价 n×最小变动价位时平仓
SetWinPoint(n)固定点止盈:价格超过开仓价 n×最小变动价位时平仓
SetFloatStopPoint(start, back)浮动止损:盈利超过 start 点后启动,从最高点回撤 back 点时平仓
def initialize(context):
    SetBarInterval('ZCE|Z|SR|MAIN', 'M', 1, 500)
    SetStopPoint(10)            # 跌破 10 个最小变动价位止损
    SetWinPoint(20)             # 超过 20 个最小变动价位止盈
    SetFloatStopPoint(20, 10)   # 盈利 20 点启动,回撤 10 点平仓

所有点数都要乘以品种的最小变动价位。浮动止损能「让盈利奔跑」,多头止损价 = 启用后最高价 − 回撤价位,空头反之。

参数优化

g_params 字典定义可优化参数,运行后右键策略选「参数优化」,设置最小值/最大值/步长,平台会遍历所有参数组合回测并列出收益、胜率等指标:

g_params['fast'] = 12       # 快周期
g_params['slow'] = 26       # 慢周期
g_params['back'] = 9        # DEA 周期

def handle_data(context):
    if CurrentBar() < g_params['slow'] + g_params['back'] - 1:
        return
    diff, dea, macd = talib.MACD(Close(), g_params['fast'],
                                 g_params['slow'], g_params['back'])
    ...

两个注意点:g_params 的值只在约定函数内部才随优化值更新,函数外部的全局变量不会跟着变(需要时在 initialize 里把 g_params['x'] 赋给全局变量);新增 g_params 键后要重新添加策略,参数优化界面才能提取到新参数。

常用模式速查

  • 多合约:多次 SetBarInterval 订阅不同合约,最多 50 个;第一个为基准合约。
  • 多周期:同一合约订阅不同周期,Tick/秒/分钟/日均可,秒线用类型 'T' + 非零周期。
  • 主力换月SetTriggerType(7) 订阅换月事件,由你自己决定换月时的仓位处理。
  • 持仓同步:用 Buy/Sell 下单出现仓差时,界面点「同步持仓」一键矫正。

小结

标准套利订阅 SPD 行情、对标准套利合约下单;自定义套利自建价差序列、两腿分别下单;均线/布林/突破只是价差判据不同。止损止盈三件套按点数设置;参数优化用 g_params 并注意值只在约定函数内生效。到此,极智量化从环境、指标、下单到套利与优化已形成闭环——左侧导航可随时回查任一章节。