docs: add Baidu quote WebSocket real-time design spec
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7366bf66fa
commit
d55877e8c7
146
docs/superpowers/specs/2026-07-22-baidu-quote-ws-design.md
Normal file
146
docs/superpowers/specs/2026-07-22-baidu-quote-ws-design.md
Normal file
@ -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;若环境拦截再评估代理,本期先直连
|
||||||
Loading…
x
Reference in New Issue
Block a user