Skip to main content

📖 Descrição

Endpoint de Server-Sent Events (SSE) que transmite oportunidades de arbitragem detectadas pelo motor WebSocket em tempo real. Cada evento representa uma oportunidade identificada após o debounce de 200ms por símbolo.
SSE é uma conexão HTTP persistente unidirecional. O browser se reconecta automaticamente em caso de queda. Use a API nativa EventSource para consumir este endpoint — não é necessário WebSocket do lado do cliente.

🛠️ Requisição

Método

GET

URL

/v1/realtime/arbitrage

Headers Necessários

HeaderValorDescrição
Accepttext/event-streamIndica que o cliente aceita SSE
Cache-Controlno-cacheDesabilita cache intermediário

Parâmetros

Nenhum.

Exemplo de Requisição (curl)

curl --location --no-buffer \
  -H "Accept: text/event-stream" \
  -H "Cache-Control: no-cache" \
  'localhost:8080/v1/realtime/arbitrage'

Exemplo de Requisição (JavaScript)

const source = new EventSource('/v1/realtime/arbitrage');

source.onmessage = (event) => {
    const opportunity = JSON.parse(event.data);
    console.log('Nova oportunidade:', opportunity);
};

source.onerror = (err) => {
    console.error('Erro SSE, reconectando...', err);
    // EventSource reconecta automaticamente
};

// Ao desmontar o componente React:
// source.close();

📤 Resposta

Headers da Resposta

HeaderValor
Content-Typetext/event-stream
Cache-Controlno-cache
Connectionkeep-alive
X-Accel-Bufferingno
O header X-Accel-Buffering: no é necessário para que Nginx (ou proxies similares) não bufferizem a resposta, garantindo entrega imediata dos eventos.

Formato dos Eventos SSE

Cada evento segue o protocolo SSE padrão:
data: {"ticker":"BTC-USDT","buyExchange":"Binance","sellExchange":"OKX",...}

data: {"ticker":"ETH-USDT","buyExchange":"Bybit","sellExchange":"Binance",...}

Estrutura do Payload JSON

{
  "ticker": "BTC-USDT",
  "buyExchange": "Binance",
  "sellExchange": "OKX",
  "buyPrice": 43250.50,
  "sellPrice": 43380.00,
  "profitPercentAskBid": 0.30,
  "volume": 1523.45,
  "timestamp": "2025-03-18T12:00:00.000Z"
}

Campos do Payload

CampoTipoDescrição
tickerstringPar de trading (ex: BTC-USDT)
buyExchangestringExchange onde comprar (preço mais baixo)
sellExchangestringExchange onde vender (preço mais alto)
buyPricefloatPreço de compra (ask) na exchange de compra
sellPricefloatPreço de venda (bid) na exchange de venda
profitPercentAskBidfloatSpread de lucro em percentual
volumefloatVolume de 24h (do cache, atualizado a cada 60s)
timestampstring (ISO 8601)Momento da detecção

🔄 Ciclo de Vida da Conexão

Cliente → GET /v1/realtime/arbitrage
Server  → 200 OK (headers SSE)
          Connection mantida aberta

Server  → data: {...oportunidade...}\n\n   (quando detectada)
Server  → data: {...oportunidade...}\n\n   (quando detectada)
          ...
Cliente → Fecha conexão (ou perde rede)
Server  → Remove cliente do broadcaster
O SSEBroadcaster suporta múltiplos clientes simultâneos via fan-out. Cada cliente recebe um canal dedicado — a lentidão de um cliente não impacta os demais.

⚠️ Considerações

Este endpoint requer ENABLED_WEBSOCKET=1 no ambiente. Se o fluxo WebSocket não estiver ativo, a conexão SSE será estabelecida mas nenhum evento será emitido até que algum handler WebSocket detecte uma oportunidade.

Exemplo de Integração React

import { useEffect, useRef, useState } from 'react';

const BASE_API_URL = import.meta.env.VITE_API_URL;
const MAX_OPPORTUNITIES = 50;

function useRealtimeArbitrage() {
    const [opportunities, setOpportunities] = useState([]);
    const sourceRef = useRef(null);

    useEffect(() => {
        const source = new EventSource(`${BASE_API_URL}/v1/realtime/arbitrage`);
        sourceRef.current = source;

        source.onmessage = (event) => {
            const data = JSON.parse(event.data);
            setOpportunities(prev => [data, ...prev].slice(0, MAX_OPPORTUNITIES));
        };

        return () => source.close();
    }, []);

    return opportunities;
}