chore: #7 kline:tick 微回补文档同步 + ws.ts 显式判断

- ws.ts: !msg.kline.final → msg.kline.final === false 更清晰
- websocket-realtime.md: 事件表/启动流程/角色表补上 kline:tick,#7 标记已修复
- tech-debt.md: #10 kline:tick 标记已完成
This commit is contained in:
Rekey
2026-06-18 23:23:50 +08:00
parent 6374159e53
commit ab3904f627
3 changed files with 10 additions and 8 deletions
+1 -1
View File
@@ -87,7 +87,7 @@ export class BinanceWsClient extends BaseWsClient {
private handleKline(msg: WsMessageKlineFormatted): void {
const kline = this.toKline(msg);
if (!msg.kline.final) {
if (msg.kline.final === false) {
bus.emit("kline:tick", kline);
return;
}
+4 -4
View File
@@ -131,10 +131,10 @@
- 问题:同时承担 REST client registry7-30 行)和 WS 订阅管理(74-121 行),两类逻辑耦合
- 修复:拆分为 `rest-registry.ts`REST client 注册 + fetchKlines+ `ws-manager.ts`WS 实例池 + watchKline/watchKlines/unWatchKline),`index.ts` 降级为纯 re-export hub,对外 API 不变
- [ ] **10. `kline:tick` 微回补未实现**(已知问题 #7
- 位置:`data/exchanges/binance/ws.ts:62-63` + `data/run/start.ts`
- 问题:WS 订阅后的衔接窗口期(回补完成 → subscribe 之间若跨分钟边界)可能导致最多 1 分钟数据缺口。文档方案已明确,待实现
- 建议`ws.ts` 中 `final === false` 时 emit `kline:tick``start.ts` 首次 tick 触发微回补
- [x] **10. `kline:tick` 微回补**(已知问题 #7
- 位置:`data/exchanges/binance/ws.ts` + `data/run/start.ts` + `data/utils/bus.ts`
- 问题:WS 订阅后的衔接窗口期(回补完成 → subscribe 之间若跨分钟边界)可能导致最多 1 分钟数据缺口
- 修复`ws.ts` 中 `final === false` 时 emit `kline:tick``start.ts` 首次 tick 触发 `backfillKline` 微回补,`tickedSymbols` 去重仅执行一次。commit `6374159`
- [x] **11. `fetchMarkets()` 返回空数组**
- 位置:`data/exchanges/binance/rest.ts:133,194`
+5 -3
View File
@@ -78,6 +78,7 @@ start.ts 启动
│ ├─ pair:ready → watchKline({exchange, type, symbol})
│ ├─ pair:failed → 记日志
│ ├─ backfill:complete → 记日志
│ ├─ kline:tick → 首次 tick 触发 backfillKline 微回补(#7
│ ├─ kline:update → upsertOrUpdateKlines → updatePairWsTime → emit("kline:saved")
│ └─ kline:saved → checkAndRefresh → emit("aggregate:refreshed")
@@ -244,6 +245,7 @@ run/start.ts 启动
│ ├─ pair:ready → watchKline({exchange, type, symbol})
│ ├─ pair:failed → 记日志 + 计数
│ ├─ backfill:complete → 记日志
│ ├─ kline:tick → 首次 tick 触发 backfillKline 微回补(#7
│ ├─ kline:update → upsertOrUpdateKlines → updatePairWsTime → emit("kline:saved")
│ └─ kline:saved → checkAndRefresh → emit("aggregate:refreshed")
@@ -279,7 +281,7 @@ run/start.ts 启动
| 模块 | 角色 | 监听 bus 事件 |
|------|------|------|
| `run/start.ts` | 编排入口:注册所有监听、桥接 service、调起回补 | `pair:ready` `pair:failed` `backfill:complete` `kline:update` `kline:saved` `ws:connected` `ws:disconnected` `ws:stale` |
| `run/start.ts` | 编排入口:注册所有监听、桥接 service、调起回补 | `pair:ready` `pair:failed` `backfill:complete` `kline:tick` `kline:update` `kline:saved` `ws:connected` `ws:disconnected` `ws:stale` |
| `exchanges/binance/ws.ts` | WS 客户端:订阅管理 + 标准化 + emit(不监听 bus | — |
| `service/kline.ts` | 数据写入:导出 `upsertOrUpdateKlines`(被动调用) | — |
| `service/pair.ts` | 时间标记:导出 `updatePairWsTime`(被动调用) | — |
@@ -386,7 +388,7 @@ start.ts 在正常运行时持续推进 last_backfill_timeexchange.ts 再次
| `pair:failed` | 回补模块 | start.ts | `{symbol, type, exchange, error}` |
| `backfill:complete` | 回补模块 | start.ts | `{status: 'done'\|'error'}` |
| `kline:update` | exchanges/ws.ts | start.ts | `Kline`(已闭合) |
| `kline:tick` | exchanges/ws.ts | start.ts | `Kline`(未闭合,触发衔接微回补 #7**⏸️ 暂缓:事件未定义,ws.ts 不 emit** |
| `kline:tick` | exchanges/ws.ts | start.ts | `Kline`(未闭合,触发衔接微回补 #7|
| `kline:saved` | start.ts | start.ts | `Kline` |
| `aggregate:refreshed` | start.ts | 策略引擎 | `Kline` |
| `ws:connected` | exchanges/ws.ts | start.ts | — |
@@ -488,4 +490,4 @@ data/
| 4 | WS 端 `takerBuyBaseVol` / `takerBuyQuoteVol` 硬编码为 `"0"` | `ws.ts:76-77` 两个字段写死为 `"0"`。已改为 `msg.kline.volumeActive` / `msg.kline.quoteVolumeActive` | ✅ 已修复 |
| 5 | 回补失败后 `break` 静默丢弃剩余 pair | `backfill.ts:84` 任一 pair 失败 `break`。**设计决策**:失败属不可恢复错误(SDK 僵死不响应 timeout),退出进程由外部重启,与第六章策略一致。**修复**:`run/start.ts``backfill:complete` 监听到 `status === 'error'``process.exit(1)` | ✅ 已修复 |
| 6 | 未来 `watchKline` 异步化的 race condition 隐患 | `start.ts``watchKline` 为同步调用,当前无问题。异步化后回补→WS 订阅的时间差可能导致数据缺口。**已明确**:此问题实质是衔接窗口问题,由 #7 的首次微回补方案覆盖 | ✅ → #7 |
| 7 | 回补→WS 衔接可能存在数据缺口 | 回补与 `subscribe` 之间若跨过分钟边界,该分钟内已闭合的 K 线不会被 WS 推送(WS 只推当前运行中的 K 线)。**决策**:数据完整性优先。每个交易对首次收到 `kline:tick` 时,即刻强制执行一次微回补(REST `fetchKlines``last_backfill_time` 到该 tick 的 `openTime`),无需等 1m K 线闭合。`kline:tick` 在 WS 订阅后数秒内即可到达,将衔接窗口从最长 1 分钟压缩到秒级。仅触发一次,后续 tick 忽略 | ⏸️ |
| 7 | 回补→WS 衔接可能存在数据缺口 | 回补与 `subscribe` 之间若跨过分钟边界,该分钟内已闭合的 K 线不会被 WS 推送(WS 只推当前运行中的 K 线)。**决策**:数据完整性优先。每个交易对首次收到 `kline:tick` 时,即刻强制执行一次微回补(调用 `backfillKline``last_backfill_time` 补齐至上一闭合分钟),无需等 1m K 线闭合。`kline:tick` 在 WS 订阅后数秒内即可到达,将衔接窗口从最长 1 分钟压缩到秒级。仅触发一次,后续 tick 忽略。实现于 commit `6374159` | ✅ 已修复 |