tradingSystem/QMT_SIDE_ACK_SEQ_PATCH.md

84 lines
3.8 KiB
Markdown
Raw Normal View History

2026-07-29 13:25:32 +08:00
# 给 QMT 侧:补 `ack_seq` 处理(协议 §4.5
## 现象
PMS 每 2 秒发一次 `ack_seq`QMT 侧回:
```json
{"instruction_id": null, "code": "BAD_PARAM", "reason": "unknown type ack_seq", "retryable": false}
```
定位到 `handlers.py``handle()`:类型分发链里有 `hello` / `ping` / `place_order` /
`cancel_order` / `query_positions` / `query_funds` / `query_orders`**唯独没有 `ack_seq`**
所以落到了最后一行的兜底:
```python
self._reject_raw(envelope, 'BAD_PARAM', f'unknown type {msg_type}', False)
```
对过一遍:我方下行 8 个类型,贵方实现了 7 个,只差这一个。
## 为什么会漏
多半是协议文档的锅,不是实现的锅。`QMT_WS_PROTOCOL.md` 的版本历史表里,
**V1.0 定稿那行排在 V0.9.2 上面**,而 `ack_seq` 恰恰是 V0.9.2 才补进来的
(「新增下行消息 ack_seq 累积确认§4.5。从上往下读到「V1.0 定稿」就停的话,
底下引入 `ack_seq` 的那行会被跳过去。PMS 侧会把这两行顺序修正,条款不动。
## 后果(已定位,非猜测)
不处理会形成自激循环:
```
PMS 发 ack_seq → QMT 回 reject → reject 自身带 seq → PMS 水位推进
→ 2 秒后 PMS 又要 ack → 再被 reject → ...
```
实测 2 秒一条,十几分钟烧掉 800 多个 seq。通道显示 ONLINE实际只在刷 reject。
更实质的影响在贵方§6.1 规定「QMT 收到 `ack_seq{seq: N}` 后可清理 `seq ≤ N` 的消息」。
收不到 ack**Redis 里的上行消息只涨不清**。联调期 Redis 不设过期(双方已确认),
这部分会一直堆着。
## 补法
`handlers.py``handle()` 里,在 `if msg_type == 'ping':` 附近加一个分支:
```python
if msg_type == 'ack_seq':
seq = int(payload.get('seq') or 0)
if seq > 0:
self.store.ack(seq) # 清理 seq <= N方法名按贵方 store 的实际接口来
return # 不需要回任何消息
```
三点提醒:
1. **`ack_seq` 不需要回消息。** 它是单向通知,回 `ack``pong` 都会让 PMS 侧多一条
无主上行。
2. **累积语义。** 收到 `{seq: 10450}` 表示 `seq ≤ 10450` 全部已落库,可一次性清理,
不是只清这一条。
3. **§6.1 的 7 天下限仍要守。** 「已确认的消息也至少保留 7 天」——防 PMS 侧库回滚后
无从追溯。所以是「可清理」不是「立即删」,按贵方存储策略取舍。
## PMS 侧已做的临时处理
PMS 已加自动降级:收到 reason 里含 `ack_seq` 的协议级 reject 就**停发 `ack_seq`**
打断循环。水位照常落库,重连补发靠 `hello.last_seq`§4.5 原话:「断线重连时以
`hello.last_seq` 为准,`ack_seq` 只用于让 QMT 及时释放存储」),**不丢成交**。
标志位每次重连重置——贵方补上之后PMS 重连即自动恢复发送,不需要通知我们改配置。
## 顺带确认的几件事
- **签名完全互通。** `crypto1.py``compact_payload_json` / `build_canonical` 与 PMS 侧
逐字一致,双向验签实测通过,这一层可以划掉了。
- **`new_nonce()` 已修。** 上一版是 `token_hex(8)`8 字节),现在是 `token_hex(16)`
符合 §2.2。
- **时间窗。** `handlers.py` 对我方每条消息做 ±30 秒检查(超了回 TS_SKEW。这是对的
但两机时钟漂开会让 `place_order` 直接被拒,现象是「下单没反应」,很难往时钟上想。
PMS 侧已把实测偏差显示出来,建议两边都确认 NTP 在跑。
- **`pong` 带 seq** 是符合 §5「所有上行消息带 seq」的实现没问题。只是按 §6.1 它也会
进 Redis 并在重连时补发——5 秒一个,一天 1.7 万条纯 `{}`。要不要给 `pong` 免掉 seq
是个可以聊的口径问题,不急。