MarketTrace
M1PosicionamientoM2FootprintM3LiquidacionesM4FinanciaciónM5Perfil de volumen
Metodología · v2.0.0 · actualizado 2026-07-04

Metodología del order flow — cuadrante OBI × CVD

Cómo se obtiene, dimensiona y lee el cuadrante de order flow: desequilibrio del libro derivado de la profundidad, CVD por flujo agresor, normalización P95 rotatoria, clasificación de zonas, régimen HTF y reglas de frescura.

Consulta el widget en vivo en /perpetuals/positioning.

Fuentes de datos

El cuadrante agrega profundidad en reposo y flujo agresor a través de cuatro venues de perpetuos — Binance, Bybit, OKX y Hyperliquid — en ambos ejes. El runtime es todo-Rust; no hay daemons de Python en el hot path.

El WebSocket de backend /ws/market empuja una snapshot cada ~10 s y una trama trail/normalizador al suscribirse y al cambiar de ventana.

Desequilibrio del libro (OBI)

OBI mide el skew de liquidez en reposo dentro de una banda ajustada alrededor del precio medio. Se calcula primero por venue, sobre el libro propio de cada venue; la mezcla cross-venue se describe en la siguiente sección. Los niveles fuera de la banda quedan excluidos porque no afectan a un trade que se come el spread.

mid       = (best_bid + best_ask) / 2          // por venue
banda     = [mid * 0.998, mid * 1.002]         // ±0.2 %
bid_qty   = Σ qty de bids dentro de la banda
ask_qty   = Σ qty de asks dentro de la banda
OBI       = (bid_qty - ask_qty) / (bid_qty + ask_qty)

Rango:    [-1, +1]
+1 →      asks vacíos, todo el peso en bids
-1 →      bids vacíos, todo el peso en asks
 0 →      equilibrado dentro de la banda

Calculado sobre los 200 niveles superiores por lado que caen dentro de la banda (TOP_LEVELS_PER_SIDE = 200). El eje X ploteado es la mezcla cross-venue de abajo, sin suavizar en esta etapa; el widget muestra OBI como tag con tres decimales para que un movimiento de 0,01 sea visible.

Agregación cross-venue de OBI (flow-weighted)

El OBI por venue (arriba) de cada venue se combina en un único OBI cross-venue ponderado por el flujo agresor reciente de ese venue — flow-weighted (FW) — no por varianza inversa. El peso de un venue sigue dónde se están imprimiendo realmente los trades, así los libros tranquilos aportan poco y los libros activos dirigen el consenso.

El 2026-05-26 la agregación pasó de ponderación por varianza inversa (IVW) a FW. Bajo IVW, Hyperliquid dominaba la mezcla: su libro cuantizado por nSigFigs (grueso) produce un OBI de varianza artificialmente baja, que IVW premia con peso alto sin importar cuán poco tamaño haya detrás. El flow-weighting ata el peso al volumen agresor realizado, así un venue de cuantización gruesa ya no puede dominar la lectura combinada.

Delta de volumen acumulado (CVD)

CVD suma el notional agresor con signo sobre una ventana rotatoria, a través de los cuatro venues. La convención de signo sigue la lectura clásica de cinta: las compras agresoras suben, las ventas agresoras presionan. El lado agresor de cada venue se normaliza en la ingesta (Bybit, OKX y Hyperliquid lo codifican de forma distinta a Binance), de modo que cada print aporta el mismo signo.

para cada print agresor (cualquier venue):
  notional = qty * price                       // USD
  si agresor == compra: delta = +notional      // agresor compró
  si no:                delta = -notional       // agresor vendió
  añadir (ts, delta) a un deque de 2 horas

cvd_30m_usd = Σ delta para ts en [ahora - 30m, ahora]
cvd_2h_usd  = Σ delta para ts en [ahora - 2h, ahora]

El deque de 2 h es el horizonte más largo; la ventana de 30 m se toma del mismo buffer en cada escritura. El archivo de barras persiste una fila por minuto con ambas ventanas, de modo que el trail pueda replayear historia tras un reinicio. El throughput agregado de los cuatro venues queda en ~40–200 prints/s según la actividad.

Normalizador del eje Y

Las magnitudes crudas de CVD a 30 m varían en dos órdenes de magnitud entre BTC (movimientos de orden $1 M), ETH, SOL y los perpetuos más pequeños. Plotear USD crudo aplastaría los activos menores. El eje Y por eso divide por un P95 rotatorio de 7 días de |cvd_30m_usd| por activo y recorta a [-1, +1].

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

p95_30m_usd: percentil rotatorio 7 días, refrescado por el endpoint de snapshot
fallback:    2 000 000 USD cuando el percentil aún no está disponible
             (arranque en frío o muestra escasa)

El endpoint /api/market/cvd-normalizer?asset=… sirve el P95 por activo, replicado por WebSocket como trama normalizer para que el FE reescale el trail con coherencia cuando el valor llega después de los datos del trail.

Clasificación de zonas (v2)

La regla de cuadrante crudo (signo de OBI, signo de CVD) se envuelve en un pipeline de tres capas para que el veredicto no parpadee con ruido sub-bp. Cada capa actúa en secuencia; sólo las señales que sobreviven a las tres se convierten en la zona mostrada.

Capa 1 — EMA sobre OBI (CVD ya es un agregado de ventana deslizante)
  obi_ema(t) = α · obi_raw(t) + (1 - α) · obi_ema(t-1)
  α = 1 - exp(-dt / span_segundos)
  span_segundos: 30 s en el trail 30m (por defecto; ajustable por activo)

Capa 2 — Banda muerta de magnitud (Schmitt-trigger, brazo inferior)
  Dentro de la banda muerta, candidato = zona actual:
    candidato = zona_actual  si |obi_ema| < OBI_DB
                              o   |cvd|     < CVD_DB_PCT × p95_30m_usd
  De lo contrario, candidato = cuadrante de (obi_ema, cvd).
  OBI_DB        por activo: BTC/ETH 0.05, SOL 0.07, XRP 0.08,
                            BNB 0.10, DOGE 0.12
  CVD_DB_PCT    10 % del p95 |cvd_30m| rolling 7d del activo

Capa 3 — Tenencia mínima (Schmitt-trigger, brazo superior)
  Un nuevo candidato debe mantenerse ≥ MIN_TENURE_S antes de
  convertirse en actual.
  MIN_TENURE_S  60 s en trail 30m; 300 s en 4h; 1800 s en 24h.

El nombre de los cuadrantes no cambia respecto a v1.0:

x >= 0 Y y >= 0  → "Compradores al mando"
x <  0 Y y <  0  → "Vendedores dominando"
x <  0 Y y >= 0  → "Demanda absorbiendo"
x >= 0 Y y <  0  → "Libro sostiene"

Mientras un candidato espera su tenencia mínima, el FE renderiza una sub-línea explícita bajo el veredicto (“Vendedores · sostenido 4m 22s · Compradores pendientes 18s de 60s”). El clasificador es una máquina de estados visible, no una caja negra.

Los parámetros se ajustan por activo desde un sweep de grid de 7 días (scripts/replay_classifier.py); los valores seleccionados viven en backend/classifier/config.pyy pueden ser sobrescritos por env (p. ej.MICRO_DEADBAND_DOGE=0.20) para hot-patch sin redeploy. El estado (OBI EMA, timers del candidato, entered-at) se persiste en Redis entre ciclos del agregador, de modo que un reinicio del daemon resume en la misma zona en lugar de arrancar en frío.

Historial del trail

El trail dibuja una polilínea con fade por edad de las últimas N posiciones del cuadrante. Ventanas seleccionables: 30m, 4h y 24h. Cada ventana extrae una serie downsampleada del archivo de barras para que un replay de 24 h no transmita 1440 minutos crudos:

El FE limita el trail renderizado a 60 puntos para que la ventana de 24 h siga encajando sin sobreploteo. Las snapshots en vivo se anexan al mismo buffer, dejando una estela detrás de la serie bucketeada. Al cambiar de activo el buffer local se reinicia para que un cuadrante fresco no quede contaminado por el trail del activo anterior.

Etiqueta de régimen HTF

La etiqueta Trend BULL/BEAR/NEUTRAL en la cabecera del widget la calcula htf_regime() en scripts/btc_monitor.py (un cron writer que se mantiene) en la cadencia de 5 m del cron de snapshot:

toma 300 velas de 1 minuto (requiere >= 289 barras válidas)
pct_4h  = (close - close_4h_atras)  / close_4h_atras  * 100
pct_24h = (close - close_24h_atras) / close_24h_atras * 100

BULL    si pct_4h >  +0.5  O pct_24h >  +1.5
BEAR    si pct_4h <  -0.5  O pct_24h <  -1.5
NEUTRAL en caso contrario (también cuando la muestra es insuficiente)

La etiqueta es solo contexto HTF, no una lectura de flujo. Existe para que los veredictos de ventana corta del cuadrante (CVD 30 m) se contrasten con la dirección multi-hora.

Long/short ratio

El stat L/S lee el globalLongShortAccountRatio de Binance en período de 15 m, encuestado cada ~5 m por el cron de snapshot. Valores por encima de 1.0 significan cuentas retail netas largas; por debajo de 1.0 netas cortas. Es posicionamiento de cuentas, no flujo — aparece junto a OBI y CVD en el panel lateral, no en el plano del cuadrante.

Frescura

Tres señales independientes pueden marcar el widget como no-vivo:

Limitaciones

Versionado

Metodología versión v2.0.0 · actualizado 2026-07-04. Los cambios materiales (nuevos venues, ajustes de fórmula, cambios de umbral) suben la versión y actualizan dateModified en los datos estructurados de arriba.