feat: multi-strategy paper trader — N strategie in parallelo su testnet
- src/live/multi_runner.py: orchestratore con fetch raggruppato per asset/tf - src/live/strategy_worker.py: worker indipendente con stato persistente JSONL - src/live/strategy_loader.py: import dinamico classi Strategy - strategies.yml: config dichiarativa con defaults e override per strategia - Docker: container unico, strategies.yml montato come volume read-only - Supporta hot-add: aggiungi riga YAML + restart, storico intatto - Ogni strategia: €1000 USDC virtuale, equity tracking, Telegram notify Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user