> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arbitragem-crypto.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Arbitragem em Tempo Real via WebSocket

> Fluxo paralelo de integração com exchanges via WebSocket e entrega de oportunidades ao browser via Server-Sent Events

# Arbitragem em Tempo Real via WebSocket

<Callout title="Fluxo Aditivo" icon="zap" color="green">
  O fluxo WebSocket é **completamente independente** do fluxo REST existente. Ambos rodam em paralelo — o WebSocket adiciona latência ultrabaixa sem afetar a estabilidade do processamento REST de 19 segundos.
</Callout>

## 🎯 Visão Geral

O sistema possui dois fluxos de integração complementares:

| Característica      | Fluxo REST (existente) | Fluxo WebSocket (novo)          |
| ------------------- | ---------------------- | ------------------------------- |
| Frequência          | A cada 19 segundos     | Contínuo (event-driven)         |
| Latência            | \~10–19 s              | \< 200 ms                       |
| Exchanges           | 17 (polling)           | 12 (fase 1–3) + 5 (REST-only)   |
| Entrega ao frontend | HTTP polling           | Server-Sent Events (SSE)        |
| Persistência        | MongoDB (`operacoes`)  | MongoDB (`operations_realtime`) |
| Ativação            | Sempre ativo           | `ENABLED_WEBSOCKET=1`           |

## 🏗️ Arquitetura dos Componentes

```mermaid theme={null}
graph TD
    A[Exchange WebSocket] -->|ticks bid/ask| B[WebSocketExchangeHandler]
    B -->|PriceUpdateCallback| C[RealtimePriceCache]
    C -->|updates channel| D[RealtimeArbitrageEngine]
    D -->|debounce 200ms| E{CompareBaseQuotePrices}
    E -->|oportunidade| F[MongoDB operations_realtime]
    E -->|oportunidade| G[SSEBroadcaster]
    G -->|fan-out| H[Browser EventSource]
    G -->|fan-out| I[Browser EventSource]
    G -->|fan-out| J[Browser EventSource]
```

### Componentes Principais

<CardGroup cols={2}>
  <Card title="WebSocketExchangeHandler" icon="plug">
    Interface contratual para cada exchange. Implementa `Connect()`, `Name()` e `HealthCheck()`. Cada exchange tem sua própria implementação.
  </Card>

  <Card title="RealtimePriceCache" icon="database">
    Cache thread-safe em memória. Preserva volume REST quando o tick WebSocket não o fornece. Fornece `GetAll()` no mesmo formato do fluxo REST.
  </Card>

  <Card title="RealtimeArbitrageEngine" icon="microchip">
    Motor de detecção. Debounce de 200ms por símbolo evita processamento excessivo. Reutiliza `CompareBaseQuotePrices()` do fluxo REST sem duplicação de código.
  </Card>

  <Card title="SSEBroadcaster" icon="paper-plane">
    Fan-out de Server-Sent Events para todos os browsers conectados. Cada cliente recebe um canal dedicado com backpressure automático.
  </Card>

  <Card title="WebSocketManager" icon="server">
    Singleton orquestrador. Gerencia reconexão automática com backoff exponencial (1s → 2s → 4s → 8s → 16s máx).
  </Card>
</CardGroup>

## 🔄 Fluxo de Dados Detalhado

### 1. Conexão e Seed de Volume

Ao conectar, o handler WebSocket da Binance:

1. Chama a REST API pública para buscar snapshot de volume (24h) de todos os pares
2. Alimenta o `RealtimePriceCache` com os dados iniciais
3. Abre conexão WebSocket: `wss://stream.binance.com:9443/ws`
4. Subscreve o stream `!bookTicker` (todos os pares, bid/ask em tempo real)
5. Inicia timer de 60s para refresh periódico do volume via REST

```go theme={null}
// Subscription message sent to Binance
{
  "method": "SUBSCRIBE",
  "params": ["!bookTicker"],
  "id": 1
}
```

### 2. Processamento de Ticks

```mermaid theme={null}
sequenceDiagram
    participant WS as WebSocket Exchange
    participant H as Handler
    participant C as Cache
    participant E as Engine
    participant B as Broadcaster

    WS->>H: tick {symbol, ask, bid}
    H->>H: nameNormalization(symbol)
    H->>C: Set(exchange, symbol, entry)
    C->>C: preservar volume se entry.Volume==0
    C->>E: updates channel (cap 2048)
    E->>E: scheduleEvaluation(symbol, 200ms debounce)
    E->>E: CompareBaseQuotePrices(cache.GetAll())
    E->>B: Broadcast(opportunity JSON)
    B->>B: fan-out para todos os clientes SSE
```

### 3. Reconexão Automática

```
Falha na conexão
    ↓
Aguarda 1s → Tenta reconectar
    ↓ (falha)
Aguarda 2s → Tenta reconectar
    ↓ (falha)
Aguarda 4s → Tenta reconectar
    ↓ (falha)
Aguarda 8s → Tenta reconectar
    ↓ (falha)
Aguarda 16s → Tenta reconectar (máximo)
    ↓ (sucesso)
Reset do backoff → Monitora continuamente
```

## ⚡ Ativação

O fluxo WebSocket é controlado por variável de ambiente para garantir zero impacto em produção enquanto não estiver pronto:

```bash theme={null}
# Habilitar o fluxo WebSocket
ENABLED_WEBSOCKET=1

# ou
ENABLED_WEBSOCKET=true
```

<Callout title="Desativado por padrão" icon="info-circle" color="blue">
  Se `ENABLED_WEBSOCKET` não estiver definido ou for qualquer outro valor, o fluxo WebSocket não é iniciado e nenhum recurso adicional é consumido.
</Callout>

```go theme={null}
// cmd/main.go — inicialização condicional
func setupWebSocket() {
    enabledWS := os.Getenv("ENABLED_WEBSOCKET")
    if enabledWS == "1" || enabledWS == "true" {
        go application.StartWebSocketFlow()
    }
}
```

## 📡 Endpoints SSE

Cinco endpoints HTTP expõem os dados do fluxo WebSocket:

| Endpoint                      | Tipo       | Descrição                                             |
| ----------------------------- | ---------- | ----------------------------------------------------- |
| `GET /v1/realtime/status`     | JSON       | Status de cada handler WebSocket                      |
| `GET /v1/realtime/arbitrage`  | SSE stream | Oportunidades de arbitragem em tempo real             |
| `GET /v1/realtime/prices`     | SSE stream | Snapshot completo de preços a cada 1s                 |
| `GET /v1/lookers/{id}/stream` | SSE stream | Preços filtrados das cryptos de um Looker específico  |
| `GET /v1/calculators/stream`  | SSE stream | PNL em tempo real de uma posição de arbitragem aberta |

### Streams por Caso de Uso

<CardGroup cols={2}>
  <Card title="/v1/realtime/prices" icon="chart-line">
    **Dashboard global** — todos os pares de todas as exchanges. Volume alto (\~900 KB/s em 6 exchanges). Use com moderação.
  </Card>

  <Card title="/v1/realtime/arbitrage" icon="bolt">
    **Oportunidades** — somente pares com spread positivo detectado. Payload compacto, ideal para alertas.
  </Card>

  <Card title="/v1/lookers/{id}/stream" icon="eye">
    **Monitoramento pessoal** — preços ask/bid apenas das cryptos configuradas no Looker do usuário (máx. 6 pares). Com campo `stale` para detectar dados desatualizados.
  </Card>

  <Card title="/v1/calculators/stream" icon="calculator">
    **PNL da posição** — PNL calculado a cada 1s para uma posição spot-futuro aberta. Usa dados de mercado do MongoDB com cache de 5s.
  </Card>
</CardGroup>

### Consumo no Frontend (EventSource)

```javascript theme={null}
// Conectar ao stream de arbitragem
const source = new EventSource('/v1/realtime/arbitrage');

source.onmessage = (event) => {
    const opportunity = JSON.parse(event.data);
    console.log(opportunity);
    // {
    //   "ticker": "BTC-USDT",
    //   "buyExchange": "Binance",
    //   "sellExchange": "OKX",
    //   "buyPrice": 43250.50,
    //   "sellPrice": 43380.00,
    //   "profitPercentAskBid": 0.29,
    //   "timestamp": "2025-03-18T12:00:00Z"
    // }
};

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

// Limpar ao desmontar componente
source.close();
```

<Callout title="Reconexão nativa" icon="lightbulb" color="yellow">
  A API `EventSource` do browser reconecta automaticamente ao servidor em caso de desconexão, sem necessidade de lógica adicional no frontend.
</Callout>

## 🗄️ Persistência

Oportunidades detectadas pelo motor WebSocket são salvas na coleção `operations_realtime` do MongoDB:

```json theme={null}
{
  "_id": "ObjectId(...)",
  "ticker": "ETH-USDT",
  "buyExchange": "Binance",
  "sellExchange": "Bybit",
  "buyPrice": 2250.10,
  "sellPrice": 2256.80,
  "profitPercentAskBid": 0.30,
  "source": "websocket",
  "createdAt": "2025-03-18T12:00:00.000Z"
}
```

<Callout title="TTL curto" icon="clock" color="blue">
  A coleção `operations_realtime` é projetada para ter TTL curto — os dados são efêmeros por natureza, servindo principalmente como auditoria e buffer para clientes que se reconectam.
</Callout>

## 🔌 Exchanges Suportadas

### Fase 1 e 2 — Concluídas ✅

| Exchange | Stream                                              | Status         |
| -------- | --------------------------------------------------- | -------------- |
| Binance  | `wss://stream.binance.com:9443/ws` — `!bookTicker`  | ✅ Implementado |
| OKX      | `wss://ws.okx.com:8443/ws/v5/public` — `tickers`    | ✅ Implementado |
| Bybit    | `wss://stream.bybit.com/v5/public/spot` — `tickers` | ✅ Implementado |
| KuCoin   | `wss://ws-api.kucoin.com` — `market/ticker:all`     | ✅ Implementado |
| Gate.io  | `wss://api.gateio.ws/ws/v4/` — `spot.tickers`       | ✅ Implementado |
| HTX      | `wss://api.huobi.pro/ws` — `market.$symbol.bbo`     | ✅ Implementado |

### Fase 3 — Planejada 🔄

| Exchange   | Stream                                                    |
| ---------- | --------------------------------------------------------- |
| Bitget     | `wss://ws.bitget.com/v2/ws/public` — `tickers`            |
| Kraken     | `wss://ws.kraken.com` — `ticker`                          |
| Bitfinex   | `wss://api-pub.bitfinex.com/ws/2` — `ticker`              |
| BingX      | `wss://open-api-ws.bingx.com/market` — `tickers`          |
| MEXC       | `wss://wbs.mexc.com/ws` — `spot@public.bookTicker.v3.api` |
| Crypto.com | `wss://stream.crypto.com/exchange/v1/market` — `ticker`   |

### Fase 4 — REST-only (sem WebSocket público)

| Exchange        | Motivo                            |
| --------------- | --------------------------------- |
| Mercado Bitcoin | Sem WebSocket público documentado |
| Foxbit          | API privada apenas                |
| Novadax         | REST polling suficiente           |
| Bitso           | WebSocket requer autenticação     |

## 🧪 Interface do Handler

Para adicionar suporte a uma nova exchange, implemente a interface `WebSocketExchangeHandler`:

```go theme={null}
package integrations

type WebSocketExchangeHandler interface {
    // Name retorna o nome da exchange (deve ser idêntico ao nome REST)
    Name() string

    // Connect inicia a conexão WebSocket e chama onUpdate para cada tick.
    // Deve bloquear até o contexto ser cancelado ou ocorrer erro fatal.
    Connect(ctx context.Context, onUpdate PriceUpdateCallback) error

    // HealthCheck retorna true se a conexão estiver ativa
    HealthCheck() bool
}

// PriceUpdateCallback é chamado para cada tick recebido
type PriceUpdateCallback func(exchange, symbol string, entry RealtimePriceEntry)

type RealtimePriceEntry struct {
    Ask       float64
    Bid       float64
    Volume    float64   // 0 = preservar último valor no cache
    AskQty    float64
    BidQty    float64
    UpdatedAt time.Time
}
```

Registre o novo handler no `WebSocketManager`:

```go theme={null}
// internal/application/ws-manager.go
func (m *WebSocketManager) registerHandlers() {
    m.handlers = []integrations.WebSocketExchangeHandler{
        integrations.NewBinanceWSHandler(),
        integrations.NewOKXWSHandler(),    // adicionar aqui
        integrations.NewBybitWSHandler(),   // adicionar aqui
    }
}
```

## 📊 Monitoramento

Use o endpoint `/v1/realtime/status` para verificar a saúde de cada handler:

```json theme={null}
{
  "enabled": true,
  "handlers": [
    {
      "exchange": "Binance",
      "connected": true,
      "lastUpdate": "2025-03-18T12:00:00Z"
    }
  ],
  "totalConnected": 1,
  "cacheSize": 847
}
```

<Callout title="Status Atual" icon="rocket" color="purple">
  * ✅ **Fase 1 + 2 concluídas**: 6 exchanges com WebSocket ativo (Binance, OKX, Bybit, KuCoin, Gate.io, HTX)
  * ✅ **Looker Stream**: `GET /v1/lookers/{id}/stream` — preços filtrados por Looker
  * ✅ **Calculator Stream**: `GET /v1/calculators/stream` — PNL em tempo real da posição
  * 🔄 **Fase 3**: Bitget, Kraken, Bitfinex, BingX, MEXC, Crypto.com
  * 🔄 **Fase 4**: Avaliar alternativas para exchanges REST-only
</Callout>
