前言
国内期货程序化执行层,很多人用天勤 TargetPosTask 做趋势调仓:信号算出目标净持仓后 set_target_volume(n),task 在每次 api.wait_update() 里对价报单;行情跳动时,task 会先 cancel_order 撤掉自己的在场委托,再按新价重报。有人嫌追价慢,在同一合约上又手写 insert_order 改价,或在 task 撤单过程中再撤一次,结果 get_position().pos 短时间反复横跳,和信号层记忆对不上。
天勤文档明确:同一合约不要混用 TargetPosTask 与 insert_order。下面说明委托 status、volume_left 状态机、安全撤单顺序,以及只依赖 task 时改价已内置在哪里。
一、Order 状态字段
| 字段 | 含义 |
|---|---|
status |
ALIVE 在途,FINISHED 结束 |
volume_left |
剩余未成交量 |
is_dead |
是否确定不会再成交 |
is_error |
是否错单 |
last_msg |
柜台说明 |
撤单应针对 status == "ALIVE" 且 volume_left > 0 的委托。
二、TargetPosTask 内置改价逻辑
target_pos_task.py 文档:task 在每次下单后会根据行情计算最新价格,价格变化时先撤由该程序发出的在场委托,再按新价重报。因此多数场景不需要手写 cancel_order;改 price="ACTIVE" 或自定义 price 函数即可。
混用风险:
- 你撤了 task 的单,下一帧 task 又报新单,逻辑难预测。
- 你
insert_order开仓,task 仍按旧 target 调仓,双倍持仓。 - 单例 task 不知道你手写单的存在,
pos与 target 长期偏离。
三、若坚持手写撤单
仅建议在紧急停机或 task 已停用后:
python
for oid, order in api.get_order().items():
if order.instrument_id in SYMBOL and order.status == "ALIVE":
api.cancel_order(oid)
while True:
api.wait_update()
if all(o.status == "FINISHED" for o in api.get_order().values()
if o.instrument_id in SYMBOL):
break
pos = api.get_position(SYMBOL).pos
# 再决定是否重建 TargetPosTask
撤单后必须多帧 wait_update 等到 FINISHED 或 volume_left==0,再读 pos。
四、部分成交后收尾
部分成交时 volume_left 大于 0。若策略放弃剩余意图,可 cancel_order 余单,并把 target 改为当前 pos,让 task 不再追剩余手数:
python
task.set_target_volume(api.get_position(SYMBOL).pos)
这比继续追价更符合「成交多少算多少」的风控。
五、InsertOrderTask 边界
InsertOrderTask 是 task 内部类,一般策略不直接实例化。若用 InsertOrderUntilAllTradedTask 等扩展,同样遵守勿与 TargetPosTask 混用同一合约。
六、价变撤单重报时序
TargetPosTask 在 ACTIVE 模式下价格跳动会撤旧单重报。若你在外层又 cancel_order,可能出现「双撤」后短暂无单。日志里同时记 task 侧与手工侧撤单事件,复盘才能对齐时间线。
七、紧急停机顺序
set_target_volume(pos)冻结目标- 撤所有 ALIVE
wait_update至 FINISHED- 再
set_target_volume(0)若需强平
跳步容易导致 task 又报新单。
八、模拟盘练撤单
在 TqSim 上挂 PASSIVE 远价单,练习 cancel_order 与读 volume_left 变化,熟悉 FINISHED 前后 pos 不变、仅委托消失的行为。
总结
撤单改价导致仓位乱,十有八九是 TargetPosTask 与手写 insert_order/cancel_order 在同一合约上抢控制权。天勤 task 已内置价变撤单重报,正常趋势策略应调 price 参数而不是外挂撤单。若紧急人工撤单,先停 task 意图(target 对齐 pos)、等委托 FINISHED、再决定是否重建 task,才能在程序化里保持仓位状态可解释。
FAQ
1)cancel_order 失败怎么办?
读 last_msg,可能已成交或已撤;以 get_order 为准。
2)task 能暂停吗?
没有 pause API;设 target=pos 等价暂停调仓。
3)多账户撤单要指定 account 吗?
TqMultiAccount 模式下 cancel_order 需对应 account 参数。
4)FAK 单还要撤吗?
FAK/IOC 类通常自动结束,少手动撤。
本文基于天勤 TqSdk 公开 API 整理,不构成投资建议。