MarketTrace
M1持仓状态M2订单簿M3强平M4资金费率
方法论 · v2.0.0 · 更新于 2026-05-12

市场持仓(OBI × CVD)

OBI × CVD 象限的来源、量纲与读取方式:基于深度的失衡、主动成交 CVD、滚动 P95 归一化、区间分类、HTF 趋势、新鲜度规则。

查看实时小部件: /perpetuals/positioning.

数据源

两个 Binance USDT-M 期货流喂入每个资产单一的微观结构守护进程。象限在 v1.0.0 中为单一来源;跨交易所扩展(每交易所 OBI 与 CVD 加上分歧标记)计划在后续版本中推出。

守护进程 scripts/microstructure_daemon.py 每 30 秒向 data/<asset>/microstructure_snapshot.json 写入一次心跳快照,并向 data/<asset>/microstructure_bars.jsonl(轨迹历史面)每分钟写入一条 K 线。后端 /ws/market WebSocket 每 ~10 秒推送一次快照,并在订阅与窗口变更时推送 trail/normaliser 帧。

订单簿失衡(OBI)

OBI 衡量中间价附近狭窄带内的挂单流动性偏斜。带外的档位被排除,因为它们不会影响吃掉价差的成交。

mid       = (best_bid + best_ask) / 2
band      = [mid * 0.998, mid * 1.002]   // ±0.2 %
bid_qty   = 带内买盘 qty 之和
ask_qty   = 带内卖盘 qty 之和
OBI       = (bid_qty - ask_qty) / (bid_qty + ask_qty)

范围:    [-1, +1]
+1 →      卖盘为空,全部权重在买盘
-1 →      买盘为空,全部权重在卖盘
 0 →      带内平衡

计算时取带内每侧前 50 档。绘制为象限的 X 轴,不做平滑。小部件以三位小数显示 OBI 标签,使 0.01 的变化也可见。

累计成交量差(CVD)

CVD 在滚动窗口内对带符号的主动成交名义额求和。方向约定遵循行业读盘惯例:主动买入推升,主动卖出施压。

对每个 aggTrade 事件:
  notional = qty * price                       // USD
  若 is_buyer_maker == false: delta = +notional   // 主动买入
  否则:                      delta = -notional   // 主动卖出
  将 (ts, delta) 添加到 2 小时 deque

cvd_30m_usd = Σ delta,ts 在 [now - 30m, now]
cvd_2h_usd  = Σ delta,ts 在 [now - 2h, now]

2 小时 deque 是最长视野;30 分钟窗口在每次写入时从同一缓冲区切片得到。bars 文件按分钟持久化一行并保存两个窗口,以便守护进程重启后轨迹可回放历史。每事件吞吐量取决于交易所活跃度,约为 10–50 prints/s。

Y 轴归一化器

原始 30 分钟 CVD 量级在 BTC(百万美元级波动)、ETH、SOL 与较小永续合约之间相差两个数量级。绘制原始 USD 会把小资产压成一条平线。因此 Y 轴按资产除以滚动 7 天的 |cvd_30m_usd| P95,并将结果限制在 [-1, +1]

y_norm = clamp(cvd_30m_usd / p95_30m_usd, -1, +1)

p95_30m_usd: 滚动 7 天分位,由 snapshot 端点刷新
fallback:    当滚动分位尚不可用时(冷启动或样本较薄)
             使用 2_000_000 USD

端点 /api/market/cvd-normalizer?asset=… 提供每资产的 P95 值,通过 WebSocket 以 normalizer 帧镜像,以便 FE 在该值在 trail 数据之后到达时一致地重缩放轨迹。

区间分类(v2)

原始象限规则(OBI 符号、CVD 符号)被包裹在三层流水线中,使裁决不会因 sub-bp 噪声而抖动。每一层依次触发;只有通过全部三层的信号才成为显示的区间。

第 1 层 — 对 OBI 做 EMA(CVD 已经是滑动窗口聚合)
  obi_ema(t) = α · obi_raw(t) + (1 - α) · obi_ema(t-1)
  α = 1 - exp(-dt / span_seconds)
  span_seconds: 30m 轨迹默认 30 秒(可按资产调整)

第 2 层 — 量级死区(Schmitt-trigger 下限)
  在死区内,候选区间 = 当前区间:
    candidate_zone = current_zone  若 |obi_ema| < OBI_DB
                                     或 |cvd|    < CVD_DB_PCT × p95_30m_usd
  否则候选 = (obi_ema, cvd) 的象限。
  OBI_DB        按资产:BTC/ETH 0.05、SOL 0.07、XRP 0.08、BNB 0.10、DOGE 0.12
  CVD_DB_PCT    资产滚动 7d |cvd_30m| p95 的 10%

第 3 层 — 最小停留(Schmitt-trigger 上限)
  新候选必须保持 ≥ MIN_TENURE_S 才能成为当前。
  MIN_TENURE_S  30m 轨迹 60s;4h 300s;24h 1800s。

象限命名相对 v1.0 未变:

x >= 0 且 y >= 0  → "买方主导"
x <  0 且 y <  0  → "卖方占优"
x <  0 且 y >= 0  → "需求吸收中"
x >= 0 且 y <  0  → "订单簿支撑"

当候选还在等待其停留时长时,FE 在裁决下方渲染一条明确的 candidate_pending子行 (“卖方 · 已持续 4m 22s · 买方候选 18s / 60s”)。分类器是一个可见的状态机,而非黑箱。

参数从 7 天网格扫描(scripts/replay_classifier.py)按资产调优;所选值位于 backend/classifier/config.py,并可通过环境变量覆盖(如 MICRO_DEADBAND_DOGE=0.20)以便在不重新部署的情况下热补丁。状态(OBI EMA、候选计时器、entered-at)在聚合器周期之间持久化到 Redis,因此守护进程重启会从同一区间恢复,而不是冷启动。

轨迹历史

轨迹绘制按年龄渐隐的折线,显示最近 N 个象限位置。可选窗口为 30m4h24h。每个窗口从 bars 文件拉取下采样序列,使 24 小时回放无需流式传输 1440 个原始分钟:

FE 将渲染的轨迹限制为 60 个点,以便 24 小时窗口在不重叠绘制的情况下仍能装下。实时快照追加到同一缓冲区,在分桶序列之后形成尾迹。切换资产时本地缓冲区重置,以免新象限被先前资产的轨迹污染。

HTF 趋势标签

小部件头部的 Trend BULL/BEAR/NEUTRAL 标签由 scripts/btc_monitor.py 中的 htf_regime() 在快照守护进程的 5 分钟节奏上计算:

拉取 300 根 1 分钟 K 线(需要 >= 289 根有效 K 线)
pct_4h  = (close - close_4h_ago)  / close_4h_ago  * 100
pct_24h = (close - close_24h_ago) / close_24h_ago * 100

BULL    若 pct_4h >  +0.5  或 pct_24h >  +1.5
BEAR    若 pct_4h <  -0.5  或 pct_24h <  -1.5
NEUTRAL 否则(样本不足时也为此值)

该标签仅为 HTF 上下文,而非流向读取。它的存在是为了让象限的短窗口裁决(30 分钟 CVD)能够对照多小时方向做合理性检查。

多空比

L/S 统计读取 Binance 的 globalLongShortAccountRatio(15 分钟周期),由快照守护进程每 ~5 分钟轮询。高于 1.0 表示零售账户净多头;低于 1.0 表示净空头。这是账户的持仓,而非流向——它与 OBI 和 CVD 一起出现在侧栏,而不是象限平面中。

新鲜度

三个独立信号可将小部件标记为非实时:

限制

版本

方法论版本 v2.0.0 · 更新于 2026-05-12。重大改动(新增交易所、公式微调、阈值变化)会升级版本并更新上文结构化数据中的 dateModified。