Pular para conteúdo

API & Backend

app/api/main.py + 11 routers em app/api/routers/. FastAPI 100% async sobre asyncpg.

Estrutura

app/api/
├── main.py              # FastAPI app, lifespan, auth, rate limit
├── routers/
│   ├── scan.py          # /api/scan — sinais para o EA
│   ├── signals.py       # /api/signals — histórico
│   ├── history.py       # /api/history — agregados
│   ├── executions.py    # POST /api/executions — EA reporta
│   ├── ea_status.py     # /api/ea-status — diagnóstico EA
│   ├── account.py       # /api/account/* — self-service assinante
│   ├── performance.py   # /api/performance — track record
│   ├── calibration.py   # /api/calibration — ECE/Brier
│   ├── models.py        # /api/models — lista champions
│   ├── status.py        # /api/status, /api/health
│   ├── public.py        # /api/public/stats (sem auth)
│   ├── admin.py         # /admin/keys, /admin/monitoring-data
│   └── webhooks.py      # /webhooks/eduzz — HMAC + provisionamento
└── static/              # HTML+JS (frontend)

Camadas de auth

flowchart LR
    Req[Request] --> IPCap{IP hard cap<br/>200/min?}
    IPCap -->|excedeu| 429a[HTTP 429]
    IPCap -->|ok| Owner{key == env<br/>API_KEY?}
    Owner -->|sim| OwnerOK[KeyInfo owner]
    Owner -->|não| DB{lookup<br/>api_keys table}
    DB -->|404| 401[HTTP 401]
    DB -->|ok| PlanRL{rate limit<br/>do plano?}
    PlanRL -->|excedeu| 429b[HTTP 429]
    PlanRL -->|ok| Shared{shared key<br/>3+ IPs/1h?}
    Shared -->|sim| Alert[Telegram alert]
    Shared --> Allow[KeyInfo assinante]

Rate limits

Camada Limite Janela
IP hard cap (DDoS) 200 req/min 1 minuto sliding
Owner 600 req/min 1 minuto sliding
Pro 300 req/min 1 minuto sliding
Basic 60 req/min 1 minuto sliding
Invalid keys (anti brute-force) 20 req/min 1 minuto sliding

Implementação: Redis ZSET com fallback in-memory. Veja app/api/main.py:71-105.

Anti-key-sharing

Tracking de IPs únicos por chave em 1h (Redis SET + EXPIRE). Se > 3 IPs distintos → alerta no Telegram (cooldown 6h).

Tolerante para uso legítimo: VPS + PC + celular = 3 IPs OK.

KeyInfo (v2.28)

class KeyInfo:
    plan_tier:        str         # owner | pro | basic | telegram
    symbols_allowed:  list | None  # None = todos
    tfs_allowed:      list | None
    expires_at:       datetime | None
    key_id:           int | None   # PK em api_keys (None para owner-env)
    user_name:        str | None
    email:            str | None
    last_seen_at:     datetime | None

Anexado a request.state.key_info por require_api_key. Routers leem via request.state.key_info.symbols_allowed para filtrar.

CORS

_ALLOWED_ORIGINS = "https://quantfx.com.br,https://api.quantfx.com.br"
methods = ["GET", "POST", "DELETE"]

Restrito ao próprio domínio. Cloudflare Tunnel garante que requests externos passam por proxy CF, com cabeçalho cf-connecting-ip (usado pelo _client_ip()).

Endpoint públicos vs autenticados

Tipo Auth Endpoints
Público nenhuma /api/public/stats, /api/health (no fail mode)
Assinante X-API-Key /api/scan, /api/account/*, /api/signals, etc.
Admin X-Admin-Secret /admin/keys, /admin/monitoring-data
Webhook HMAC-SHA256 /webhooks/eduzz

OpenAPI

FastAPI gera spec automaticamente:

  • Swagger UI: https://api.quantfx.com.br/docs
  • ReDoc: https://api.quantfx.com.br/redoc
  • JSON: https://api.quantfx.com.br/openapi.json

Healthcheck

GET /api/health retorna 200/503 conforme:

{
  "status":           "ok",       // ok | degraded | down
  "api_version":      "2.0.0",
  "db":               "ok",
  "last_prediction":  "2026-05-27T02:51:37+00:00",
  "last_candle":      "2026-05-27T05:45:00+00:00",
  "pred_lag_minutes": 3.5,
  "btc_lag_minutes":  4.1,
  "stale_pred_count": 17,
  "total_active_slots": 40
}

UptimeRobot consulta a cada 5 min. Se 503 → notifica Telegram.

Performance characteristics

Métrica Valor
Connection pool min 2, max 10 (asyncpg)
Command timeout 30s
DB latency média ~3ms (local)
Cache /api/models Pré-aquecido no lifespan (evita cold start 9s)
Memory ~150MB por worker uvicorn
CPU idle ~2% (eventloop dorme)