期货量化主力换月程序怎么移仓:天勤 underlying_symbol 与任务切换

前言

国内期货是按月挂牌交易的:螺纹钢同时有 2505、2510、2511 等多个具体合约,其中成交量最大的那个月份叫主力合约。每隔一段时间,市场注意力会从近月移到远月,主力就会换月。对做程序化的人来说,换月那几天特别容易出事:研究时用的是主连曲线,实盘却要下在具体月份上;旧月份里还有持仓没平掉,程序已经对着新月份 set_target_volume(3),结果新旧两月同时持仓,保证金和风险度一起飙升。

天勤量化(TqSdk)是国内常用的 Python 期货量化框架。它的核心对象是 TqApi:你创建一次 TqApi,在里面订阅行情、查持仓、下单,整个程序靠反复调用 wait_update() 推进。主连合约在代码里常写作 KQ.m@SHFE.rb,它的行情对象上有一个字段 underlying_symbol,表示当前主力对应的具体可交易合约。换月程序化的关键,就是盯住这个字段何时变化,并据此完成移仓,而不是假装合约永远不变。

一、先弄清几个名词

名称 是什么 为什么会出现换月问题
具体月份合约 SHFE.rb2510,交易所真实可交易标的 到期、流动性转移,主力会换到别的月份
主连 KQ.m@ 把历史上各阶段主力拼接成连续 K 线,方便看长期趋势 研究好用,但不能直接当作单一合约的真实成交价
TqApi 天勤主连接,变量常写作 api 订阅、交易、查询都通过它,需 api.close() 释放
get_quote(代码) 取得某合约实时行情快照 主连 quote 上有 underlying_symbol
underlying_symbol 主连当前指向的具体合约代码 换月时这个字符串会变,程序若不处理就会对错合约
wait_update() 阻塞等待一批业务数据更新 不调用它,内存里的行情和持仓都是旧的
get_kline_serial 订阅 K 线表,表里有 datetime 信号若在具体月上算,换月后要改订阅的 symbol
TargetPosTask 天勤调仓工具,把净持仓调到目标手数 每个具体合约通常只能有一个 task 实例
set_target_volume(n) 设置目标净仓为 n 手,真正发单在后续 wait_update 换月要对旧月 set 0、对新月 set 目标
get_position 查柜台认可的持仓 移仓是否完成以 pos.pos 为准
pos.pos 净持仓,正为多、负为空 旧月不为 0 就不能算移仓完成

二、换月时程序里实际会发生什么

现象 原因 若不管会怎样
underlying_symbol 从 rb2505 变成 rb2510 交易所主力切换 仍对旧月下单,流动性差、滑点大或拒单
主连 K 线连续、具体月 K 线有断档 不同合约历史长度不同 信号 bar 与执行合约对不上
旧月 pos.pos 仍大于 0 移仓未完成 新旧两月叠仓,保证金占用翻倍

主连价格是拼接出来的研究序列,不能默认它等于某一个具体合约从上市到退市的全部真实成交路径。实盘执行必须跟踪具体合约,换月就是执行层重新对齐的过程。

三、underlying_symbol 怎么读、为何刚订阅可能为空

python 复制代码
from tqsdk import TqApi, TqAuth, TqSim
from tqsdk.lib import TargetPosTask

api = TqApi(TqSim(), auth=TqAuth("快期账户", "密码"))
cont = "KQ.m@SHFE.rb"
q_cont = api.get_quote(cont)

while True:
    api.wait_update()
    trade_sym = q_cont.underlying_symbol
    if trade_sym:
        break

说明:

  • KQ.m@SHFE.rbSHFE 是上期所,rb 是螺纹钢品种;KQ.m@ 表示主力连续。
  • get_quote 后各字段可能还是空的,必须 wait_update() 收到行情包才有值,这是天勤文档明确提醒过的。
  • trade_sym 形如 SHFE.rb2510,才是你应用 TargetPosTaskget_position 的执行合约。

策略里应维护变量 current_trade_sym,每个交易日开盘或每次主循环检查 trade_sym != current_trade_sym;若变化,进入移仓流程,不能静默改代码里的字符串却不平旧仓。

四、移仓流程:先平后开还是分批

两种常见写法,团队选一种写进策略说明书:

  1. 先平后开:在旧 symbol 上 set_target_volume(0),循环 wait_update 直到 get_position(旧).pos == 0,再对新 symbol 创建 TargetPosTaskset_target_volume(目标)
  2. 分批换月:在数个交易日内逐步把仓位从旧月迁到新月,降低单日冲击成本。

注意天勤约束:同一具体合约只能有一个 TargetPosTask(单例)。换月后对新 trade_sym 建 task;旧月 task 在平仓完成后不再设置新目标。若对同一 symbol 用不同的 priceoffset_priority 重复创建 task,会直接抛异常。

python 复制代码
def on_roll(old_sym, new_sym, target, tasks):
    if old_sym in tasks:
        tasks[old_sym].set_target_volume(0)
    # 此处应循环 wait_update,直到 get_position(old_sym).pos == 0
    if new_sym not in tasks:
        tasks[new_sym] = TargetPosTask(api, new_sym, price="ACTIVE")
    tasks[new_sym].set_target_volume(target)

price="ACTIVE" 表示对价下单(买用卖一、卖用买一),换月求成交时常用;若改用 PASSIVE 排队,在换月流动性混乱时可能久不成交。

五、K 线订阅要不要跟着切

  • 信号来自主连 K 线、执行用 underlying_symbol:主连序列换月时内部标的会变,通常不必重订主连 get_kline_serial;但要盯执行合约是否切换。
  • 信号来自具体月 K 线:换月后应改 get_kline_serial(new_sym, 周期秒数, data_length=...),并重新做指标就绪判断------新月份历史 K 线变短,均线可能出现 nan,在 nan 上不能交易。

日志建议记录:换月日期、旧 sym、新 sym、移仓前后 pos.pos、耗时,便于与期货公司账单核对。

六、模拟与回测注意

TqSim(天勤内置模拟账户)、TqKq(快期模拟)换月行为依赖行情服务,换月周应在模拟盘完整跑一遍移仓。回测若用主连,换月附近成交假设与具体月实盘会有偏差,样本外应用具体月再验证。

总结

主力换月那几天,程序要把 underlying_symbol 的变化当成和「信号触发」同级的重要事件:先发现切换,再平旧月、对新主力恢复目标仓,而不是继续对过期主力下单。天勤用主连做研究、用具体月做执行是常见分工,TqApiwait_update 驱动一切更新,TargetPosTask 负责把净仓推到目标。把移仓顺序、超时与日志写进配置并在模拟盘演练一遍,换月周就不容易变成持仓翻倍或流动性踩坑的突发事故。

FAQ

1)underlying_symbol 长时间为空?

继续 wait_update;检查是否休市、网络是否正常、主连代码是否写对。勿在空字符串上下单。

2)换月当天信号和旧仓方向相反?

先处理旧仓风险(风控优先),再跟新信号,避免两头加仓。

3)能否同时持有新旧两月做价差?

那是套利策略,不是移仓;两腿各自 TargetPosTask,比例单独管理。

4)个人投资者第一次写换月逻辑?

先用 TqSim 模拟,打印每次 underlying_symbol 变化,人工对照行情软件主力是否一致。

风险提示

以上内容用于移仓流程参考,不构成投资建议。

相关推荐
马士兵教育1 小时前
Java还有前景吗?Java+AI大模型学习路线及项目?
java·人工智能·python·学习·机器学习
KaMeidebaby2 小时前
卡梅德生物技术快报|纯化重组蛋白实操详解
人工智能·python·tcp/ip·算法·机器学习
Cloud_Shy6182 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第五章 Item 30 - 32)
开发语言·人工智能·笔记·python·学习方法
天佑木枫2 小时前
15天Python入门系列 · 序
开发语言·python
happylifetree2 小时前
Python017-第二章15.数据容器-dict常用操作
python
装不满的克莱因瓶2 小时前
了解 LangChain 中的 LLM 与 ChatModel 的差异
人工智能·python·ai·langchain·llm·agent·chatmodel
IT知识分享3 小时前
从零开发在线简繁转换工具:OpenCC 实战、避坑经验与方案选型
javascript·python
lunzi_08263 小时前
【学习笔记】《Python编程 从入门到实践》第8章:函数定义、参数传递与模块导入
笔记·python·学习
杨运交3 小时前
[030][Web模块]Spring Boot 验证与 OpenAPI 集成实战:从校验规则到文档生成
前端·spring boot·python