跨交易所强平
强平数据流的获取、归一、大小与解读方式:WebSocket 数据源、字段结构、方向语义、自适应分桶、级联检测、新鲜度规则。
查看实时小部件: /perpetuals/liquidations.
数据源
三个交易所的 WebSocket 数据源,每个资产对应一条归一化的 Redis 流。每一笔已执行的强平记录都会进入数据流——我们不会从持仓量推估强平压力,不会推断止损区域,也不会合成记录。
- Binance。
wss://fstream.binance.com/market/ws/<symbol>@forceOrder——按符号的公开流。旧路径/ws/会被 Binance 静默限流,/market/ws/才是真正活跃的路径。 - Bybit。
wss://stream.bybit.com/v5/public/linear上的liquidation主题。 - OKX。
wss://ws.okx.com:8443/ws/v5/public上的liquidation-orders频道,instType 为SWAP。
每个守护进程将事件写入按资产命名的 Redis Stream prod:liq:<asset>:events,上限为 MAXLEN ≈ 10 000(约 4 小时的连锁密集数据,清淡日可覆盖完整 24 小时)。后端为 REST 与 WebSocket 两种接口都从单一资产流读取;不存在单独的 pubsub 频道——流本身就是广播面。
事件字段结构
每个事件的字段在三个数据源中完全一致。两个时间戳故意保持区分:
ts_ms—— 交易所打的成交时间戳。跨交易所比较记录时间应使用此字段。producer_ts_ms—— 我方守护进程写入时的墙钟时间。producer_ts_ms − ts_ms是可见的数据源延迟加上我方与交易所之间的时钟偏差。会采样进入 200 事件的滚动环形缓冲区,用于 p50/p99 报告。exchange∈{binance, bybit, okx}。side∈{long, short}—— 见下方语义。qty—— 基础资产单位(BTC、ETH 等)。price—— 报价货币的成交价格。usd=qty × price。跨资产比较使用名义价值(USD);BTC 与 DOGE 间的原始 qty 比较没有意义。
方向语义
强平流以交易所的平仓订单视角编码方向,这与交易者持仓方向相反。我们归一到失败的持仓方向:
side: "long"—— 多头被强制平仓(价格下穿强平价位)。在 Binance 是SELLforceOrder;在 Bybit 是side: "Buy"的持仓被强平;在 OKX 是posSide: "long"。side: "short"—— 空头被强制平仓(价格上穿)。在 Binance 是BUYforceOrder;在 Bybit 是side: "Sell";在 OKX 是posSide: "short"。
数据流颜色随此而定:红色圆点 = 多头爆仓(价格下跌);绿色圆点 = 空头爆仓(价格上涨)。
大小缩放
每个圆点在 viewBox-px 中的半径为 clamp(√(usd / $10 000) × 2, 4, 22)。平方根抑制按面积线性的缩放,使得 $1 M 事件看起来约为 $100 K 事件的 ~3.16 倍——而不是 10 倍——且单个连锁记录不会盖住周围一切。下限 clamp 让低于 $10 K 的小事件保持可点击区域;上限 clamp 防止最大的连锁溢出面板。
r = clamp(sqrt(usd / 10_000) * 2, 4, 22) // viewBox-px # 参考值(对应大小图例) $10 K → r ≈ 4 $100 K → r ≈ 6.3 $1 M → r = 20 $10 M+ → r = 22 (clamped)
自适应渲染
原始散点只在 ~15 分钟尺度下表现良好。超过此尺度,一秒内的数百笔小记录会糊成一片均匀光晕,连锁结构消失。我们按窗口切换渲染模式:
- ≤ 15 分钟。原始散点——每个事件一个圆。最大的圆点最后绘制,以便连锁在杂尘之上仍可读。
- 1 小时–4 小时。按 (时间, 方向) 的 1 分钟桶。每个非空桶一个圆,大小按
Σ usd,绘制位置为桶内成交量加权价格。圆内的N×小徽章显示该桶合并了多少底层事件。 - 24 小时。同样逻辑,使用 5 分钟桶。
命中测试、前 N 名注释与工具提示均针对渲染后(分桶后)的事件;聚集检测、累计面板与速率子面板扫描原始事件,因为这些信号关乎单事件密度和方向流动,而非悬停目标。
聚集检测
价格聚集带在当前窗口的原始事件上检测:
reference_price = 当前 mid(最新事件价格)
bin_width = reference_price * 0.001 // 0.1 %
按 round((price - reference) / bin_width) 对事件分桶
对每个桶:
如果 Σ usd ≥ 窗口总额的 15 % 且 distinct 事件数 ≥ 3:
标记为聚集
cluster_price = 该桶价格的成交量加权均值
按 Σ usd 保留前 3 个聚集每个聚集获得一条虚线水平线 + 徽章 $X cluster · N× @ price。使用成交量加权均值(而非桶的标称中点)使该线落在金额实际集中的深度。
前 N 个内联注释
窗口中最大的最多三个圆点获得内联标签 $amount · time · venue|N×,使视线立即落在最大的连锁上。$50 K 的下限避免给杂尘加标签。标签锚点会根据圆点位于图表左半还是右半翻转,文字不会越过右轴或左缘。
强平速率子面板
在累计面板下方,镜像柱状图按方向拆分每个时间桶的 Σ usd:空头从基线向上延伸(绿色),多头向下延伸(红色)。桶大小遵循散点的自适应阈值(≤ 15m 为 30s,1–4h 为 1min,24h 为 5min),使柱体与上方圆点在视觉上对齐。
数据源健康
按 (资产, 交易所) 的状态哈希 prod:liq:status:<asset>:<exchange> 每 5 秒刷新一次,TTL 为 60 秒。后端将其转换为三个状态:
- ok —— 守护进程存活(状态哈希在 30 秒内刷新)且最近 2 分钟内有事件落入。
- stale —— 守护进程存活,但该交易所已沉默 ≥ 2 分钟。可能是真的清淡也可能是哑的数据源;前端渲染为琥珀色。
- missing —— 守护进程已死(状态哈希过期或从未写入)。渲染为红色。
健康提示工具中显示的延迟 p50 / p99 数值来自守护进程对 producer_ts_ms − ts_ms 的 200 事件滚动环形缓冲区。
空时间带
窗口中完全没有强平的连续区段会获得轻微背景着色。否则,24 小时视图只有 6 小时本地数据时,看起来会像渲染器坏了,而不是“那段时间没有连锁”。阈值为 gap ≥ 窗口的 5 % —— 在 24 小时视图中足以标记安静的 30 分钟,又不会在沉默秒中用微带把图表画成条纹。
缓存
- WebSocket。实时,无缓存。尾部由 Redis Streams 的
XREAD BLOCK驱动,WS 任务在新条目到达前阻塞等待,不轮询。 - /api/liquidations/recent。5 秒公共缓存——足以吸收刷新风暴,而不会让数据流过期。
- /api/liquidations/health。3 秒公共缓存。短到看上去实时,长到让刷新风暴不会每请求扇出 18 个
HGETALL。
限制
- 由交易所自报。每个交易所自行决定何为强平记录。罕见的伪记录(cancel-replace 闪烁、部分成交被计两次)可能混入。我们不做跨交易所去重:单个交易者横跨三个交易所的连锁,按设计就是三个事件。
- 流深度。
MAXLEN ≈ 10 000条/资产流。繁忙日单一资产可在 ~4 小时内填满该流;清淡日同一缓冲覆盖完整 24 小时。24 小时小部件窗口是硬上限——无更长期的回放面。 - 标记价格是最新强平价,不是连续 mid。水平标记线与价格轨迹均由强平记录派生。数据稀疏时轨迹呈锯齿状;若用连续 mid 数据源则会平滑。不要把该轨迹读作精确 mid 历史——把它读作“记录发生在哪里?”。
- 跨交易所时间偏差真实存在。Binance 以 1 秒粒度打戳,Bybit 与 OKX 更细;时钟会漂移。
ts_ms用于跨交易所对齐;producer_ts_ms仅作为延迟度量有用,而非排序键。 - OKX 免费层覆盖。
liquidation-orders频道在公开(免鉴权)WebSocket 上可用,但在最低 VIP 层级时,OKX 的强平 firehose 在同步连锁期间可能延迟。在此期间健康胶囊会翻为 stale。
版本
方法论版本 v1.0.0 · 更新于 2026-05-12。重大改动(新增交易所、公式微调、阈值变化)会升级版本并更新上文结构化数据中的 dateModified。