tradingSystem/QMT_SIDE_ACK_SEQ_PATCH.md

84 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 给 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
是个可以聊的口径问题,不急。