Esta página foi traduzida automaticamente. O original em inglês é a versão canônica. Ler em inglês
Pular para o conteúdo principal

WebSocket API

Streaming de dados em tempo real para negociação de opções na Hypercall.

Referência Interativa

Confira a Referência Interativa da WebSocket API para uma experiência de navegação melhor, com exemplos ao vivo e detalhes de schema.

Especificação Legível por Máquina

Baixe a especificação AsyncAPI para uso programático.

Conexão

Conecte-se a wss://HOST/ws:

Endpoints:

  • Produção: wss://api.hypercall.xyz/ws
  • Local: ws://localhost:3000/ws
Status da testnet

A testnet está temporariamente desativada até que a Hypercall adquira mais HYPE de testnet.

Identificação da Carteira

Para receber dados em canais autenticados (ordens, fills, portfólio), identifique sua carteira após conectar enviando uma mensagem Authenticate:

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

O servidor responde com a confirmação:

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

Após receber Authenticated, você pode se inscrever em canais autenticados. Se o endereço da carteira for inválido, o servidor responde com uma mensagem Error e a conexão permanece aberta.

Descontinuado: Autenticação por Parâmetro de Query

O parâmetro de query ?wallet= ainda é suportado para compatibilidade retroativa, mas está descontinuado e será removido em uma versão futura. Prefira a abordagem baseada em mensagens acima.

Vitalidade da Conexão

O servidor impõe um heartbeat de WebSocket:

  • Envia um frame de controle Ping a cada 20 segundos
  • Espera um Pong correspondente dentro de 60 segundos
  • Fecha a conexão com o código de fechamento 1008 e o motivo pong timeout se o cliente parar de responder

As implementações de WebSocket de navegadores lidam com ping/pong automaticamente. Muitas bibliotecas de websocket em Rust, incluindo tungstenite e tokio-tungstenite, também lidam com o ping/pong de frames de controle para você. Consulte a documentação da biblioteca do seu cliente antes de adicionar tratamento manual de Pong. Implementações customizadas ou de socket bruto devem responder a frames Ping com Pong.

Recuperação de Consumidor Lento

O servidor fecha uma conexão /ws que não consegue drenar dados de saída dentro do teto de segurança configurado de mensagens, bytes codificados, idade da fila ou escrita no socket. Quando a conexão ainda consegue aceitar um frame de fechamento, o servidor usa o código 1008 e um motivo JSON compacto:

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

Os campos do motivo são:

CampoSignificado
classClasse de entrega cujo frame cruzou o limite de segurança.
causemessage_limit, byte_limit, message_age ou write_timeout.
recoveryPróxima ação necessária, como resubscribe, snapshot_resubscribe, portfolio_refetch ou rest_reconcile.

Após qualquer desconexão, reconecte, identifique a carteira novamente quando necessário, reinscreva-se e reconcilie o estado atual antes de processar novos eventos. Canais públicos ordenados exigem um novo snapshot. Canais de eventos privados exigem reconciliação através da superfície REST autoritativa, porque o replay de cursor ainda não está disponível. Uma conexão totalmente travada pode terminar antes de conseguir ler o motivo do fechamento, então os clientes devem usar esse fluxo de recuperação também para um fechamento não limpo.

Use conexões separadas para dados de mercado públicos de alta taxa e comandos autenticados ou streams privados. As classes de entrega selecionam métricas e comportamento de recuperação, mas os frames em uma conexão ainda compartilham um único caminho ordenado de escrita no socket. Uma escrita pública travada pode, portanto, atrasar frames privados posteriores nessa mesma conexão até que o deadline de escrita a feche.

Inscrição em Canais

Envie uma mensagem JSON para se inscrever:

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

Para cancelar a inscrição:

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

Você receberá uma confirmação:

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

Filtragem por Símbolo

Os canais order_updates e fills suportam um filtro symbols opcional. Quando fornecido, o servidor só envia mensagens cujo ativo subjacente corresponde a um dos símbolos especificados.

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

Tanto ativos subjacentes simples ("BTC") quanto nomes completos de instrumentos ("BTC-20260131-100000-C") são aceitos. Para adicionar mais símbolos, envie outro Subscribe. Para remover símbolos específicos:

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

Quando nenhum symbols é especificado, todas as atualizações da sua carteira são encaminhadas.

Filtragem da Cadeia de Opções

O canal options_chain suporta filtragem por símbolos de ativo subjacente, data de vencimento e tipo de opção:

{
"type": "Subscribe",
"channel": "options_chain",
"symbols": ["BTC-20260131-100000-C"],
"expiry": "2026-01-31",
"option_type": "call"
}
FiltroValoresPadrão
symbolsArray de símbolos completos de instrumentos (ex.: ["BTC-20260131-100000-C"])Todos os instrumentos
expiryString de data "YYYY-MM-DD"Todos os vencimentos
option_type"call", "put" ou omita para ambosAmbos

Canais Disponíveis

CanalAutenticação NecessáriaDescrição
orderbookNãoAtualizações de livro de ofertas L2 para todos os símbolos
tradesNãoFeed público de negociações
market_updatesNãoMudanças de listagem de mercado (criado/excluído/vencido)
options_chainNãoAtualizações incrementais da cadeia de opções (filtrável por symbols, expiry, option_type)
index_pricesNãoPreços spot/índice em tempo real para todos os ativos subjacentes
indicative_market_dataNãoStream de provedor de cotações em allowlist. Ainda não disponível de forma geral
order_updatesSimMudanças de status das suas ordens (filtrável por símbolo)
fillsSimSeus fills de negociação (filtrável por símbolo)
portfolioSimAtualizações da sua posição e saldo
liquidationSimMudanças no seu estado de liquidação
competitionSimSeu resumo de PnL de competição, rank e estatísticas finais
competition_engagementSimMudanças de rank, gap para o próximo rank e classificação final
rfqSimCotações de RFQ, atualizações de status e notificações de fill

Tipos de Mensagem

Enviar Ordem (Autenticado)

Envie uma ordem através do caminho de comando da 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..."
}
CampoTipoDescrição
walletstringEndereço da carteira que é dona da ordem
symbolstringSímbolo da opção
sidestring"Buy" ou "Sell"
sizestringTamanho do contrato, correspondendo exatamente ao valor assinado
pricestringPreço limite, correspondendo exatamente ao valor assinado
tifstringTime-in-force opcional, padrão "gtc"
routestringRota opcional. Use "book_only" para ordens WebSocket cientes de rota. A omissão da rota permanece aceita até pelo menos 4 de julho de 2026.
client_idstringID de ordem do cliente opcional
nonceintegerNonce único de assinatura
signaturestringAssinatura EIP-712 PlaceOrder

O PlaceOrder da WebSocket atualmente despacha diretamente para o livro de ofertas. route="best_execution" e route="rfq_only" são rejeitados na WebSocket porque esse caminho ainda não executa roteamento RPI/RFQ. Use POST /order para best_execution.

Atualização do Livro de Ofertas

Snapshot/atualização de livro de ofertas L2 para um 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
}
CampoTipoDescrição
symbolstringSímbolo da opção
bidsarrayNíveis de bid como tuplas [price, size], o tamanho é em contratos legíveis por humanos
asksarrayNíveis de ask como tuplas [price, size], o tamanho é em contratos legíveis por humanos
timestampintegerTimestamp Unix (milissegundos)

Negociação

Evento público de negociação.

{
"type": "Trade",
"symbol": "BTC-20260131-100000-C",
"price": "0.0523",
"size": "5.0",
"side": "buy",
"timestamp": 1737331200000
}
CampoTipoDescrição
symbolstringSímbolo da opção
pricestringPreço da negociação em USD
sizestringTamanho da negociação em contratos
sidestringLado agressor (buy ou sell)
timestampintegerTimestamp Unix (milissegundos)

Fill (Autenticado)

Notificação do seu fill de negociação.

{
"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
}
CampoTipoDescrição
order_idintegerID da sua ordem
fill_idintegerID da execução
symbolstringSímbolo da opção
sidestringLado da negociação (buy ou sell)
pricestringPreço da execução em USD
sizestringTamanho da execução em contratos
timestampintegerTimestamp Unix (milissegundos)
wallet_addressstringEndereço da sua carteira
feestringTaxa de negociação cobrada. Retorna 0 enquanto as taxas do venue de lançamento estiverem desativadas
trade_idintegerID único da negociação
is_takerbooleanSe você foi o taker
builder_code_addressstring?Carteira do builder code (se houver)
builder_code_feestring?Taxa do builder code. Retorna null enquanto as taxas do venue de lançamento estiverem desativadas

Atualização de Portfólio (Autenticado)

Atualização do stream de portfólio para posições, saldos, margem e Greeks.

Exemplo de atualização 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 portfólios vazios, as atualizações de Greeks usam:

  • per_leg: []
  • aggregate: null

Resumo de PnL da Competição (Autenticado)

Atualização do stream de competição para exibição de PnL no cabeçalho/rodapé.

{
"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
}

Quando não há competição ativa, active_competition é null.

Atualização de Ordem (Autenticado)

Notificação de mudança de status da ordem.

{
"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"
}

Atualização de Mercado

Mudanças na listagem de mercados.

Mercado Criado:

{
"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
}

Posição Vencida (Autenticado)

Notificação quando sua posição é liquidada no vencimento.

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

Mudança de Estado de Liquidação (Autenticado)

Mudança no estado de liquidação da sua conta.

{
"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
}
EstadoDescrição
NormalA conta está saudável
WarningAproximando-se da chamada de margem
LiquidatingLeilão de liquidação ativo

Atualização de Preço de Índice

Preços spot/índice agrupados para todos os ativos subjacentes.

{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50"},
{"underlying": "ETH", "price": "3200.00"},
{"underlying": "HYPE", "price": "28.50"}
],
"timestamp": 1737331200000
}
CampoTipoDescrição
pricesarrayArray de entradas {underlying, price} para cada ativo subjacente rastreado
prices[].underlyingstringSímbolo do ativo subjacente (ex.: "BTC", "ETH")
prices[].pricestringPreço spot/índice atual em USD
timestampintegerTimestamp Unix (milissegundos)

Dados de Mercado Indicativos

Stream de provedores de cotações na allowlist com melhor bid/ask agregado dos provedores de cotações registrados. Este canal ainda não está disponível de forma geral. Use os dados de mercado via REST e os canais autenticados de ordem/execução/portfólio, a menos que a Hypercall tenha habilitado o streaming de provedores de cotações para a sua integração.

{
"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
}
CampoTipoDescrição
instrumentstringSímbolo da opção
best_bidstringMelhor preço de bid agregado (opcional)
best_askstringMelhor preço de ask agregado (opcional)
bid_ivnumberVolatilidade implícita do melhor bid (opcional)
ask_ivnumberVolatilidade implícita do melhor ask (opcional)
indicative_bid_sizestringTamanho total de bid entre os provedores (opcional)
indicative_ask_sizestringTamanho total de ask entre os provedores (opcional)
num_providersintegerNúmero de provedores de cotações ativos
timestampintegerTimestamp Unix (milissegundos)

Mudança de Rank na Competição (Autenticado)

Notificação quando seu rank muda em uma competição ativa.

{
"type": "CompetitionRankChange",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"from_rank": 15,
"to_rank": 12,
"delta_places": 3,
"pnl": "420.25",
"timestamp": 1737331200000
}

Atualização de Gap da Competição (Autenticado)

Distância até o rank imediatamente acima do seu.

{
"type": "CompetitionGapUpdate",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"next_rank": 11,
"gap_metric_value": "50.00",
"timestamp": 1737331200000
}

Classificação Final da Competição (Autenticado)

Enviada quando uma competição termina com seus resultados finais.

{
"type": "CompetitionFinalStanding",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null,
"timestamp": 1737331200000
}

Cotações de RFQ (Autenticado)

Cotações recebidas em resposta à sua submissã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"
}

Atualização de Status de RFQ (Autenticado)

Mudança de status para um RFQ que você submeteu.

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

Erro

Mensagem de erro do servidor.

{
"type": "Error",
"message": "Invalid channel: foobar"
}

Autenticação

Os canais autenticados exigem uma mensagem de identificação de carteira após a conexão:

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

As mensagens nos canais autenticados são filtradas para mostrar apenas os dados da sua carteira. Nenhuma assinatura é necessária para conexões WebSocket.

Exemplo: 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())

Exemplo: 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`);
}
};