TargetPosTask 适合把“这个合约最终应持有多少净仓”交给工具执行。正数表示目标多头,负数表示目标空头,零表示目标空仓。它会根据当前持仓与目标之间的差额管理调仓,但并不会在set_target_volume调用当下同步完成;下单、撤单和价格更新都依赖后续持续的wait_update。
最小用法是设置目标,不是手写每笔订单
下面使用本地模拟账户,把一个具体月份合约调整到一手多头。代码用于理解机制,运行前仍需核验合约、模拟资金和市场状态。
import os from tqsdk import TqApi, TqAuth, TqSim, TargetPosTask symbol = "SHFE.rb2610" sim = TqSim(init_balance=100000) api = TqApi( sim, auth=TqAuth(os.environ["TQ_USER"], os.environ["TQ_PASSWORD"]), ) position = sim.get_position(symbol) target = TargetPosTask(api, symbol, price="ACTIVE") target.set_target_volume(1) try: while True: api.wait_update() if api.is_changing(position): print("当前净持仓:", position.pos) if position.pos == 1: break finally: api.close()set_target_volume(1)表达的是目标状态,不是“再买一手”。若当前已经持有一手多头,差额为零;若当前是一手空头,调仓过程需要从负一移动到正一。把目标持仓与增量手数混淆,会让策略方向反复出错。
默认的ACTIVE使用对价方式调整,买入参考卖一,卖出参考买一。盘口价格变化时,任务可能撤回自己在场的委托并按新价格重新下单。即使使用对价,也不能保证真实市场立即成交。
wait_update 是任务真正工作的地方
TargetPosTask 在设置目标时不直接下单或撤单。后续每次wait_update才给它机会根据行情、持仓和委托状态继续工作。因此,设置目标后立即关闭 API,通常得不到预期调仓结果。
程序还要决定等待到什么程度。只看持仓达到目标,可能仍有任务相关状态尚未收尾;只看函数调用成功,更不能说明成交完成。业务日志应记录目标值、目标变更时间、当前持仓和相关成交,方便解释一次调仓经历了什么。
连续信号可以重复调用set_target_volume更新目标,但需要避免把每个 Tick 的相同信号都写成新指令。先比较新目标与当前策略目标是否不同,真正变化时再提交,日志也会更干净。
目标变化过快时,执行可能一直追赶最新目标。策略应定义最小决策周期或信号确认规则,并记录哪些目标被后续目标替换。工具可以执行目标,却不会判断目标频繁变化是否合理。
到达目标也应按账户事实确认。净仓等于目标是核心条件,但还要检查是否存在任务发出的活动委托,以及成交记录是否完整。否则在极短的状态窗口里看到仓位相等,就提前结束程序,后续订单仍可能改变结果。
同一合约不要混用两套下单控制
使用 TargetPosTask 管理某合约时,不应再对同一合约同时调用insert_order手工下单。两套逻辑分别观察持仓并创建订单,可能互相撤单、重复调仓或产生错误结果。
同一个账户下,同一合约任何时刻只能有一个 TargetPosTask 实例。构造参数需要变化时,先取消原任务,等待它处理未成交委托,再创建新实例。不能在旧任务仍活动时直接叠加另一个不同价格方式的任务。
账户还有人工交易或其他策略时,默认按整个账户该合约净持仓调节可能超出当前策略的控制范围。部署前要确认仓位归属,必要时使用独立账户或更明确的交易隔离,不能让目标任务误处理其他来源的仓位。
ACTIVE、PASSIVE 与自定义价格怎样选
ACTIVE使用对价,通常更重视成交机会;PASSIVE使用排队价,买入参考买一、卖出参考卖一,可能产生更多撤单。两者只是执行方式,不改变策略应该持有多少仓位。
也可以提供价格函数,但函数必须在每次调用时返回有效价格。自定义价格涉及最小变动价位、涨跌停、盘口空值和异常回退,复杂度明显上升。若只是刚开始验证目标仓位,不要为了“更聪明的价格”把执行规则写得无法解释。
价格方式应在模拟环境中单独比较成交速度、撤单数量和偏离情况。不能只看最终是否到达目标,因为两种方式在过程风险和交易成本上可能不同。
哪些场景不适合只用目标持仓
若策略需要精确管理每笔订单的价格、有效期、部分成交处理和排队逻辑,直接委托管理通常更合适。TargetPosTask 的优势是把净仓目标转成调仓动作,不是替代所有微观执行需求。
若规则同时管理多账户,创建任务时需要明确账户实例。把目标送到错误账户是严重业务错误,不能通过后续持仓检查轻易弥补。日志应同时记录账户标识、合约和目标。
若使用大单拆分,最小与最大每笔手数必须一起配置,并满足有效关系。拆分会改变委托数量和执行过程,需要额外检查剩余目标与异常恢复;小规模学习代码没有必要提前加入。
主连与指数合约也不适合作为目标持仓的执行对象。研究信号要先映射到具体可交易合约,处理换月后再创建对应任务。
目标仓位工具同样不会替你做风险预算。set_target_volume(50)在语法上可能成立,却不说明账户资金、品种限制和策略风险允许五十手。目标进入任务前,应由独立风险检查确认手数、账户和交易时段。
当盘口缺失、合约不可交易或账户状态异常时,价格计算与调仓可能无法正常推进。程序要把这类状态视为停止新增风险的原因,并留下当前目标和账户状态,不能用任意价格回退来强行成交。
取消与退出要完整处理
调用任务的cancel会请求撤销它已经发出但尚未成交的委托,并让该实例停止继续接受目标。撤销动作仍需事件循环完成。取消后若要新建任务,应先等待旧任务结束,重新读取持仓与成交,再计算新的目标。
程序退出前要明确是保留仓位、调整到零,还是只停止任务并撤销未成交委托。三者含义不同。不能简单关闭进程,期待任务自动把账户恢复到某个状态。
重启后也不应照搬上次保存的目标直接执行。先读取账户当前持仓和活动委托,确认旧任务是否留下未决状态,再根据最新信号决定目标。
目标持仓清单
- 把目标值理解为最终净仓,而不是本次增减手数。
- 设置目标后持续
wait_update,并观察持仓、订单和成交过程。 - 同账户同合约只保留一个 TargetPosTask,不与手工下单混用。
- 价格方式、账户实例和具体月份合约在创建前明确核对。
- 取消、退出和重启都先处理未成交委托,再重新计算目标。
TargetPosTask 能减少开平与调仓样板代码,但不会替代策略规则和风险判断。最稳妥的使用方式,是让策略只负责给出清楚目标,让任务负责执行,同时用账户事实验证每次目标是否真的完成。