📸 Sistema de Snapshots e Preços

Visão Geral

O sistema de snapshots é uma camada de cache inteligente que armazena preços históricos de criptomoedas na base de dados local, reduzindo drasticamente as chamadas à API do CoinGecko e melhorando performance.

Por que Snapshots?

Problema sem cache:

Análise de portfólio com 100 datas × 5 ativos = 500 chamadas API
CoinGecko rate limit: ~30 chamadas/minuto
Tempo necessário: ~17 minutos 😱
Erro 429 (Too Many Requests): frequente ⚠️

Solução com snapshots:

1ª execução: 500 chamadas (salva tudo na BD)
2ª execução: 0 chamadas (lê tudo da BD) ⚡
Tempo: < 1 segundo 🚀

Arquitetura

Camadas de Cache

┌─────────────────────────────────────────┐
│  1. Session Cache (Memória)            │
│  Dicionário Python temporário           │
│  Duração: 1 sessão Streamlit            │
└─────────────────────────────────────────┘
               ↓ (se não encontrar)
┌─────────────────────────────────────────┐
│  2. Database Cache (PostgreSQL)         │
│  Tabela t_price_snapshots               │
│  Duração: Permanente                    │
└─────────────────────────────────────────┘
               ↓ (se não encontrar)
┌─────────────────────────────────────────┐
│  3. CoinGecko API (Externa)             │
│  Endpoints: /simple/price, /history     │
│  Rate limit: ~30/min grátis             │
└─────────────────────────────────────────┘

Fluxo de Dados

Pedido: Preço de ADA em 2025-01-15

1. Verificar Session Cache
   └─> _prices_session_cache[(ADA, 2025-01-15)]
       └─> Se encontrar: RETURN ⚡
       
2. Verificar Database
   └─> SELECT price FROM t_price_snapshots 
       WHERE asset_id=X AND snapshot_date='2025-01-15'
       └─> Se encontrar: 
           - Guarda em Session Cache
           - RETURN ⚡
       
3. Chamar CoinGecko API
   └─> GET /coins/cardano/history?date=15-01-2025
       └─> Parse response
           - Guarda em Database
           - Guarda em Session Cache
           - time.sleep(2)  # Rate limiting
           - RETURN

Tabela t_price_snapshots

Schema

CREATE TABLE t_price_snapshots (
    snapshot_id SERIAL PRIMARY KEY,
    asset_id INTEGER NOT NULL REFERENCES t_assets(asset_id),
    snapshot_date DATE NOT NULL,
    price NUMERIC(20, 8) NOT NULL,
    vs_currency VARCHAR(10) NOT NULL DEFAULT 'eur',
    created_at TIMESTAMP DEFAULT NOW(),
    
    -- Constraint: 1 preço por ativo/data/moeda
    UNIQUE(asset_id, snapshot_date, vs_currency)
);

-- Índice para lookup rápido
CREATE INDEX idx_price_snapshots_lookup 
ON t_price_snapshots(asset_id, snapshot_date, vs_currency);

Características

Integração CoinGecko

Cliente CoinGecko (services/coingecko.py)

1. Mapeamento Símbolo → ID

Problema: CoinGecko usa IDs internos, não símbolos

Símbolo → ID
ADA     → cardano
BTC     → bitcoin
ETH     → ethereum

2. Preços Atuais

Endpoint: GET /simple/price

ids: bitcoin,ethereum,cardano
vs_currencies: eur

3. Preços Históricos

Endpoint: GET /coins/{id}/history

date: 31-10-2025  # DD-MM-YYYY

Performance

Benchmarks

Cenário: Portfolio com 50 datas, 3 ativos

Método Tempo Chamadas API
Sem cache ~300s 150
Cache BD apenas ~5s 0 (após 1ª vez)
Cache BD + Session ~0.8s 0 (após 1ª vez)
Prefetch + Bulk ~0.5s 0 (após 1ª vez)

Boas Práticas

✅ DO

❌ DON'T