Skip to main content

📖 Descrição

Endpoint de Server-Sent Events (SSE) que transmite periodicamente um snapshot completo de todos os preços atualmente armazenados no RealtimePriceCache. O snapshot é emitido a cada 1 segundo, contendo ask/bid/volume de todos os pares de todas as exchanges com conexão WebSocket ativa.
O endpoint /v1/realtime/arbitrage emite apenas oportunidades (pares com spread positivo). Este endpoint /v1/realtime/prices emite todos os preços do cache independentemente de haver arbitragem — ideal para dashboards de monitoramento de mercado.

🛠️ Requisição

Método

GET

URL

/v1/realtime/prices

Headers Necessários

HeaderValor
Accepttext/event-stream
Cache-Controlno-cache

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/prices'

Exemplo de Requisição (JavaScript)

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

source.onmessage = (event) => {
    const snapshot = JSON.parse(event.data);
    // snapshot é um array de entradas de preço
    snapshot.forEach(entry => {
        console.log(`${entry.ticker} @ ${entry.exchange}: ask=${entry.ask} bid=${entry.bid}`);
    });
};

source.onerror = () => {
    // EventSource reconecta automaticamente
};

// Ao desmontar:
// source.close();

📤 Resposta

Headers da Resposta

HeaderValor
Content-Typetext/event-stream
Cache-Controlno-cache
Connectionkeep-alive
X-Accel-Bufferingno

Frequência de Emissão

Um evento é emitido a cada 1 segundo enquanto a conexão estiver aberta.

Formato dos Eventos SSE

data: [{"ticker":"BTC-USDT","exchange":"Binance","ask":43380.00,"bid":43375.50,...}, ...]

data: [{"ticker":"BTC-USDT","exchange":"Binance","ask":43381.00,"bid":43376.00,...}, ...]

Estrutura do Payload JSON

O payload é um array de entradas de preço:
[
  {
    "ticker": "BTC-USDT",
    "exchange": "Binance",
    "ask": 43380.00,
    "bid": 43375.50,
    "askQty": 0.012,
    "bidQty": 0.085,
    "volume": 28543.12,
    "updatedAt": "2025-03-18T12:00:00.000Z"
  },
  {
    "ticker": "ETH-USDT",
    "exchange": "Binance",
    "ask": 2258.10,
    "bid": 2257.90,
    "askQty": 1.25,
    "bidQty": 0.75,
    "volume": 145230.00,
    "updatedAt": "2025-03-18T12:00:00.000Z"
  }
]

Campos de Cada Entrada

CampoTipoDescrição
tickerstringPar de trading normalizado (ex: BTC-USDT)
exchangestringNome da exchange de origem
askfloatMelhor preço de venda (ask)
bidfloatMelhor preço de compra (bid)
askQtyfloatQuantidade disponível no ask
bidQtyfloatQuantidade disponível no bid
volumefloatVolume de 24h (seed REST, refresh a cada 60s)
updatedAtstring (ISO 8601)Timestamp do último tick WebSocket

💡 Casos de Uso

Dashboard de Preços ao Vivo

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

function usePricesSnapshot() {
    const [prices, setPrices] = useState([]);

    useEffect(() => {
        const source = new EventSource(
            `${import.meta.env.VITE_API_URL}/v1/realtime/prices`
        );

        source.onmessage = (event) => {
            setPrices(JSON.parse(event.data));
        };

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

    return prices;
}

Filtrar Preços por Exchange

source.onmessage = (event) => {
    const all = JSON.parse(event.data);
    const binancePrices = all.filter(e => e.exchange === 'Binance');
    updateTable(binancePrices);
};

Calcular Spread Manualmente

source.onmessage = (event) => {
    const all = JSON.parse(event.data);
    
    // Agrupar por ticker
    const byTicker = {};
    all.forEach(entry => {
        if (!byTicker[entry.ticker]) byTicker[entry.ticker] = [];
        byTicker[entry.ticker].push(entry);
    });

    // Para cada ticker, encontrar melhor compra e venda
    Object.entries(byTicker).forEach(([ticker, entries]) => {
        const minAsk = Math.min(...entries.map(e => e.ask));
        const maxBid = Math.max(...entries.map(e => e.bid));
        const spread = (maxBid - minAsk) / minAsk * 100;

        if (spread > 0) {
            console.log(`${ticker}: spread ${spread.toFixed(2)}%`);
        }
    });
};

⚠️ Considerações de Performance

Este endpoint emite um payload potencialmente grande (todos os pares de todas as exchanges) a cada segundo. Use-o com moderação — em produção, prefira o endpoint /v1/realtime/arbitrage que emite apenas as oportunidades relevantes.
Volume estimado de dados:
  • Fase 1 (Binance): ~850 pares × 1 exchange ≈ ~150 KB/s por cliente
  • Fase 2 (6 exchanges): ~800 pares × 6 exchanges ≈ ~900 KB/s por cliente
  • Fase 3 (12 exchanges): considere paginação ou filtragem por exchange
Para interfaces de usuário, filtre o stream no servidor ou adicione um parâmetro de query exchange para receber apenas os preços de interesse — evitando tráfego desnecessário.