# 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)