期货量化目标仓和净持仓对不齐:天勤 TargetPosTask 与 pos 偏差排查

前言

国内期货趋势量化程序的典型链路是:天勤 TqApi 订阅螺纹钢 5 分钟 K 线,双均线算出「目标净持仓 5 手」这一交易信号,执行层调用 TargetPosTask.set_target_volume(5),task 在后续每次 api.wait_update() 里向期货公司发单、撤单、对价改价,柜台回报刷新到 get_position("SHFE.rb2510").pos(净持仓手数,正为多、负为空)。

排查实盘时,日志连续三天写着 target=5,但 pos 一直是 4 或 6,差一两手对不齐。第一反应往往是「均线算错」,更常见却是:部分成交、场上还有 status=="ALIVE" 的在途单、同一合约重复建了 task、或手写 insert_order 与 task 抢仓位。set_target_volume 当下并不成交,target 与 pos 短期不一致可以是正常现象。下面按天勤单例约束、调仓时序和排查顺序,说明怎么区分正常过渡与真故障。

一、先弄清几个名词

名称 是什么 偏差排查里怎么用
set_target_volume(n) 告诉 task 目标净持仓手数 只改意图,不立刻成交
get_position(symbol).pos 柜台确认的净持仓 真相,正负表示多空
TargetPosTask 天勤自动调仓类 在 wait_update 里执行
wait_update() 收行情与交易回报 不调就不会推进 task
get_order() 当前委托字典 看在途 ALIVE 单
volume_left 委托剩余未成交量 部分成交时大于 0
status 委托状态 ALIVE/FINISHED 是否在途
min_volume / max_volume 大单拆分参数 分批导致短期对不齐
offset_priority 开平顺序 平今失败时 pos 卡住

二、为什么 target 和 pos 可以短期不一致

TargetPosTask 文档写得很清楚:set_target_volume 当下不下单,下单撤单发生在之后的 wait_update()。因此下列情况属于正常现象:

  • 刚调用 set_target_volume(5),下一行就读 pos,仍是旧值。
  • 单子已报入交易所,部分成交,pos 在 4 与 5 之间。
  • 启用了 min_volume/max_volume 拆分,多帧 wait_update 才凑满目标。
  • 对价 price="ACTIVE" 追价时,旧单撤完新单未成交,中间有空窗。

需要告警的是:连续多个交易时段、无 ALIVE 单、无拒单,而 pos 仍与 target 差值不变。

三、天勤单例约束:重复建 task 会埋雷

target_pos_task.pyTargetPosTask 用单例元类:同一账户同一 symbol 只能有一个 task 实例。若用不同 priceoffset_prioritymin_volume 再建一次,会直接抛异常。

更隐蔽的是:同一合约既用 TargetPosTask,又手写 insert_order。文档明确禁止混用,否则 task 内部状态与柜台持仓错位,表现为 target 已改但 pos 长期不对,或莫名多出一笔委托。

排查时全局搜索该 symbol 是否只有一处 TargetPosTask,以及是否还有 insert_order 调用。

四、推荐排查顺序

  1. api.wait_update() 至少跑几帧,确认不是读太早。
  2. pos = api.get_position(symbol).pos,记 target(自己维护或 task 日志)。
  3. 遍历 get_order(),筛 symbol 相同且 status == "ALIVE" 的项,看 volume_leftdirection
  4. 若有拒单,读 last_msg;开平、资金类错误会导致 task 停在某一手数。
  5. 查是否拆分模式:看创建 task 时的 max_volume
  6. 多账户模式是否漏传 account 参数,导致读到别的账户持仓。

可落地的日志字段建议每次调仓记:bar_datetimetargetposalive_volume(在途剩余量之和)、delta=target-pos

python 复制代码
def log_pos_gap(api, symbol, target, logger):
    api.wait_update()
    pos = api.get_position(symbol).pos
    alive = sum(
        o.volume_left for o in api.get_order().values()
        if o.instrument_id in symbol and o.status == "ALIVE"
    )
    logger.info(
        "pos_gap symbol=%s target=%s pos=%s alive_left=%s",
        symbol, target, pos, alive,
    )

五、纠偏与恢复

确认无在途单且 pos 仍不对时:

  • get_position 为准重置本地 state,再 set_target_volume 到真实目标。
  • 若怀疑 task 内部错乱,进程级重启:停机、对账、重建 TargetPosTask(改创建参数必须重启,见发版边界)。
  • 不要连续狂调 set_target_volume 试图「催成交」,容易触发报单频率规则。

六、典型 last_msg 与偏差共存

last_msg 关键词 常见后果
资金不足 target 不变,pos 落后
非交易时段 夜盘衔接误发单
平今不足 空头减仓卡住
超过最大委托量 部分成交

拒单后若不读 last_msg,会误以为 task 还在正常追价。

七、模拟与实盘偏差对比

TqSim 往往更快对齐;实盘 ACTIVE 追价在波动大时可能反复撤单重报,gap 持续更久。应用同一套 log_pos_gap 在两种环境各跑一天,建立「正常 gap 持续时间」基线。

总结

期货量化里目标仓与净持仓短期不一致,多数是天勤 TargetPosTask 的正常过渡:调仓在 wait_update 里分步完成,部分成交和拆单都会拉长对齐时间。持续对不齐时,按 pos、在途 ALIVE 单、last_msg、是否混用 insert_order、是否重复建 task 这条链排查;日志里同时记 target 与 pos,比单看信号可靠得多。在 TqSimTqKq 上把偏差场景跑一遍,再挂实盘,能少踩很多「以为程序坏了其实是成交慢」的坑。

FAQ

1)差 1 手要不要强行补单?

先看在途单和部分成交;无在途且拒单已排除,再 set_target_volume 一次即可,避免与 task 内部循环打架。

2)反手时偏差更大正常吗?

反手要先平后开,中间帧 pos 可能经过 0 或反向,属于正常,用日志看全过程。

3)模拟盘会对得更齐吗?

TqSim 成交模型更理想,实盘偏差更大;模拟对齐不能代表实盘一定对齐。

4)能否不用 TargetPosTask?

可以全程 insert_order,但要自己管开平和在途单,工作量更大。


本文基于天勤 TqSdk 公开 API 与源码整理,不构成投资建议。实盘前请在仿真环境验证。

相关推荐
2601_956319881 小时前
期货夜盘无人值守监控什么:断线、无成交与拒单信号
python·区块链
科技林总2 小时前
解决vllm服务漏扫问题
python·安全
2601_955505252 小时前
自然人身份确权可信基础设施赋能 DID 身份合规
运维·金融·区块链·健康医疗·智能硬件·教育电商·政务
财经资讯数据_灵砚智能3 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年6月10日
大数据·人工智能·python·ai·信息可视化·自然语言处理·灵砚智能
namexingyun3 小时前
拆解Fable 5三重安全护栏:模型路由、蒸馏防护与生物安全分类器的技术原理 - 微元算力(weytoken)
java·人工智能·python·安全·架构·ai编程
chenment3 小时前
别再为每个模型单独写一套队列了:用 200 行代码封装多模态统一调用层
人工智能·python·产品
啊森要自信3 小时前
【GUI自动化测试】控件、鼠标键盘操作与多场景自动化
c语言·开发语言·python·adb·ipython
YJlio3 小时前
《Sysinternals实战指南》16.5 Ctrl2Cap 工具详解:把 Caps Lock 变成 Ctrl 的键盘改造与回退方法
linux·运维·服务器·网络·python·学习·计算机外设
某林2123 小时前
从底层硬件死锁到 QoS 通信底层的全链路复盘
python·ros2·qos