Esta página fue traducida automáticamente. El original en inglés es la versión canónica. Leer en inglés →
Saltar al contenido principal

API WebSocket

Transmisión de datos en tiempo real para el trading de opciones en Hypercall.

Referencia interactiva

Consulte la Referencia interactiva de la API WebSocket para una mejor experiencia de navegación, con ejemplos en vivo y detalles de los esquemas.

Especificación legible por máquina

Descargue la especificación AsyncAPI para uso programático.

Evolución aditiva del esquema

Los objetos de mensaje de WebSocket pueden incorporar nuevos campos sin previo aviso. Los clientes deben ignorar los campos que no reconozcan. Hypercall no elimina campos de un esquema de mensaje existente.

Conexión​

Conéctese a wss://HOST/ws:

Endpoints:

  • Producción: wss://api.hypercall.xyz/ws
  • Local: ws://localhost:3000/ws
Estado de testnet

La testnet está deshabilitada temporalmente hasta que Hypercall obtenga más HYPE de testnet.

Compresión​

/ws admite permessage-deflate de RFC 7692. Actívelo en su cliente para reducir el ancho de banda de datos de mercado: en tráfico de producción capturado, los frames comprimidos de forma independiente son aproximadamente un 45% más pequeños, y los lotes de precios índice aproximadamente un 70% más pequeños.

  • Su cliente ofrece la extensión en la solicitud de upgrade, por ejemplo Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits.
  • Cuando el servidor la acepta, la respuesta 101 incluye Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover. A partir de ahí, cada mensaje del servidor se comprime por separado, sin una ventana deslizante compartida, y los mensajes de menos de unos cientos de bytes se siguen enviando sin comprimir. Su librería los descomprime de forma transparente.
  • Si la respuesta no tiene el encabezado Sec-WebSocket-Extensions, todos los frames van sin comprimir. La compresión se habilita por entorno, por lo que los clientes deben manejar ambos casos; los mensajes JSON son idénticos en cualquiera de ellos. Producción todavía no acepta la extensión, así que los frames de producción actualmente van sin comprimir.
  • Su cliente puede comprimir lo que envía. El servidor descomprime cada mensaje del cliente hasta 256 KiB y cierra la conexión si un mensaje superara ese límite.

Los navegadores negocian la extensión automáticamente. La mayoría de las librerías no requieren cambios:

Python (websockets habilita la compresión por defecto):

import websockets

async with websockets.connect("wss://api.hypercall.xyz/ws", compression="deflate") as ws:
...

Node.js (ws):

import WebSocket from "ws";

const ws = new WebSocket("wss://api.hypercall.xyz/ws", { perMessageDeflate: true });

Rust: el WsClient de hypercall-client negocia permessage-deflate por defecto (consulte Ejemplo: cliente en Rust). tungstenite y tokio-tungstenite sin extensiones todavía no lo implementan, por lo que se conectan sin compresión. Para usar compresión con su propio socket, utilice un cliente que la implemente, como yawc:

let url = "wss://api.hypercall.xyz/ws".parse()?;
let mut ws = yawc::WebSocket::connect(url)
.with_options(yawc::Options::default().with_low_latency_compression())
.await?;

Identificación de la wallet​

Para recibir datos en los canales autenticados (órdenes, ejecuciones, portafolio), identifique su wallet después de conectarse enviando un mensaje Authenticate:

{"type": "Authenticate", "wallet": "0x1234..."}

El servidor responde con una confirmación:

{"type": "Authenticated", "wallet": "0x1234..."}

Después de recibir Authenticated, puede suscribirse a los canales autenticados. Si la dirección de la wallet no es válida, el servidor responde con un mensaje Error y la conexión permanece abierta.

Obsoleto: autenticación por parámetro de consulta

El parámetro de consulta ?wallet= sigue siendo compatible por razones de retrocompatibilidad, pero está obsoleto y se eliminará en una versión futura. Prefiera el método basado en mensajes descrito arriba.

Actividad de la conexión​

El servidor aplica un heartbeat de WebSocket:

  • Envía un frame de control Ping cada 20 segundos
  • Espera el Pong correspondiente en un plazo de 60 segundos
  • Cierra la conexión con el código de cierre 1008 y el motivo pong timeout si el cliente deja de responder

Las implementaciones de WebSocket en los navegadores gestionan ping/pong automáticamente. Muchas librerías de websocket en Rust, incluidas tungstenite y tokio-tungstenite, también gestionan por usted el ping/pong de los frames de control. Revise la documentación de la librería de su cliente antes de añadir un manejo manual de Pong. Las implementaciones personalizadas o de socket sin procesar deben responder a los frames Ping con Pong.

Recuperación de consumidores lentos​

El servidor cierra una conexión /ws que no logra vaciar los datos salientes dentro del límite de seguridad configurado de mensajes, bytes codificados, antigüedad en cola o escritura en el socket. Cuando la conexión todavía puede aceptar un frame de cierre, el servidor usa el código 1008 y un motivo JSON compacto:

{"error":"slow_consumer","class":"ordered_public","cause":"message_age","recovery":"snapshot_resubscribe"}

Los campos del motivo son:

CampoSignificado
classClase de entrega cuyo frame superó el límite de seguridad.
causemessage_limit, byte_limit, message_age o write_timeout.
recoveryAcción siguiente requerida, como resubscribe, snapshot_resubscribe, portfolio_refetch o rest_reconcile.

Tras cualquier desconexión, vuelva a conectarse, identifique de nuevo la wallet cuando sea necesario, vuelva a suscribirse y concilie el estado actual antes de procesar nuevos eventos. Los canales públicos ordenados requieren un snapshot nuevo. Los canales privados de eventos requieren conciliación a través de la interfaz REST autoritativa, porque la reproducción por cursor todavía no está disponible. Una conexión completamente bloqueada puede terminar antes de poder leer el motivo del cierre, por lo que los clientes deben aplicar este flujo de recuperación también ante un cierre no limpio.

Use conexiones separadas para los datos de mercado públicos de alta frecuencia y para los comandos autenticados o los streams privados. Las clases de entrega determinan las métricas y el comportamiento de recuperación, pero los frames de una misma conexión comparten una única ruta de escritura ordenada en el socket. Por lo tanto, una escritura pública bloqueada puede retrasar frames privados posteriores en esa misma conexión hasta que el plazo de escritura la cierre.

Suscripción a canales​

Envíe un mensaje JSON para suscribirse:

{"type": "Subscribe", "channel": "orderbook"}

Para cancelar la suscripción:

{"type": "Unsubscribe", "channel": "orderbook"}

Recibirá una confirmación:

{"type": "Subscribed", "channel": "orderbook"}

Filtrado por símbolo​

Los canales order_updates y fills admiten un filtro opcional symbols. Cuando se proporciona, el servidor solo envía los mensajes cuyo activo subyacente coincide con uno de los símbolos especificados.

{"type": "Subscribe", "channel": "order_updates", "symbols": ["BTC"]}

Se aceptan tanto activos subyacentes sin más ("BTC") como nombres completos de instrumentos ("BTC-20260131-100000-C"). Para añadir más símbolos, envíe otro Subscribe. Para eliminar símbolos concretos:

{"type": "Unsubscribe", "channel": "order_updates", "symbols": ["BTC"]}

Cuando no se especifica symbols, se reenvían todas las actualizaciones de su wallet.

Los canales públicos orderbook, trades, indicative_market_data e indicative_market_data_v2 también aceptan symbols, que se comparan con los símbolos exactos de los instrumentos (sin distinguir mayúsculas y minúsculas), no con los activos subyacentes:

{"type": "Subscribe", "channel": "orderbook", "symbols": ["BTC-20260131-100000-C"]}

Sin symbols, estos canales entregan todos los instrumentos.

Filtrado de la cadena de opciones​

El canal options_chain admite filtrado por símbolos de instrumento, fecha de vencimiento y tipo de opción:

{
"type": "Subscribe",
"channel": "options_chain",
"symbols": ["BTC-20260131-100000-C"],
"expiry": "2026-01-31",
"option_type": "call"
}
FiltroValoresPor defecto
symbolsArray de símbolos completos de instrumentos (p. ej., ["BTC-20260131-100000-C"])Todos los instrumentos
expiryCadena de fecha "YYYY-MM-DD", comparada con la fecha de calendario UTC del vencimiento de cada instrumentoTodos los vencimientos
option_type"call", "put", "both", u omitido para ambosAmbos

Entrega por lotes​

indicative_market_data_v2 transporta las mismas filas que indicative_market_data, con varias filas por frame:

{"type": "Subscribe", "channel": "indicative_market_data_v2", "symbols": ["BTC-20260131-100000-C"]}

El servidor confirma con un marcador de lote:

{"type": "Subscribed", "channel": "indicative_market_data_v2", "batch": true}

A continuación retiene cada fila como máximo durante una ventana de lote, 25 ms por defecto, y envía las filas publicadas en esa ventana como un único frame IndicativeMarketDataBatch. Un lote también se envía antes de tiempo en cuanto alcanza 256 filas.

  • Detección de compatibilidad: solo una confirmación con "batch": true indica que el servidor agrupa por lotes. Los servidores publicados antes de este canal confirman cualquier nombre de canal sin el marcador y luego no envían nada, y los servidores actuales responden a un canal desconocido con un error unknown_channel. En cualquiera de los dos casos, cancele la suscripción a indicative_market_data_v2 y suscríbase a indicative_market_data en la misma conexión.
  • Latencia: una fila llega hasta una ventana más tarde que en indicative_market_data. En tráfico de producción con la ventana por defecto, las filas esperaron 12 ms de media y nunca más de 25 ms. Use el canal v1 si actúa sobre actualizaciones individuales de cotizaciones en cuestión de milisegundos.
  • Ancho de banda: el agrupamiento por sí solo ahorra alrededor de un 7% de bytes. El gran ahorro llega con permessage-deflate: los lotes comprimidos son unas 9,8 veces más pequeños que los frames de una fila sin comprimir para una suscripción sin filtro, y unas 8,3 veces más pequeños para una sola cadena de opciones, frente a unas 1,8 veces para filas comprimidas una a una.
  • Orden: las filas de updates están en orden de publicación, y los lotes llegan en orden. Las filas no se consolidan, por lo que un mismo instrumento puede aparecer más de una vez en un lote. Aplique las filas en orden y llegará al mismo estado que en el canal v1.
  • Snapshot: el snapshot del momento de la suscripción también llega como frames de lote.
  • Filtros: symbols funciona igual que en indicative_market_data. Al restringir el filtro o cancelar la suscripción, primero se envían las filas que ya estaban pendientes con el filtro anterior y después la confirmación Unsubscribed, de modo que ninguna fila se pierde ni se duplica.
  • Canales independientes: una conexión puede suscribirse a ambos canales con filtros distintos. indicative_market_data no cambia.

Canales disponibles​

CanalRequiere autenticaciónDescripción
orderbookNoActualizaciones L2 del libro de órdenes para todos los símbolos
tradesNoFeed público de operaciones
market_updatesNoCambios en los listados de mercados (creados/eliminados/vencidos)
options_chainNoActualizaciones incrementales de la cadena de opciones (filtrable por symbols, expiry, option_type)
index_pricesNoPrecios spot/índice en tiempo real para todos los activos subyacentes
indicative_market_dataNoStream de proveedores de cotizaciones en lista de permitidos. Aún no está disponible de forma general
indicative_market_data_v2NoEl mismo stream en frames de lote. Consulte Entrega por lotes
order_updatesSíCambios de estado de sus órdenes (filtrable por símbolo)
fillsSíEjecuciones de sus operaciones (filtrable por símbolo)
portfolioSíActualizaciones de sus posiciones y saldos
liquidationSíCambios en su estado de liquidación
rfqSíCotizaciones RFQ, actualizaciones de estado y notificaciones de ejecución
experimental_order_updates, experimental_combo_fillsSíCanales experimentales de combos. Consulte API experimental de combos
experimental_combo_tradesNoOperaciones públicas experimentales de combos

Los datos de competiciones y clasificaciones no se sirven desde api.hypercall.xyz, ni por WebSocket ni por REST. Suscribirse a los canales retirados competition o competition_engagement devuelve un Error. La aplicación de trading lee las competiciones por HTTP desde el servicio de analítica en https://api-ui.hypercall.xyz, por ejemplo GET /v2/competitions, GET /v2/competitions/{id}, GET /v2/competitions/leaderboard y GET /v2/competitions/all-time/leaderboard.

Tipos de mensaje​

Colocar orden (autenticado)​

Coloque una orden a través de la ruta de comandos de WebSocket.

{
"type": "PlaceOrder",
"wallet": "0x1234...",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"size": "1",
"price": "100",
"tif": "gtc",
"route": "book_only",
"client_id": "my-order-1",
"nonce": 1780000000000,
"signature": "0x..."
}

El nonce anterior es ilustrativo. Genere uno nuevo para cada orden a partir de la hora Unix actual en milisegundos, por ejemplo Date.now() en JavaScript. Un valor fijo copiado queda fuera de la ventana aceptada y se rechaza.

CampoTipoDescripción
walletstringDirección de la wallet propietaria de la orden
symbolstringSímbolo de la opción
sidestring"Buy" o "Sell"
sizestringTamaño del contrato, idéntico al valor firmado
pricestringPrecio límite, idéntico al valor firmado
tifstringTime-in-force opcional, por defecto "gtc"
routestringUse "book_only". Una ruta omitida todavía se acepta, pero está obsoleta y su fecha de retirada ya ha pasado.
client_idstringID de orden del cliente, opcional
reduce_onlybooleanOpcional, por defecto false. Una orden reduce-only firma PlaceOrderReduceOnly y requiere un route explícito
mmp_enabledbooleanOpcional, por defecto false
builder_code_addressstringWallet de builder code, opcional
nonceintegerNonce de firma obligatorio: la hora Unix actual en milisegundos. Debe estar dentro de un rango de dos días antes y un día después de la hora actual. Cada nonce se acepta una sola vez por firmante, y las órdenes REST y WebSocket comparten el mismo espacio de nonces. Un frame reproducido se rechaza.
signaturestringFirma EIP-712 de PlaceOrder

La conexión debe haber enviado Authenticate previamente; de lo contrario, el servidor responde {"type": "Error", "message": "Not authenticated"}. El firmante debe ser wallet o un agente aprobado para ella.

Actualmente, PlaceOrder por WebSocket se envía directamente al libro de órdenes. route="best_execution" y route="rfq_only" se rechazan en WebSocket porque esta ruta todavía no ejecuta el enrutamiento RPI/RFQ. Use POST /order para best_execution.

Una orden admitida recibe respuesta en la misma conexión con un OrderResult:

{
"type": "OrderResult",
"order_id": 12345,
"status": "ACKED",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"price": "100",
"size": "1"
}

Se añade reason cuando la orden no es aceptada. Los fallos de validación, de firma y de límite de frecuencia se envían como un Error cuyo message empieza por Order placement failed:. Los cambios de estado posteriores llegan por order_updates.

Actualización del libro de órdenes​

Snapshot/actualización L2 del libro de órdenes para un símbolo.

{
"type": "OrderbookUpdate",
"symbol": "BTC-20260131-100000-C",
"option_token_address": "0x...",
"bids": [["95000.5", "10.5"], ["94999.0", "25.0"]],
"asks": [["95001.0", "8.0"], ["95002.5", "15.0"]],
"timestamp": 1737331200000
}
CampoTipoDescripción
symbolstringSímbolo de la opción
option_token_addressstring?Dirección on-chain del token de la opción, cuando se conoce
bidsarrayNiveles bid como tuplas [price, size]; el tamaño está en contratos legibles
asksarrayNiveles ask como tuplas [price, size]; el tamaño está en contratos legibles
timestampintegerMarca de tiempo Unix (milisegundos)

Operación​

Evento público de operación.

{
"type": "Trade",
"symbol": "BTC-20260131-100000-C",
"price": "0.0523",
"size": "5.0",
"side": "Buy",
"timestamp": 1737331200000
}
CampoTipoDescripción
symbolstringSímbolo de la opción
pricestringPrecio de la operación en USD
sizestringTamaño de la operación en contratos
sidestringLado del agresor (Buy o Sell)
timestampintegerMarca de tiempo Unix (milisegundos)

Ejecución (autenticado)​

Notificación de ejecución de su operación.

{
"type": "Fill",
"order_id": 12345,
"fill_id": 67890,
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"price": "0.0523",
"size": "5.0",
"timestamp": 1737331200000,
"wallet_address": "0x1234...abcd",
"fee": "0",
"trade_id": 99999,
"is_taker": true,
"builder_code_address": null,
"builder_code_fee": null,
"instrument_type": "option"
}
CampoTipoDescripción
order_idintegerID de su orden
fill_idintegerID de la ejecución
symbolstringSímbolo de la opción
sidestringSu lado de la operación (Buy o Sell)
pricestringPrecio de ejecución en USD
sizestringTamaño de la ejecución en contratos
timestampintegerMarca de tiempo Unix (milisegundos)
wallet_addressstringDirección de su wallet
feestringComisión de trading cobrada. Devuelve 0 mientras las comisiones del venue de lanzamiento estén deshabilitadas
trade_idintegerID único de la operación
is_takerbooleanIndica si usted fue el taker
builder_code_addressstring?Wallet de builder code (si existe)
builder_code_feestring?Comisión de builder code. Devuelve null mientras las comisiones del venue de lanzamiento estén deshabilitadas
instrument_typestring"option"

Actualización del portafolio (autenticado)​

Se envía en el canal portfolio para posiciones, saldos, margen y griegas. Al suscribirse, el servidor envía un snapshot Initial y después actualizaciones incrementales.

El type de cada frame es su tipo de actualización:

Tipo de actualizaciónCampos además de timestamp
Initialpositions
PositionUpdateposition
BalanceUpdatetotal_margin_used
MarginUpdatespan_margin, margin_summary, margin_mode, total_margin_used, available_balance
GreeksUpdateper_leg, aggregate

El timestamp de los frames de portfolio está en segundos Unix, a diferencia de las marcas de tiempo en milisegundos de los demás canales.

Ejemplo de actualización de griegas:

{
"type": "GreeksUpdate",
"timestamp": 1737331200,
"per_leg": [
{
"symbol": "BTC-20260131-100000-C",
"quantity": "2.0",
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
],
"aggregate": {
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
}

Para portafolios vacíos, las actualizaciones de griegas usan:

  • per_leg: []
  • aggregate: null

Actualización de orden (autenticado)​

Notificación de cambio de estado de una orden. Se incluyen las actualizaciones PARTIALLY_FILLED. filled_size es la cantidad acumulada ejecutada en todas las ejecuciones de la orden, no la cantidad de la última ejecución.

{
"type": "OrderUpdate",
"order_id": 12345,
"client_id": "my-order-1",
"request": {
"price": "0.0523",
"size": "10.0",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"tif": "gtc"
},
"status": "PARTIALLY_FILLED",
"filled_size": "0.75",
"timestamp": 1767225600000,
"reason": null,
"wallet_address": "0x0000000000000000000000000000000000000001",
"instrument_type": "option"
}

status es uno de ACKED, OPEN, PARTIALLY_FILLED, FILLED, CANCELED o REJECTED. client_id se omite cuando la orden no tiene uno. instrument_type es "option" o "perp".

Actualización de mercado​

Cambios en los listados de mercados.

Mercado creado:

{
"type": "MarketUpdate",
"action": "Created",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1737331200000
}

Mercado vencido:

{
"type": "MarketUpdate",
"action": "Expired",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1738281600000
}

action es Created, Expired, Deleted (solo incluye symbol y timestamp) o ComboCreated (consulte API experimental de combos).

Actualización de la cadena de opciones​

Se envía en options_chain cuando cambia un listado o su mejor nivel del libro. action es Upsert o Remove.

{
"type": "OptionsChainUpdate",
"action": "Upsert",
"currency": "BTC",
"expiry": 1769846400,
"row": {
"strike": 100000.0,
"call": {
"symbol": "BTC-20260131-100000-C",
"bid_price_usd": 1520.0,
"ask_price_usd": 1580.0
}
},
"timestamp": 1737331200000
}

Una fila Upsert contiene una pata (call o put) con los campos de pata del snapshot de la cadena de opciones: symbol, option_token_address, precio bid y ask, IV, tamaño en contratos y nocional en USD, greeks_abs y greeks_cash (el ejemplo anterior está abreviado). Los valores no disponibles son null; la pata que no forma parte de la actualización se omite. Un Remove incluye currency, expiry, strike, option_type, symbol y timestamp cuando un instrumento se elimina, vence o entra en liquidación al vencimiento pendiente. expiry está en segundos Unix.

Posición vencida (autenticado)​

Se envía en el canal portfolio cuando su posición se liquida al vencimiento.

{
"type": "PositionExpired",
"wallet_address": "0x1234...abcd",
"symbol": "BTC-20260131-100000-C",
"position_size": "10.0",
"settlement_price": "105000",
"settlement_value": "500.0",
"settlement_entry_price": "100.0",
"cost_basis": "1000.0",
"net_pnl": "-500.0",
"timestamp": 1738281600000
}

settlement_entry_price, cost_basis y net_pnl son null cuando no están disponibles.

Cambio de estado de liquidación (autenticado)​

Se envía en el canal liquidation cuando cambia el estado de liquidación de su cuenta.

{
"type": "LiquidationStateChange",
"wallet_address": "0x1234...abcd",
"previous_state": "healthy",
"new_state": "pre_liquidation",
"liquidation_mode": "partial",
"margin_mode": "standard",
"equity": "10000.0",
"mm_required": "10500.0",
"maintenance_margin": "-500.0",
"shortfall": "500.0",
"partial_liquidation": { "...": "..." },
"full_liquidation": null,
"timestamp": 1737331200000
}
CampoDescripción
previous_state, new_statehealthy, pre_liquidation, in_liquidation o liquidated
liquidation_modepartial, full, o null cuando no hay ningún flujo de liquidación activo
margin_modestandard o portfolio
equityPatrimonio de la cuenta
mm_requiredRequisito de margen de mantenimiento
maintenance_marginPatrimonio menos el requisito de margen de mantenimiento
shortfallImporte por el que la cuenta está por debajo del margen de mantenimiento
partial_liquidationProgreso de la liquidación parcial (hora de entrada, patrimonio objetivo, plazo de escalado, órdenes de liquidación activas, bonificación), o null
full_liquidationDetalles de la subasta de liquidación total (ID de subasta, hora de inicio, margen necesario y, al completarse, el ganador, la bonificación y la transacción de resolución), o null

Consulte Liquidación para saber qué significa cada estado.

Actualización de precios índice​

Precios spot/índice agrupados para todos los activos subyacentes.

{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50", "timestamp": 1737331200000},
{"underlying": "ETH", "price": "3200.00", "timestamp": 1737331199980},
{"underlying": "NVDA", "price": "182.40", "timestamp": 1737331199950}
],
"timestamp": 1737331199950
}
CampoTipoDescripción
pricesarrayArray de entradas {underlying, price, timestamp} para cada activo subyacente seguido
prices[].underlyingstringSímbolo del activo subyacente (p. ej., "BTC", "ETH")
prices[].pricestringPrecio spot/índice actual en USD
prices[].timestampintegerHora de observación en la fuente para este activo subyacente, en milisegundos Unix
timestampintegerHora de observación en la fuente más antigua incluida en prices, en milisegundos Unix

Datos de mercado indicativos​

Stream de proveedores de cotizaciones en lista de permitidos, con el mejor bid/ask agregado de los proveedores de cotizaciones registrados. Este canal aún no está disponible de forma general. Use los datos de mercado REST y los canales autenticados de órdenes/ejecuciones/portafolio, salvo que Hypercall haya habilitado el streaming de proveedores de cotizaciones para su integración.

{
"type": "IndicativeMarketData",
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"indicative_bid_size": "50.0",
"indicative_ask_size": "25.0",
"num_providers": 3,
"published_at": 1737331200004,
"timestamp": 1737331200000
}
CampoTipoDescripción
instrumentstringSímbolo de la opción
best_bidstringMejor precio bid agregado, opcional
best_askstringMejor precio ask agregado, opcional
bid_ivnumberVolatilidad implícita del mejor bid, opcional
ask_ivnumberVolatilidad implícita del mejor ask, opcional
indicative_bid_sizestringTamaño bid total entre proveedores, opcional
indicative_ask_sizestringTamaño ask total entre proveedores, opcional
num_providersintegerNúmero de proveedores de cotizaciones activos
rfq_provider_quotesarrayCotizaciones por proveedor, opcional: wallet, bid_price, ask_price, max_bid_size, max_ask_size, updated_at
published_atintegerHora del reloj de la API en que se publicó esta fila, en milisegundos Unix. Mida la antigüedad de rfq_provider_quotes respecto a este valor, no respecto a su reloj local
timestampintegerHora de la última cotización del proveedor, en milisegundos Unix

Lote de datos de mercado indicativos​

Se envía en el canal indicative_market_data_v2 (consulte Entrega por lotes). Cada elemento de updates tiene los mismos campos que un mensaje IndicativeMarketData, sin type.

{
"type": "IndicativeMarketDataBatch",
"flushed_at": 1737331200025,
"updates": [
{
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"num_providers": 3,
"published_at": 1737331200004,
"timestamp": 1737331200000
},
{
"instrument": "BTC-20260131-105000-C",
"best_bid": "0.0310",
"best_ask": "0.0322",
"num_providers": 2,
"published_at": 1737331200004,
"timestamp": 1737331200001
}
]
}
CampoTipoDescripción
flushed_atintegerHora del reloj de la API en que se envió el lote, en milisegundos Unix. flushed_at - published_at es el retraso por agrupamiento de una fila
updatesarrayFilas publicadas durante la ventana, de la más antigua a la más reciente

Cotizaciones RFQ (autenticado)​

Cotizaciones recibidas en respuesta a su solicitud RFQ.

{
"type": "RfqQuotes",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"quotes": [
{
"quote_id": "660e8400-e29b-41d4-a716-446655440001",
"net_premium": "52.30",
"expires_at": 1737331225000
}
],
"status": "quoted",
"taker_wallet": "0x1234...abcd"
}

Actualización de estado de RFQ (autenticado)​

Cambio de estado de un RFQ que usted envió.

{
"type": "RfqStatusUpdate",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "executed",
"taker_wallet": "0x1234...abcd"
}

Sincronización de reloj​

Envíe ClockSync con cualquier cadena nonce para obtener una muestra del reloj de la API en la misma conexión, por ejemplo para acotar el retraso de transporte:

{"type": "ClockSync", "nonce": "abc"}
{"type": "ClockSynced", "nonce": "abc", "server_at": 1737331200000}

server_at está en milisegundos Unix. No requiere autenticación.

Error​

Mensaje de error del servidor. Base su lógica en code cuando esté presente, no en message.

{
"type": "Error",
"message": "Unknown channel 'foobar'",
"code": "unknown_channel",
"channel": "foobar"
}
CampoTipoDescripción
messagestringDescripción legible
codestringMotivo estable, opcional. unknown_channel: un Subscribe indicó un canal que no existe
channelstringOpcional. El canal indicado por un Subscribe rechazado

Un Subscribe a un canal que no figura en Canales disponibles recibe el error unknown_channel, y no se crea ninguna suscripción. Los servidores anteriores confirmaban cualquier nombre y luego no enviaban nada.

Los demás errores solo incluyen message. Ejemplos: Authentication required for this channel cuando se suscribe a un canal autenticado antes de Authenticate, Not authenticated para PlaceOrder antes de Authenticate, e Invalid wallet address: ....

Autenticación​

Los canales autenticados requieren un mensaje de identificación de la wallet después de conectarse:

{"type": "Authenticate", "wallet": "0x1234567890abcdef..."}

Los mensajes de los canales autenticados se filtran para mostrar solo los datos de su wallet. Las conexiones WebSocket no requieren firma.

Ejemplo: cliente en Python​

import asyncio
import websockets
import json

async def main():
uri = "wss://api.hypercall.xyz/ws"

async with websockets.connect(uri) as ws:
# Identify the wallet before subscribing to authenticated channels.
await ws.send(json.dumps({
"type": "Authenticate",
"wallet": "0xYourWallet"
}))

# Subscribe to orderbook
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "orderbook"
}))

# Subscribe to fills for BTC only
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "fills",
"symbols": ["BTC"]
}))

# Listen for messages
async for message in ws:
data = json.loads(message)
print(f"Received: {data['type']}")

asyncio.run(main())

Ejemplo: cliente en TypeScript​

const ws = new WebSocket("wss://api.hypercall.xyz/ws");

ws.onopen = () => {
ws.send(JSON.stringify({ type: "Authenticate", wallet: "0xYourWallet" }));

// Subscribe to channels
ws.send(JSON.stringify({ type: "Subscribe", channel: "orderbook" }));

// Subscribe to order updates filtered to BTC
ws.send(JSON.stringify({
type: "Subscribe",
channel: "order_updates",
symbols: ["BTC"],
}));
};

ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(`Received: ${msg.type}`);

if (msg.type === "OrderbookUpdate") {
console.log(`${msg.symbol}: ${msg.bids.length} bids, ${msg.asks.length} asks`);
}
};

Ejemplo: cliente en Rust​

El WsClient del crate hypercall-client identifica la wallet, restaura las suscripciones tras una reconexión y responde por usted a los pings del servidor. Ofrece compresión permessage-deflate por defecto y recurre a frames sin comprimir cuando el servidor no la acepta, con los mismos mensajes JSON en ambos casos. Llame a with_permessage_deflate(false) para dejar de ofrecerla.

use hypercall_client::WsClient;

#[tokio::main]
async fn main() -> hypercall_client::Result<()> {
let ws = WsClient::new();
ws.connect("https://api.hypercall.xyz", None).await?;
ws.subscribe(vec!["orderbook", "index_prices"]).await?;

if let Some(msg) = ws.wait_for_message(|_| true, 5_000).await {
println!("Received: {msg:?}");
}
Ok(())
}