# Multi-Strategy Paper Trader — Design Spec

## Obiettivo

Eseguire N strategie di trading in parallelo su Deribit testnet (paper trading locale), ognuna con capitale virtuale indipendente di €1000 USDC. Lo storico trade di ogni strategia persiste tra restart. Nuove strategie aggiungibili in corso d'opera via config YAML senza perdere lo storico delle esistenti.

## Architettura

Un singolo container Docker esegue un orchestratore (`MultiStrategyRunner`) che gestisce N `StrategyWorker`. Ogni worker è indipendente: proprio capital, propri trade, proprio stato.

```
Docker Container
├── MultiStrategyRunner (orchestratore, loop principale)
│   ├── StrategyWorker[SQ02_BTC_15m] → paper trade → JSONL
│   ├── StrategyWorker[ML01_ETH_15m] → paper trade → JSONL
│   └── ...altri worker da YAML
├── CerberoClient (condiviso, fetch prezzi)
└── TelegramNotifier (condiviso)
```

## Componenti

### 1. `strategies.yml` — Configurazione

```yaml
defaults:
  capital: 1000
  position_size: 0.15
  leverage: 3
  hold_bars: 3
  poll_seconds: 60
  retrain_hours: 24

strategies:
  - name: SQ02_antifake_vol
    asset: BTC
    tf: 15m
    enabled: true

  - name: SQ02_antifake_vol
    asset: ETH
    tf: 15m
    enabled: true

  - name: ML01_squeeze_gbm
    asset: ETH
    tf: 15m
    enabled: true
    position_size: 0.20
    params:
      ml_threshold: 0.70
      bb_window: 14
      sq_threshold: 0.8
```

Ogni entry eredita `defaults`. Override per-strategia possibile su tutti i campi. Il campo `params` passa kwargs a `generate_signals()` o al backtest ML.

### 2. `StrategyWorker` — Worker per singola strategia

Responsabilità:
- Importa la classe Strategy corrispondente da `scripts/strategies/`
- Mantiene stato: capital, posizione aperta, equity
- Al startup: ricarica `status.json` se esiste (resume), altrimenti inizia da zero
- Ad ogni tick: riceve DataFrame candele, genera segnali, paper-trade
- Logga ogni evento in `trades.jsonl` (append-only)
- Aggiorna `status.json` ad ogni tick

Stato persistente (`status.json`):
```json
{
  "capital": 1023.45,
  "in_position": true,
  "direction": "long",
  "entry_price": 2534.20,
  "entry_time": "2026-05-27T14:30:00Z",
  "bars_held": 1,
  "total_trades": 15,
  "total_wins": 12,
  "started_at": "2026-05-27T10:00:00Z"
}
```

Trade log (`trades.jsonl`), append-only:
```json
{"ts": "2026-05-27T14:30:00Z", "event": "OPEN", "direction": "long", "price": 2534.20, "size": 0.18, "capital": 1023.45}
{"ts": "2026-05-27T15:15:00Z", "event": "CLOSE", "reason": "hold_limit", "entry": 2534.20, "exit": 2560.10, "pnl": 3.45, "fee": 0.92, "net_pnl": 2.53, "capital": 1025.98}
```

### 3. `MultiStrategyRunner` — Orchestratore

Loop principale:
1. Carica `strategies.yml`
2. Per ogni entry, crea `StrategyWorker` (o riprende se già esiste)
3. Ogni 60s:
   a. Fetch candele live da Cerbero (una volta per asset/tf unico)
   b. Passa DataFrame a ogni worker
   c. Ogni worker valuta segnali e gestisce posizione
   d. Worker ML: retrain ogni 24h
4. Notifica Telegram per ogni trade

Ottimizzazione: fetch candele raggruppato per (asset, tf). Se 3 strategie usano BTC 15m, fetch una volta sola.

### 4. Persistenza

```
data/paper_trades/
  SQ02_antifake_vol__BTC__15m/
    trades.jsonl
    status.json
  SQ02_antifake_vol__ETH__15m/
    trades.jsonl
    status.json
  ML01_squeeze_gbm__ETH__15m/
    trades.jsonl
    status.json
```

Directory naming: `{strategy_name}__{asset}__{tf}` con double underscore separatore.

Volume Docker: `./data:/app/data` — persiste tra restart.

### 5. Aggiunta strategia in corso

1. Aggiungi entry in `strategies.yml`
2. `docker compose restart`
3. Runner carica YAML, trova nuova entry senza `status.json` → parte da €1000
4. Strategie esistenti riprendono da `status.json` → storico intatto

### 6. Docker

`Dockerfile` — invariato, aggiunge `strategies.yml` alla COPY.

`docker-compose.yml`:
```yaml
services:
  paper-trader:
    build: .
    container_name: pythagoras-multi
    restart: unless-stopped
    volumes:
      - ./data:/app/data
      - ./strategies.yml:/app/strategies.yml:ro
    env_file:
      - .env
    environment:
      - PYTHONUNBUFFERED=1
```

`CMD` cambia a: `uv run python -m src.live.multi_runner`

### 7. Strategia-specifica: ML01

ML01 richiede training del modello GBM. Il worker ML01:
- Al primo avvio: train su storico (365 giorni via Cerbero)
- Ogni `retrain_hours`: retrain
- Usa `SignalEngine` esistente per check_signal()
- Le strategie SQ* non hanno training — solo regole deterministiche

### 8. File da creare/modificare

Nuovi:
- `src/live/multi_runner.py` — orchestratore
- `src/live/strategy_worker.py` — worker per singola strategia
- `strategies.yml` — config
- `src/live/strategy_loader.py` — import dinamico classi Strategy

Modifiche:
- `docker-compose.yml` — nuovo CMD, volume strategies.yml
- `Dockerfile` — COPY strategies.yml

Invariati:
- `src/live/cerbero_client.py`
- `src/live/telegram_notifier.py`
- `src/live/signal_engine.py` (usato da ML01 worker)
