From d55877e8c7050db7a9d938b6e500974be6c743f8 Mon Sep 17 00:00:00 2001 From: dongzp <975303544@qq.com> Date: Wed, 22 Jul 2026 09:51:44 +0800 Subject: [PATCH] docs: add Baidu quote WebSocket real-time design spec Co-authored-by: Cursor --- .../specs/2026-07-22-baidu-quote-ws-design.md | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-22-baidu-quote-ws-design.md diff --git a/docs/superpowers/specs/2026-07-22-baidu-quote-ws-design.md b/docs/superpowers/specs/2026-07-22-baidu-quote-ws-design.md new file mode 100644 index 0000000..87612b5 --- /dev/null +++ b/docs/superpowers/specs/2026-07-22-baidu-quote-ws-design.md @@ -0,0 +1,146 @@ +# 百度财经 WebSocket 行情实时刷新 — 设计 + +**日期:** 2026-07-22 +**状态:** 已口头确认,待书面复核 + +--- + +## 1. 背景与目标 + +当前行情通过 HTTP `getStockQuotation` 在页面打开时拉取一次全量(分时、盘口、成交明细)。`quotation.ts` 已预留「实时更新后续对接 WebSocket」。 + +本阶段目标:接入百度财经 WebSocket,在 HTTP 全量底之上做增量刷新,使报价、盘口、分时图、分时成交与大单分析实时更新。 + +--- + +## 2. 已确认决策 + +| 项 | 选择 | +|---|---| +| 初始全量 | 现有 HTTP `getStockQuotation`,成功后再连 WS | +| 数据映射 | `tick` → 成交明细(TradeTape)+ 大单分析;`snapshot` → 报价 / 盘口 / 分时点 | +| 架构 | 独立 `BaiduQuoteWs` 客户端 + mapper;状态仍落 `quota` store | +| 合约 | 仍读 `contractConfig` 单合约,不做多合约订阅 | +| WS 库 | 原生 `WebSocket`,不引入第三方 | +| 连接 UI | 本期不做连接指示灯 / 手动重连按钮 | + +--- + +## 3. 架构与数据流 + +``` +页面挂载 + → quota.fetchQuote() // HTTP 全量 + → BaiduQuoteWs.connect() // wss://finance-ws.pae.baidu.com/ + → subscribe tick + snapshot + → 每 6s ping + → 每 60s patch snapshot + → onMessage + → product=tick → 合并 trades(最新在前) + → product=snapshot → 更新报价 / 盘口 / upsert intraday +页面卸载 / 主动 refresh + → BaiduQuoteWs.disconnect()(refresh 成功后再 connect) +``` + +### 模块划分 + +| 文件 | 职责 | +|------|------| +| `src/api/baidu/ws.ts` | 连接、心跳、订阅、重连、回调 | +| `src/api/baidu/wsTypes.ts` | tick / snapshot 消息 TypeScript 类型 | +| `src/api/baidu/mapWsQuote.ts` | 增量消息映射并合并进 `QuoteData` | +| `src/stores/quota.ts` | HTTP 成功后启 WS;应用增量;卸载断开 | +| `src/composables/useQuote.ts` | `onMounted` 拉行情;`onUnmounted` 断开 WS | + +大单分析已基于 `quote.trades` 计算,只需更新 `trades`,不改组件。 + +--- + +## 4. 协议细节 + +**端点:** `wss://finance-ws.pae.baidu.com/` + +**订阅(open 后立即发送两条):** + +```json +{"method":"subscribe","source":"pc-web","product":"tick","items":[{"code":"FG609","name":"玻璃2609","market":"ab","financeType":"futures"}]} +{"method":"subscribe","source":"pc-web","product":"snapshot","items":[{"code":"FG609","name":"玻璃2609","market":"ab","financeType":"futures"}]} +``` + +`code` / `name` 来自 `contractConfig`;`market` 固定 `ab`;`financeType` 固定 `futures`。 + +**保活:** +- 每 6s:`{"method":"ping","source":"pc-web"}` +- 每 60s:snapshot 的 `patch`(items 同订阅) + +**重连:** 断线后指数退避(1s → 2s → 4s … 上限 30s);重连成功后重新 subscribe;不自动重拉 HTTP。 + +**disconnect:** 清 ping/patch 定时器、关闭 socket、停止重连调度。 + +--- + +## 5. 合并规则 + +### 5.1 tick → trades + +- 解析 `data.detailinfos` → `TradeTick[]`(字段映射与现有 HTTP `parseTrades` 一致:`formatTime` / `price` / `volume` / `bsFlag`;最新在前) +- 前置合并到 `quote.trades` +- 去重键:`time + price + volume + side` +- 上限:最近 **200** 条 + +### 5.2 snapshot → 报价 / 盘口 / 分时 + +- `cur`:更新 `last` / `change` / `changePercent` / `avg`;状态可从 `cur.status` 或 `update` 取 +- `pankouinfos`(数组,按 `ename`):更新 open / high / low / volume / amount / openInterest / amplitude / settlement / prevSettlement / outerVol / innerVol 等 +- `askinfos` / `buyinfos`:刷新五档;过滤无效价;重算 `buyRatio` / `sellRatio` +- `update`:刷新 `updatedAt` / `status` +- `point`:按分钟时间(从 `point.time` 取 `HH:mm`)upsert 到 `intraday` + - 覆盖 / 写入:`price` ← `point.price`,`avg` ← `point.avgPrice` + - `volume`:WS 只给 `totalVolume`(全日累计)。分钟成交量 = `max(0, totalVolume - 此前各分钟 volume 之和)`;同分钟再次推送时用同一公式重算并覆盖 + - 新分钟:append;同分钟:覆盖该点 + +### 5.3 错误处理 + +- `resultCode !== "0"`:打日志,忽略本条 +- JSON / 字段解析失败:打日志,不中断连接 +- 组件层无感;不暴露 WS 连接状态到 UI + +--- + +## 6. 生命周期 + +1. `useQuote` `onMounted` → `store.fetchQuote()` +2. `fetchQuote` 成功 → `store.connectWs()`(若已连接则先 disconnect 再 connect) +3. `useQuote` `onUnmounted` → `store.disconnectWs()` +4. `refresh()` / `fetchForAnalysis()`:仍走 HTTP 全量;成功后重连 WS,用最新全量覆盖后再接增量 +5. K 线逻辑不变;WS 不修改 `candles` + +--- + +## 7. 明确不做(本期) + +- 连接状态 UI / 手动重连按钮 +- 多合约同时订阅 +- 修改 TradeTape / LargeOrderAnalysis / ChartPanel(仅消费响应式 `quote`) +- 引入第三方 WS 库 +- WS 失败时回退 HTTP 轮询 + +--- + +## 8. 验证要点 + +- HTTP 成功后会发送 tick + snapshot 两条 subscribe +- 约每 6s 有 ping,约每 60s 有 snapshot patch +- tick 合并 trades:去重生效、长度 ≤ 200;TradeTape / 大单分析随之刷新 +- snapshot.point:同分钟覆盖、新分钟追加;分时图更新 +- snapshot 盘口 / 现价字段正确刷新 +- 页面卸载后无残留 timer / 未关闭的 socket +- 手动 refresh 后 WS 会断开并重新订阅 + +--- + +## 9. 风险与注意 + +- WS 与 HTTP 的 snapshot 字段结构不完全一致(HTTP 用 `origin_pankou`,WS 用 `pankouinfos` 数组);mapper 需独立,勿强行复用 HTTP mapper 全文 +- 去重键不含服务端唯一 id(协议未提供);极端情况下同秒同价同量同向两笔可能被误去重,可接受 +- 跨域 / 鉴权:浏览器直连百度 WS;若环境拦截再评估代理,本期先直连