WebSocket API
Streaming de datos en tiempo real para el trading de opciones de Hypercall.
Consulte la Referencia interactiva de la WebSocket API para disfrutar de una mejor experiencia de navegación con ejemplos en vivo y detalles de esquema.
Descargue la especificación AsyncAPI para uso programático.
Conexión
Conéctese a wss://HOST/ws:
Endpoints:
- Producción:
wss://api.hypercall.xyz/ws - Local:
ws://localhost:3000/ws
Testnet está temporalmente deshabilitada hasta que Hypercall adquiera más HYPE de testnet.
Identificación de wallet
Para recibir datos en canales autenticados (órdenes, fills, portfolio), 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..."}
Tras recibir Authenticated, puede suscribirse a 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.
El parámetro de consulta ?wallet= todavía se admite por compatibilidad con versiones anteriores, pero está obsoleto y se eliminará en una versión futura. Prefiera el enfoque basado en mensajes descrito arriba.
Vitalidad de la conexión
El servidor aplica un heartbeat de WebSocket:
- Envía un frame de control
Pingcada 20 segundos - Espera un
Pongcorrespondiente dentro de un plazo de 60 segundos - Cierra la conexión con el código de cierre
1008y el motivopong timeoutsi el cliente deja de responder
Las implementaciones de WebSocket de los navegadores gestionan ping/pong automáticamente. Muchas bibliotecas de websocket de Rust, incluidas tungstenite y tokio-tungstenite, también gestionan el ping/pong de frames de control por usted. Consulte la documentación de la biblioteca de su cliente antes de agregar un manejo manual de Pong. Las implementaciones personalizadas o de socket sin procesar deben responder a los frames Ping con Pong.
Recuperación de consumidor lento
El servidor cierra una conexión /ws que no puede drenar los datos salientes dentro del límite de seguridad configurado de mensajes, bytes codificados, antigüedad de cola o escritura de 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:
| Campo | Significado |
|---|---|
class | Clase de entrega cuyo frame cruzó el límite de seguridad. |
cause | message_limit, byte_limit, message_age o write_timeout. |
recovery | Próxima acción requerida, como resubscribe, snapshot_resubscribe, portfolio_refetch o rest_reconcile. |
Después de cualquier desconexión, vuelva a conectarse, identifique la wallet de nuevo cuando sea necesario, vuelva a suscribirse y reconcilie el estado actual antes de procesar nuevos eventos. Los canales públicos ordenados requieren un snapshot nuevo. Los canales de eventos privados requieren reconciliación a través de la superficie REST autoritativa, ya que la reproducción por cursor aún no está disponible. Una conexión totalmente estancada puede terminar antes de poder leer el motivo de cierre, por lo que los clientes deben usar este flujo de recuperación también para un cierre no limpio.
Use conexiones separadas para datos de mercado públicos de alta frecuencia y para comandos autenticados o streams privados. Las clases de entrega seleccionan las métricas y el comportamiento de recuperación, pero los frames de una conexión siguen compartiendo una única ruta ordenada de escritura de socket. Una escritura pública estancada puede, por lo tanto, 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 simples ("BTC") como nombres completos de instrumento ("BTC-20260131-100000-C"). Para agregar más símbolos, envíe otro Subscribe. Para eliminar símbolos específicos:
{"type": "Unsubscribe", "channel": "order_updates", "symbols": ["BTC"]}
Cuando no se especifica ningún symbols, se reenvían todas las actualizaciones de su wallet.
Filtrado de la cadena de opciones
El canal options_chain admite el filtrado por símbolos de activo subyacente, 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"
}
| Filtro | Valores | Predeterminado |
|---|---|---|
symbols | Array de símbolos completos de instrumento (p. ej., ["BTC-20260131-100000-C"]) | Todos los instrumentos |
expiry | Cadena de fecha "YYYY-MM-DD" | Todos los vencimientos |
option_type | "call", "put", u omitir para ambos | Ambos |
Canales disponibles
| Canal | Requiere autenticación | Descripción |
|---|---|---|
orderbook | No | Actualizaciones del libro de órdenes L2 para todos los símbolos |
trades | No | Feed público de operaciones |
market_updates | No | Cambios en el listado de mercados (creado/eliminado/vencido) |
options_chain | No | Actualizaciones incrementales de la cadena de opciones (filtrable por symbols, expiry, option_type) |
index_prices | No | Precios spot/de índice en tiempo real para todos los activos subyacentes |
indicative_market_data | No | Stream de proveedores de cotizaciones en lista de permitidos. Aún no disponible de forma general |
order_updates | Sí | Cambios de estado de sus órdenes (filtrable por símbolo) |
fills | Sí | Sus fills de operaciones (filtrable por símbolo) |
portfolio | Sí | Actualizaciones de sus posiciones y saldos |
liquidation | Sí | Cambios en su estado de liquidación |
competition | Sí | Resumen de su P&L de competición, ranking y estadísticas finales |
competition_engagement | Sí | Cambios de ranking, diferencia con el siguiente puesto y clasificación final |
rfq | Sí | Cotizaciones RFQ, actualizaciones de estado y notificaciones de fills |
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": 1000,
"signature": "0x..."
}
| Campo | Tipo | Descripción |
|---|---|---|
wallet | string | Dirección de wallet propietaria de la orden |
symbol | string | Símbolo de la opción |
side | string | "Buy" o "Sell" |
size | string | Tamaño del contrato, coincidiendo exactamente con el valor firmado |
price | string | Precio límite, coincidiendo exactamente con el valor firmado |
tif | string | Time-in-force opcional, por defecto "gtc" |
route | string | Ruta opcional. Use "book_only" para órdenes WebSocket con reconocimiento de ruta. Una ruta omitida sigue aceptándose al menos hasta el 4 de julio de 2026. |
client_id | string | ID de orden de cliente opcional |
nonce | integer | Nonce de firma único |
signature | string | Firma EIP-712 PlaceOrder |
Actualmente, PlaceOrder de WebSocket despacha directamente al libro de órdenes. route="best_execution" y route="rfq_only" se rechazan en WebSocket porque esta ruta aún no ejecuta el enrutamiento RPI/RFQ. Use POST /order para best_execution.
Actualización del libro de órdenes
Snapshot/actualización del libro de órdenes L2 para un símbolo.
{
"type": "OrderbookUpdate",
"symbol": "BTC-20260131-100000-C",
"bids": [["95000.5", "10.5"], ["94999.0", "25.0"]],
"asks": [["95001.0", "8.0"], ["95002.5", "15.0"]],
"timestamp": 1737331200000
}
| Campo | Tipo | Descripción |
|---|---|---|
symbol | string | Símbolo de la opción |
bids | array | Niveles de bid como tuplas [price, size], el tamaño se expresa en contratos legibles por humanos |
asks | array | Niveles de ask como tuplas [price, size], el tamaño se expresa en contratos legibles por humanos |
timestamp | integer | Timestamp 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
}
| Campo | Tipo | Descripción |
|---|---|---|
symbol | string | Símbolo de la opción |
price | string | Precio de la operación en USD |
size | string | Tamaño de la operación en contratos |
side | string | Lado agresor (buy o sell) |
timestamp | integer | Timestamp Unix (milisegundos) |
Fill (autenticado)
Notificación de su fill de 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
}
| Campo | Tipo | Descripción |
|---|---|---|
order_id | integer | El ID de su orden |
fill_id | integer | ID del fill |
symbol | string | Símbolo de la opción |
side | string | Lado de la operación (buy o sell) |
price | string | Precio del fill en USD |
size | string | Tamaño del fill en contratos |
timestamp | integer | Timestamp Unix (milisegundos) |
wallet_address | string | La dirección de su wallet |
fee | string | Comisión de trading cobrada. Devuelve 0 mientras las comisiones del venue de lanzamiento estén deshabilitadas |
trade_id | integer | ID único de la operación |
is_taker | boolean | Si usted fue el taker |
builder_code_address | string? | Wallet del builder code (si corresponde) |
builder_code_fee | string? | Comisión del builder code. Devuelve null mientras las comisiones del venue de lanzamiento estén deshabilitadas |
Actualización de portafolio (autenticado)
Actualización del stream de portafolio para posiciones, saldos, margen y Greeks.
Ejemplo de actualización de Greeks:
{
"type": "PortfolioUpdate",
"timestamp": 1737331200000,
"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 Greeks usan:
per_leg: []aggregate: null
Resumen de PnL de competencia (autenticado)
Actualización del stream de competencia para mostrar el PnL en el encabezado/pie de página.
{
"type": "CompetitionPnlSummary",
"wallet_address": "0x1234...abcd",
"lifetime_realized_pnl": "1250.50",
"active_competition": {
"competition_id": 7,
"competition_name": "Spring Sprint",
"competition_state": "active",
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null
},
"timestamp": 1737331200000
}
Cuando no hay una competencia activa, active_competition es null.
Actualización de orden (autenticado)
Notificación de cambio de estado de una orden.
{
"type": "OrderUpdate",
"order_id": 12345,
"client_order_id": "my-order-1",
"status": "filled",
"filled_size": "10.0",
"remaining_size": "0",
"avg_fill_price": "0.0523"
}
Actualización de mercado
Cambios en el listado 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
}
Posición vencida (autenticado)
Notificación 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",
"timestamp": 1738281600000
}
Cambio de estado de liquidación (autenticado)
Cambio en el estado de liquidación de su cuenta.
{
"type": "LiquidationStateChange",
"wallet_address": "0x1234...abcd",
"previous_state": "Normal",
"new_state": "Warning",
"equity": "10000.0",
"mm_required": "9500.0",
"shortfall": "0",
"auction_id": null,
"timestamp": 1737331200000
}
| Estado | Descripción |
|---|---|
Normal | La cuenta está saludable |
Warning | Se aproxima a un margin call |
Liquidating | Subasta de liquidación activa |
Actualización de precio índice
Precios spot/índice agrupados para todos los activos subyacentes.
{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50"},
{"underlying": "ETH", "price": "3200.00"},
{"underlying": "HYPE", "price": "28.50"}
],
"timestamp": 1737331200000
}
| Campo | Tipo | Descripción |
|---|---|---|
prices | array | Array de entradas {underlying, price} para cada activo subyacente rastreado |
prices[].underlying | string | Símbolo del activo subyacente (p. ej., "BTC", "ETH") |
prices[].price | string | Precio spot/índice actual en USD |
timestamp | integer | Timestamp Unix (milisegundos) |
Datos de mercado indicativos
Stream de proveedores de cotizaciones en lista de acceso permitido 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 orden/fill/portafolio a menos 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,
"timestamp": 1737331200000
}
| Campo | Tipo | Descripción |
|---|---|---|
instrument | string | Símbolo de la opción |
best_bid | string | Mejor precio bid agregado (opcional) |
best_ask | string | Mejor precio ask agregado (opcional) |
bid_iv | number | Volatilidad implícita del mejor bid (opcional) |
ask_iv | number | Volatilidad implícita del mejor ask (opcional) |
indicative_bid_size | string | Tamaño total del bid entre proveedores (opcional) |
indicative_ask_size | string | Tamaño total del ask entre proveedores (opcional) |
num_providers | integer | Número de proveedores de cotizaciones activos |
timestamp | integer | Timestamp Unix (milisegundos) |
Cambio de rango en competencia (autenticado)
Notificación cuando su rango cambia en una competencia activa.
{
"type": "CompetitionRankChange",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"from_rank": 15,
"to_rank": 12,
"delta_places": 3,
"pnl": "420.25",
"timestamp": 1737331200000
}
Actualización de diferencia en competencia (autenticado)
Distancia hasta el siguiente rango por encima de usted.
{
"type": "CompetitionGapUpdate",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"next_rank": 11,
"gap_metric_value": "50.00",
"timestamp": 1737331200000
}
Clasificación final de competencia (autenticado)
Se envía cuando una competencia termina con sus resultados finales.
{
"type": "CompetitionFinalStanding",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null,
"timestamp": 1737331200000
}
Cotizaciones RFQ (autenticado)
Cotizaciones recibidas en respuesta a su envío de 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"
}
Error
Mensaje de error del servidor.
{
"type": "Error",
"message": "Invalid channel: foobar"
}
Autenticación
Los canales autenticados requieren un mensaje de identificación de wallet después de conectarse:
{"type": "Authenticate", "wallet": "0x1234567890abcdef..."}
Los mensajes en canales autenticados se filtran para mostrar únicamente los datos de su wallet. No se requiere firma para las conexiones WebSocket.
Ejemplo: Cliente 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 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`);
}
};