Libro de órdenes cross-exchange
Cómo el mapa de calor combina la profundidad de los perpetuos de Binance, Bybit y OKX en una sola vista con eje temporal: fuentes, normalización, alineación temporal, casos límite, restricciones.
Consulta el widget en vivo en /perpetuals/order-book.
Fuentes de datos
Tres feeds de exchanges, solo streams públicos de profundidad. No se requieren API keys.
- Perpetuos USDT-M de Binance. WebSocket de diff-stream más una instantánea REST en arranque en frío, ambos en el endpoint de futuros. Libro L2 local validado por número de secuencia, top 200 niveles publicados por activo.
- Perpetuos lineales V5 de Bybit. WebSocket público,
orderbook.<tier>.<SYMBOL>. Tier 200 donde el venue lo soporta (BTC, ETH, SOL hoy), tier 50 para el resto. Frame de instantánea al suscribir, deltas conuincremental monótono, una resuscripción fuerza una nueva instantánea ante huecos de secuencia. - SWAP V5 de OKX. Canal público
books(400 niveles, sin auth), top 200 retenidos. Instantánea más frames de update encadenados porseqId/prevSeqIdde cada entrada. Consideramos las variantes tick-by-tick pero requieren un nivel de fees VIP que no tenemos; ver Limitaciones. - Activos cubiertos. BTC, ETH, SOL, BNB, XRP, DOGE.
Normalización: precios y cantidades
La agregación cross-exchange solo funciona cuando todas las fuentes hablan las mismas unidades. Dos ajustes ocurren al ingestar, antes de que algo llegue al agregador.
Cantidad en moneda base. Binance y Bybit devuelven cantidades en la moneda base directamente (BTC para el perpetuo BTC-USDT, etc.). OKX devuelve el tamaño en contratos, donde un contrato es ctVal unidades de la moneda base. Para BTC-USDT-SWAP ctVal = 0,01; para DOGE-USDT-SWAP es 1000. El feed de OKX resuelve ctVal del endpoint público de instrumentos al arrancar y aplica el multiplicador en cada nivel antes de publicar. Sin este paso, la profundidad de DOGE se leería 1000× más profunda en la vista cross-exchange.
Precio en buckets por activo. Cada exchange usa un tamaño de tick ligeramente distinto; el agregador redondea los precios hacia abajo al borde de bucket más cercano para que los ticks adyacentes entre exchanges se fusionen en el mismo muro. Buckets primarios por activo:
btc: $1,0 eth: $0,10 sol: $0,05 bnb: $0,10 xrp: $0,001 doge: $0,0001
Vistas multi-bucket
En cada ciclo la misma profundidad cruda se bucketiza en dos tamaños de bucket por activo en paralelo: el tick primario (arriba) y una variante 5× más gruesa. El usuario elige cuál mostrar; el mapa de calor reconecta al bucket adecuado sin abrir nuevo socket.
Para BTC eso significa una vista $1 (granularidad fina, densa cerca del precio medio) y una vista $5. Con 200 bins por lado a $1 el mapa llega a ±$200 desde el medio; la vista $5 alcanza ±$1 000, que es donde viven los imanes de números redondos ($79 k / $80 k / $81 k). La misma lógica escala por activo: ETH publica $0,10 + $0,50, DOGE publica $0,0001 + $0,001.
Agregación: suma + desglose por exchange
Para cada bucket, el agregador suma cantidades a través de las tres fuentes y conserva la contribución por exchange junto al total. Eso permite a la UI renderizar una sola fila de muro más un desglose apilado al pasar el cursor, sin un round-trip extra.
for src in (binance, bybit, okx):
for (price, qty_base) in src.depth.bids:
bucket = floor(price / BUCKET_SIZE) × BUCKET_SIZE
bid_buckets[bucket].total += qty_base
bid_buckets[bucket].by[src] += qty_base
# asks: igual, luego ordena por precio ascendente
top_bids = sorted(bid_buckets, by price desc)[:200]
top_asks = sorted(ask_buckets, by price asc)[:200]El payload de salida incluye la lista de fuentes y las mejores cotizaciones por exchange por separado. No exponemos un único mejor bid/ask consolidado; ver Limitaciones.
Cadencia y resolución de spoofs
El agregador publica a 10 Hz (una instantánea cada ~100 ms). Los feeds de productores escriben hasta ~20 Hz, pero el límite efectivo es la tasa de push del exchange (~50 a 100 ms nativo).
Con celdas de 100 ms en el mapa de calor, los muros y spoofs aparecen así:
- Spoof ≥ 100 ms → 1 celda visible (detección de borde).
- Spoof ≥ 200 ms → 2 celdas visibles (fiable).
- Spoof ≥ 500 ms → 5 celdas, se lee como una mota vertical clara.
- Muro de varios segundos → mancha horizontal a través de muchas celdas.
Los spoofs sub-100 ms no se detectan. Eso requeriría canales tick-by-tick (TBT) que están bloqueados por nivel de fees en los tres venues a nuestro nivel de acceso.
Alineación temporal
Cada productor extrae el timestamp de evento del exchange de su stream de profundidad nativo (el campo E de Binance, el ts de nivel superior de Bybit, el ts por entrada de OKX) y lo propaga junto al tiempo de publicación del propio productor.
En el agregador cada instantánea expone el timestamp de evento por fuente y el skew cross-exchange (máximo menos mínimo de los tiempos de evento entre las fuentes OK). El tsde la instantánea del mapa se mantiene como el momento de polling del agregador para que la línea temporal esté uniformemente espaciada; el skew se muestra en el tooltip cuando es ≥ 100 ms (rojo a partir de 300 ms), de modo que el “consenso” en una sola celda queda acotado de forma honesta.
Skew típico observado: < 100 ms en estado estable; picos a 300 a 500 ms en momentos de estrés de la base donde el feed de un venue se retrasa brevemente. Sin esta atribución, un muro colocado en Binance a T+0 y en Bybit a T+200 ms se leería como un único consenso instantáneo, que no lo es.
Gestión de fuentes desactualizadas
Cada productor escribe su clave de fuente con un TTL de 60 segundos más un timestamp. El agregador computa la edad por fuente en cada ciclo y excluye cualquier fuente con más de 60 segundos de la vista combinada; la fuente excluida sigue apareciendo en el array sources con estado stale, de forma que el frontend muestra un indicador degradado.
En el frontend: las pastillas de fuente del toolbar muestran color y estado, y el mapa continúa con las fuentes restantes. Un estado stale persistente suele significar que el productor sufrió un reset del watchdog o que el WebSocket se cayó sin reconectar limpio, y la página se degrada de forma visible en lugar de silenciosa.
Limitaciones y trampas conocidas
- Sin un mejor bid/ask consolidado. La base cross-exchange es normal: el perpetuo de BTC en Binance suele cotizar entre 5 y 15 dólares por encima o por debajo del mismo instrumento en Bybit y OKX. Una unión ingenua del top de libro se invierte durante esos periodos (mejor bid agregado mayor que mejor ask agregado). El widget muestra los muros agregados y las mejores cotizaciones por exchange por separado para evitar esa trampa, y resalta una banda violeta de inversión solo cuando la brecha supera el 0,10 % del precio medio (configurable con
?inv_bps=Nen la URL). - Cobertura de profundidad. 200 bins por lado por tamaño de bucket: alcance ±$200 en la vista BTC $1, ±$1 000 en la vista BTC $5. Los anclajes de números redondos a ±2 % del precio medio están más allá de lo que cualquiera de los tres exchanges devuelve en sus canales públicos. Esa profundidad es estructuralmente invisible para esta metodología.
- Latencia sub-100 ms. El agregador hace polling a 10 Hz; las tasas de push de los exchanges topan en ~50 a 100 ms en los canales públicos gratuitos. Las variantes tick-by-tick de OKX (
books-l2-tbt,books50-l2-tbt) requieren un nivel de fees superior que no tenemos; la suscripción devuelvecode 64003. Bybit y Binance no publican un canal tick-by-tick gratuito comparable para futuros. - 200 niveles ≠ libro profundo. Cada productor alimenta 200 niveles crudos. En mercados normales eso cubre aproximadamente 30 a 50 dólares desde el medio en BTC con la granularidad nativa de cotización; en pares más tranquilos puede llegar más lejos. Los muros más profundos del libro simplemente no están en el feed independientemente del tamaño de bucket.
- El skew cross-exchange es real. El mapa de calor renderiza celdas a intervalos uniformes de 100 ms, pero la instantánea trimembre subyacente para cada celda puede abarcar hasta
cross_exchange_skew_msen tiempo de evento, típicamente < 100 ms, ocasionalmente 200 a 500 ms. El tooltip lo muestra cuando es relevante; trátalo como el piso de granularidad temporal.
Versionado
Lanzamiento inicial v1.0.0 el 2026-05-08 (agregación a 4 Hz, 50 niveles). v2.0.0 el 2026-05-09: se sube a 10 Hz, 200 niveles, vistas multi-bucket ($1 + $5 por activo), alineación por timestamp de evento por fuente con exposición del skew cross-exchange. Los cambios materiales en la ruta de cómputo suben la versión y actualizan la fecha publicada. Los cambios cosméticos no.