# WebSocket 共用与币安限频评估 ## 一、币安合约 WS 限制(摘要) - **Base URL**:`wss://fstream.binance.com` - **单 stream**:`/ws/` - **组合 stream**:`/stream?streams=///...` - **单连接最多订阅**:**1024 个 Streams** - **订阅限速**:**每秒最多 10 条订阅消息**,超限会断连;**反复断连的 IP 可能被屏蔽** - **连接有效期**:单连接不超过 24 小时,需断线重连 - **Ping/Pong**:服务端约 3 分钟发 ping,客户端需在 10 分钟内回复 pong(当前 aiohttp heartbeat 已满足) --- ## 二、当前系统 WS 使用方式(按进程) 当前为 **一进程一账户**(如 supervisor 按 `ATS_ACCOUNT_ID` 起多个 trading_system 进程),每个进程内: | 用途 | 连接数/进程 | 订阅内容 | 是否公开 | 可否多账户共用 | |------|-------------|----------|----------|----------------| | **UserDataStream** | 1 | listenKey(订单/持仓/余额) | 否(需 listenKey) | **否**,每账户必须独立 | | **Ticker24hStream** | 1 | `!ticker@arr`(全市场 24h ticker) | 是 | **可共用**,全市场一份即可 | | **BookTickerStream** | 1 | `!bookTicker`(全市场最优买卖) | 是 | **可共用**,全市场一份即可 | | **KlineStream** | 1 | `/stream` + 动态 `SUBSCRIBE`:`@kline_` | 是 | **可共用**,按需订阅,单连接 ≤1024 streams | | **持仓价格监控**(position_manager) | **每持仓 1 条** | 每连接 `/ws/@ticker` | 是 | **可共用**,可合并为一条组合流 | 即:**每账户 4 条固定连接 + 持仓数个单独连接**。 --- ## 三、多账户时的连接与订阅量(当前架构) 设账户数为 **N**,单账户最大持仓数为 **M**(如 10): - **UserDataStream**:N 条(每账户 1,**不能省**) - **Ticker24hStream**:N 条 → 若共用为 **1 条** - **BookTickerStream**:N 条 → 若共用为 **1 条** - **KlineStream**:N 条,每连接动态订阅若干 `symbol@kline_interval` → 若共用为 **1 条**,总 streams 数为「所有账户用到的 (symbol, interval) 并集」 - **持仓监控**:N × M 条(每持仓一个 `/ws/@ticker`)→ 若合并为一条组合流,为 **1 条连接**,streams 数为「所有账户持仓的 symbol 并集」,且 **≤1024** **当前是否超限:** - **1024 streams/连接**:单条 KlineStream 当前按「扫描/策略用到的 symbol×interval」订阅,通常几十~小几百级,远低于 1024;持仓监控若合并为一条组合流,symbol 数一般也远小于 1024。**正常使用不会超**。 - **10 条订阅/秒**:KlineStream 在扫描时可能对多个 symbol×interval 连续调用 `subscribe`,若并发高会短时间多发订阅消息,有**超过 10 条/秒**的风险,存在被断连、进而 IP 被限的风险。**需要限速**(见下文实现)。 --- ## 四、可共用的流与建议 ### 1. 强烈建议共用(公开、全市场一份即可) - **Ticker24hStream**(`!ticker@arr`) - 全市场 24h 行情,与账户无关。 - **建议**:单机多进程时,可由一个「行情进程」或主进程单独起 1 条连接,写入 Redis/共享缓存,其他进程只读缓存;或若已用 Redis 等共享缓存,仅一个进程负责拉 WS 并更新缓存。 - **BookTickerStream**(`!bookTicker`) - 全市场最优买卖,与账户无关。 - **建议**:同上,共用 1 条连接 + 共享缓存。 ### 2. 建议共用(减少连接与 stream 总数) - **KlineStream**(`@kline_`) - 按 (symbol, interval) 动态订阅,单连接最多 1024 streams。 - 多账户共用 1 条连接时,订阅集合为「各账户用到的 (symbol, interval) 并集」,通常仍远小于 1024。 - **建议**:单机多进程时,可只在一个进程内起 KlineStream,其他进程通过 Redis/共享内存读 K 线缓存;或部署一个共享「K 线 WS 服务」供多进程使用。 - **持仓监控**(`@ticker`) - 当前实现为「每持仓 1 条 `/ws/@ticker`」,多账户×多持仓会变成 N×M 条连接。 - **建议**:改为**一条组合流**:`/stream?streams=s1@ticker/s2@ticker/...`,把所有需要监控的 symbol 放在一起,总 symbol 数 <1024 即可。多账户可共用这一条连接(订阅「所有账户持仓 symbol 的并集」),每个账户只消费自己关心的 symbol 即可。 ### 3. 不能共用 - **UserDataStream**(listenKey) - 与账户绑定,每账户独立 listenKey、独立连接。**必须每账户 1 条连接**。 --- ## 五、限频与实现建议 ### 1. 订阅消息 ≤10 条/秒(必须遵守) - **KlineStream** 在 `subscribe(symbol, interval)` 时向同一连接发送 SUBSCRIBE。 - 若扫描阶段并发请求多个 symbol×interval,会在短时间连续发送多条订阅,容易超过 **10 条/秒**。 - **实现**:在 KlineStream 内做**订阅限速**:例如维护「最近 1 秒内已发送的订阅次数」,若已达 10 次则 sleep 到「满 1 秒」后再发;或批量排队,按每秒最多 8~10 条发送。 - 已在代码中为 KlineStream 增加限速逻辑(见下节)。 ### 2. 单连接 1024 streams - 当前 KlineStream 与持仓监控的 stream 数量均远低于 1024,只需在后续若「预订阅」大量 symbol×interval 或大量持仓时,确保单连接订阅数 ≤1024 即可(可做订阅数统计与上限检查)。 ### 3. 连接 24 小时 - 现有各 WS 均有断线重连,满足「不超过 24 小时」的文档要求;保持即可。 --- ## 六、结论与风险 | 项目 | 当前是否可能超限 | 说明 | |------|------------------|------| | 单连接 1024 streams | 否 | 当前 K 线与持仓监控订阅量远低于 1024 | | 10 条订阅/秒 | **是(有风险)** | KlineStream 扫描时可能短时大量 subscribe,已加限速 | | 连接数 | 否 | 多账户时连接数线性增长,共用后可显著下降 | | 24h / Ping-Pong | 否 | 已重连 + heartbeat | **已实现:** 1. **KlineStream 订阅限速**:发送 SUBSCRIBE 时控制在 ≤10 条/秒。 2. **多进程/多账户共用 Ticker24h、BookTicker、KlineStream**: - 使用 Redis 选主(`market_ws_leader`):仅 **Leader** 进程建立上述三条 WS 连接并写入 Redis。 - 非 Leader 进程不建这三条连接,通过 **Redis 刷新任务**(Ticker24h/BookTicker 每 2 秒从 Redis 拉取)和 **get_klines 时读 Redis** 获取数据。 - 配置项 `USE_SHARED_MARKET_WS`(默认 true):有 Redis 时启用共用;关闭则每进程独立建连接。 3. **持仓监控**:仍为每进程按持仓建多条 `/ws/@ticker`;后续可改为单连接组合流并共享(未实现)。