Python 写期货自动交易:行情下单与成交回报怎么组织

前言

我接触过很多刚写期货程序化的同事,行情能打印出来,一到下单和成交回报就各写各的:有的在循环里直接 insert_order,有的在回调里改全局变量,跑一晚上对不上账。其实不必一开始就搭微服务,关键是把 数据订阅、事件驱动、交易执行、状态核对 四层分清,让同一套骨架能从模拟走到实盘。

天勤 TqSdk 把行情、账户、委托、成交都挂在同一个 TqApi 上,用 wait_update 推进;下面按这个模型说明模块怎么拆、各层职责是什么,并给出最小闭环示例。策略逻辑可以换成你自己的,但组织方式建议先固定。

一、四层结构怎么记

层级 职责 天勤里常见入口
数据层 订阅行情、K 线、账户截面 get_quoteget_kline_serialget_accountget_position
事件层 判断本次更新是否值得处理 wait_updateis_changing
执行层 把信号变成报单或目标仓 insert_orderTargetPosTask.set_target_volume
核对层 委托、成交、持仓是否一致 get_orderget_trade、position 字段

新手常把执行层和核对层混在一起:下单后不跟踪 order.status,成交了也不读 get_trade,只靠"我以为成交了"推进策略,实盘很快失控。

二、数据层:先订再算

创建 TqApi 时选定交易单元(本地调试可用 TqSim,团队模拟常用 TqKq,实盘用 TqAccount)。随后一次性订阅本策略需要的对象:

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

api = TqApi(TqSim(), auth=TqAuth("快期账户", "密码"))
symbol = "SHFE.rb2510"
quote = api.get_quote(symbol)
kl = api.get_kline_serial(symbol, 60, data_length=200)
pos = api.get_position(symbol)
acc = api.get_account()

get_kline_serialdata_length 要大于指标周期,否则均线等指标前面全是 nan。行情对象在首次 wait_update 之前可能为空,文档也提醒过:刚订阅后 quote.datetime 可能还是空字符串。

三、事件层:用 wait_update 当心跳

wait_update 是天勤策略的主驱动:阻塞等待业务数据更新,同时把之前发出的订阅、报单真正发到网络,并让 TargetPosTask 等后台任务有机会下单。官方说明里写得很清楚------不调 wait_update,很多指令不会真正出去

python 复制代码
while True:
    api.wait_update()
    # 下面只在"关心的字段变了"时进逻辑

主循环里避免长时间 sleep、大段同步计算或阻塞 IO;这些都会推迟下一次 wait_update,行情和回报都会变慢。

四、执行层:手写报单 vs 目标持仓

入门理解链路insert_order:方向、开平、限价一目了然,适合学拒单和挂单规则。

信号驱动调仓TargetPosTask:策略只维护"目标净仓几手",拆单、撤单改价由 task 在后续每次 wait_update 时处理。注意文档约束:set_target_volume 之后必须继续 wait_update;同一合约不要和 insert_order 混用。

python 复制代码
from tqsdk.lib import TargetPosTask

task = TargetPosTask(api, symbol)
while True:
    api.wait_update()
    if api.is_changing(kl.iloc[-1], "datetime"):
        # 此处算信号,示例:目标多头 1 手
        task.set_target_volume(1)

五、核对层:成交回报从哪来

天勤没有单独的"回调函数列表",回报体现在数据截面更新上:

  • 委托:get_order() 或指定 order_id,看 statusvolume_left
  • 成交:get_trade()
  • 持仓:get_position(symbol)pos_longpos_short

wait_update 返回后,用 is_changing 过滤订单、成交、持仓字段,再写结构化日志。模拟盘还可对照 TqSimtrade_log 做二次校验。

六、模块落地到文件时的建议

单文件 demo 可以全写在一个 while True 里;策略变复杂后建议拆成:

  1. config:合约、周期、账户构造
  2. data:订阅与指标计算(纯函数,不直接下单)
  3. signal:输入 K 线/行情,输出目标方向或目标仓
  4. execution:只负责 TargetPosTaskinsert_order
  5. reconcile:每根 K 线或每分钟对 order/trade/position 做一次快照

这样换模拟、换实盘时,通常只改 TqApi 构造行和环境变量,信号与执行接口不变。

总结

Python 期货自动交易可按 数据订阅 → wait_update 事件驱动 → 执行(insert_order 或 TargetPosTask)→ get_order/get_trade/position 核对 四层组织。天勤把行情、账户、委托、成交放在同一 TqApi 截面里,避免自己维护多套 CTP 回调状态机。

落地时先订合约与 K 线,主循环里短逻辑 + 字段级 is_changing;执行层选手写报单或目标持仓二选一;核对层用订单、成交、持仓字段写日志,模拟盘可对照 trade_log。策略变复杂后再拆 config、signal、execution、reconcile 模块,换环境只改账户构造。

FAQ

1)必须先有行情才能下单吗?

实盘和模拟都依赖合约信息(最小变动价位、交易状态等)。应先 wait_update 收到有效 quote 再报单,否则容易拒单或价格无效。

2)TargetPosTask 和 insert_order 能一起用吗?

官方明确不建议同一合约同时使用,否则 task 与手写报单会冲突。

3)多合约怎么组织?

每个合约一个 TargetPosTask 实例(同一账户同一合约单例);信号层为每个 symbol 维护独立目标仓,不要共用一个全局"方向变量"。

4)回报要不要单独线程收?

天勤模型下用 wait_update 统一收包即可;再开线程抢 CTP 回调容易和 API 内部状态打架。

风险提示

本文讨论程序结构与技术实现,不构成投资建议。实盘前请在模拟环境充分验证。

相关推荐
倾一生爱恋换一世纯真1 小时前
接口自动化测试框架搭建流程
python
TE-茶叶蛋1 小时前
Next.js中App Router 全部特殊文件一览
开发语言·javascript·网络
红藕香残玉簟秋1 小时前
【Rust学习】windows安装rust
开发语言·学习·rust
abcy0712132 小时前
python flask app.py里的接口放在别的目录下图文教程
python
弹简特2 小时前
【零基础学Python】08-Python面向对象之封装、多态和函数进阶
开发语言·python
人道领域2 小时前
一篇文章解决Codex的安装,实操一遍过
java·开发语言·codex
thisiszdy2 小时前
<C++> 智能指针
开发语言·c++
fox_lht2 小时前
第十四章 一个输入和输出项目:构建一个命令行程序
开发语言·后端·rust
专注VB编程开发20年2 小时前
工控上位机开发为什么固死.net 4.5.2sdk?适配win7
python·信息可视化·c#