说明:本文包含 AI 创作内容,请自行判断是否适用。文中包含的代码片段,切勿直接使用,需要根据实际情况修改。
概述
很多新手写 QMT 策略时,下单用的是 passorderpassorder用法,但“怎么知道这单到底成了没”全靠下一次 handlebar 里去 get_trade_detail_data 轮询。轮询当然能用,但有延迟、又费资源,还容易在查不到委托的瞬间误判成“没下出去”导致重复下单。
更优雅的做法是用 QMT 提供的两个回调函数:order_callback(委托回调)和 deal_callback(成交回调)。本文讲清楚它们的触发时机、参数结构,以及怎么和 passorder 的 userOrderId 串起来做一个可靠的订单状态机。
两个回调的触发时机
| 回调 | 触发时机 | 典型用途 |
|---|---|---|
order_callback |
委托被柜台接收(已报单) | 确认“单子下出去了”,从待确认列表移除 |
deal_callback |
委托部分或全部成交 | 确认“真成交了”,更新持仓、发通知 |
一句话区分:order_callback 管的是“报单到达”,deal_callback 管的是“撮合成交”。一个委托可能触发一次 order_callback,但可能分多次 deal_callback(部分成交)。
函数签名
1 | def order_callback(ContextInfo, account, orderInfo): |
注意:这两个函数名是 QMT 约定的,写对名字就会自动被调用,不需要你在 init 里注册。
订单对象常用字段
orderInfo / dealInfo 是 QMT 传进来的对象,常用属性:
| 属性 | 含义 |
|---|---|
m_strInstrumentID |
证券代码(不带后缀) |
m_strExchangeID |
交易所,如 'SH'、'SZ' |
m_strRemark |
你下单时传的 userOrderId(备注) |
m_nVolume / m_nCanUseVolume |
委托/可用数量 |
m_dPrice |
委托/成交价格 |
其中 m_strRemark 最关键——它是你和 passorder 之间的“暗号”。下单时写进去,回调时读出来,就能精确定位是哪一笔单子回来了。
不同版本字段名可能略有差异,完整字段请参考 QMT 知识库文档,本文用的是社区最常见的字段名。
用 userOrderId 把下单和回调串起来
下面是一个最小可用的“下单 → 委托确认 → 成交确认”状态机:
1 | # -*- coding: utf-8 -*- |
为什么这样写更可靠
1. 不再误判“没下出去”
轮询派最大的坑是:下单后立刻去查 get_trade_detail_data('order'),可能那一瞬间委托还没回报,查不到,于是以为没下出去又下一笔——超单。用 order_callback 等回报到了再改状态,从根上避免。
2. 部分成交也能正确累计
一笔 1000 股的买单可能分 3 次 deal_callback(300 + 500 + 200)。上面代码用 o['filled'] += dealInfo.m_nVolume 累加,只有累计等于委托量时才标记 filled,符合真实撮合过程。
3. 失败委托可识别
如果一个 pending 状态的订单长时间没有 order_callback,基本可以判定是废单(价格不合规、数量不对、柜台风控等)。可以用一个定时任务扫描超时的 pending 订单,触发告警:
1 | def init(C): |
关于
run_time定时任务的用法,参考 每天代码重置与定时任务设置。
配合通知推送到手机
成交回调是发通知的最佳时机——不是“下单了”就通知,而是“真成交了”才通知,避免被一堆废单打扰。把 deal_callback 里的 send_notify 接上邮件/微信推送即可,具体实现见 QMT 与手机通信 - 邮件推送实现方法 或 策略消息推送到微信的几种方案。
注意事项
- 回调里不要做重活:回调在 QMT 主线程触发,里面不要写耗时 IO(比如同步发邮件阻塞几秒),否则会拖慢整个行情/交易处理。需要时把消息丢到一个队列,由定时任务慢慢发。
- 回调里不要直接
passorder:在deal_callback里立刻根据成交结果反手下另一笔是常见需求,但要确认账户状态、行情就绪,且做好防重入,否则容易连环下单。 - 字段名以实测为准:不同券商版本的 QMT,
orderInfo字段名可能有细微差别,第一次用建议先print(dir(orderInfo))看一下实际属性。 - 回测里回调行为不同:回测中
deal_callback通常按 K 线撮合触发,频率和实盘完全不同,详见 QMT 回测与实盘的关键差异。 - order_callback和deal_callback中可能存在时间延迟,正常情况下是很快回报,但是有时候券商服务器可能是几个小时候才能 callback,所以建议自己增加判断是否真正下单成交,当然这种情况极少发生。
- 当系统断网重连之后,服务器可能会把当天的所有单子全部给你callback一遍,所以不能完全相信 callback 的准确性,需要自己增加判断是否真正下单成交。通常是需要自己建立一个小型数据库,记录下单状态,等成交回调来更新。如果 callback 中出现的单子在数据库里面已经显示完成状态,那么可能这个 callback 就是券商服务器重复推送了。
总结
order_callback= 报单到达,deal_callback= 撮合成交。- 用
passorder的userOrderId(m_strRemark)做暗号,把下单和回调串成一个订单状态机。 - 状态机里区分
pending / ordered / filled / rejected,配合超时扫描,就能解决实盘最头疼的“重复下单”和“废单识别”问题。 - 回调里保持轻量,重活丢给定时任务,通知只在真正成交时发。
把这套机制跑通,你的实盘策略才谈得上“可靠”二字。
说明:本文包含 AI 创作内容,请自行判断是否适用。文中包含的代码片段,切勿直接使用,需要根据实际情况修改。