Files
Multi_Swarm_Coevolutive/docs/reports/2026-05-10-phase1-technical-report.md
Adriano 943aa38cf2 docs: finalize Phase 1 decision memo + technical report
Phase 1 chiusa con tutti i 5 hard gate passati (run phase1-real-005):

- Loop converge: 3 gen consecutive crescita median 0.0001 -> 0.0188.
- Parse success: 100% (98/98) grazie a JSON grammar.
- Top-5 vs median: 1116x ratio (top-1 fit 0.3347 vs median 0.0003).
- Entropy fitness: 0.914 a gen 9 (sopra soglia 0.5).
- Cost: $0.069 reale vs $700 cap.

Decision: GO Phase 2 con 3 aggiustamenti (Adversarial soglie piu' strette,
speciation di base, walk-forward 70/30).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:56:42 +02:00

283 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1 Lean Spike — Rapporto Tecnico
**Autore**: Adriano Dal Pastro
**Data**: 10 maggio 2026
**Versione**: 1.0 (finalizzato)
**Status**: ✅ Phase 1 chiusa, tutti 5 hard gate passati
**Documenti correlati**:
- `docs/superpowers/specs/2026-05-09-decisione-strategica-design.md` (decisione strategica B3)
- `docs/superpowers/plans/2026-05-09-phase1-lean-spike.md` (piano implementativo)
- `docs/decisions/2026-05-10-gate-phase1.md` (decision memo finale)
---
## 1. Setup sperimentale
L'obiettivo della Phase 1 lean spike è dimostrare che il loop tecnico (LLM hypothesis → backtest falsification → adversarial check → GA selection) funziona end-to-end e produce output formalizzabile. I cinque hard gate definiti nello spec sez. 4.4 misurano feasibility, non alpha edge — quella è valutazione di Phase 2.
### 1.1 Configurazione del run di riferimento
Il run `phase1-real-005` (id `1c526996160446b18c0fb57d94874975`) è il primo a superare tutti i gate dopo 4 iterazioni di bug-fix (vedi sez. 3 del decision memo).
| Parametro | Valore |
|---|---|
| Population size (K) | 20 |
| Generazioni | 10 |
| Elite k | 2 |
| Tournament k | 3 |
| Crossover probability | 0.5 |
| Random seed | 42 |
| Symbol | BTC-PERPETUAL (Deribit) |
| Timeframe | 1h |
| Range storico | 2024-01-01 → 2026-01-01 (2 anni, 17545 candele) |
| Fees backtest | 5 basis points |
| n_trials_dsr | 50 |
| Tier LLM dominante | C (qwen3-235b-a22b-2507 via OpenRouter) |
| Cerbero MCP endpoint | http://localhost:9001 (locale) |
| Durata wall-clock | 29 minuti |
| Costo LLM | $0.069 |
### 1.2 Stack tecnologico
Python 3.13, uv 0.10.9. Test framework: pytest + pytest-mock + responses. Persistence: sqlite3 + sqlmodel. Parsing strategia: `json.loads` con dataclass-based AST. Analytics: pandas + numpy + scipy. LLM: openai SDK con base URL OpenRouter (route unica per tutti i tier S/A/B/C/D). HTTP: requests + tenacity. Dashboard: streamlit + plotly + canvas HTML5 custom.
### 1.3 Architettura del run
L'orchestrator (`src/multi_swarm/orchestrator/run.py`, 184 righe) coordina la pipeline end-to-end:
1. **OHLCV loading**: `CerberoOHLCVLoader` chiama `mcp-deribit/tools/get_historical` paginando in chunk da 4500 barre (cap soft Deribit ~5000). Cache parquet su sha1 della query — il run v5 ha riusato cache popolata dai run precedenti, fetch istantaneo.
2. **Market summary**: statistiche return (mean, std, skew, kurt) + classificazione regime volatilità.
3. **Initial population**: 20 genomi distribuiti uniformemente sui 6 cognitive style (physicist, biologist, historian, meteorologist, ecologist, engineer), temperature random in [0.7, 1.2], lookback random in {100, 150, 200, 300}.
4. **Per ogni generazione (10 totali)**:
- **Hypothesis**: chiamata LLM con prompt SYSTEM (regole grammar) + USER (market summary). Output JSON estratto via regex fence ```json. Se parse/validation fallisce: retry 1x con error message nel prompt utente.
- **Falsification**: AST compilato in `Callable[[df], Series[Side]]`, backtest event-driven con 1-bar exec delay, calcolo Sharpe + Deflated Sharpe (Bailey & López 2014, n_trials=50).
- **Adversarial**: 4 check euristici (no_trades, degenerate, overtrading, undertrading).
- **Fitness**: `0.5*dsr + 0.25*(tanh(sharpe)+1)` × `1/(1+max_dd)`, range [0, ~1]. Kill (=0) su zero trade o HIGH adversarial finding.
- **Next generation**: elitism 2 + tournament 3 + 50% crossover / 50% mutation.
5. **Persistence SQLite**: ogni genome, evaluation, cost_record, adversarial_finding, generation summary persistito con indici per query rapide della dashboard.
### 1.4 Caveat metodologici noti
- **In-sample**: il backtest in Phase 1 lean spike non usa walk-forward; tutto il range 2024-2026 viene usato sia per la generazione delle ipotesi sia per la loro valutazione. La sopravvivenza out-of-sample è esplicitamente fuori scope di Phase 1 (gate Phase 2 #2).
- **Compiler con indicatori built-in**: il compiler JSON-based (`src/multi_swarm/protocol/compiler.py`) calcola RSI, SMA, ATR, MACD, realized_vol localmente con pandas. `CerberoTools` è plumbed ma non chiamato durante l'esecuzione delle strategie — è disponibile per agenti future-tense ma il fitness Phase 1 dipende solo dagli indicatori locali.
- **RSI epsilon-floor**: il compiler ha un epsilon sul `roll_down` per evitare RSI=100 esatto su serie monotonicamente crescenti (artefatto matematico irrilevante su dati reali ma documentato).
- **Top-1 strategia con DSR marginale**: vedi sez. 3.
---
## 2. Loop convergence
### 2.1 Fitness per generazione
| Gen | Median | Max | P90 | Entropy |
|---|---|---|---|---|
| 0 | 0.0001 | 0.0601 | 0.0165 | 0.588 |
| 1 | 0.0042 | 0.1893 | 0.0731 | 1.261 |
| 2 | 0.0188 | 0.3347 | 0.2039 | 1.333 |
| 3 | 0.0069 | 0.3347 | 0.3347 | 1.347 |
| 4 | 0.0910 | 0.3347 | 0.3347 | 1.415 |
| 5 | 0.0016 | 0.3347 | 0.3347 | 0.611 |
| 6 | 0.0040 | 0.3347 | 0.3347 | 0.886 |
| 7 | 0.0151 | 0.3347 | 0.3347 | 0.982 |
| 8 | 0.0066 | 0.3347 | 0.3347 | 0.746 |
| 9 | 0.0061 | 0.3347 | 0.3347 | 0.914 |
### 2.2 Lettura
**Convergenza tre-step iniziale**: gen 0→1→2 mostra crescita mediana 4x-50x (0.0001 → 0.0042 → 0.0188) e crescita max 3x-6x (0.06 → 0.19 → 0.33). Gate 1 PASS su questa finestra.
**Plateau dell'elite da gen 2**: max stabile a 0.3347 per le restanti 7 generazioni — comportamento atteso con `elite_k=2` che preserva il top performer attraverso le generazioni. P90 si allinea al max da gen 3, segno che almeno 2 elite mantengono la top fitness.
**Median oscillante**: dopo il picco a gen 4 (0.091), la median fluttua fra 0.0016 e 0.0151 nelle generazioni successive. Causa: turnover stocastico della popolazione (mutation + crossover) introduce genomi nuovi, alcuni dei quali parse correctly ma falliscono Adversarial (no_trades) e si attestano a fitness 0, abbassando la median. Non è regressione strutturale del GA.
**Entropy**: oscilla 0.6-1.4 dopo gen 0, sempre sopra soglia 0.5 → diversità di fitness preservata anche durante plateau dell'elite.
---
## 3. Top-5 genomi: ispezione qualitativa
| Rank | Genome ID | Gen | Style | Fitness | DSR | Sharpe | Max DD | Trades | Temp |
|---|---|---|---|---|---|---|---|---|---|
| 1 | `696052b8...` | 2 | physicist | 0.3347 | 0.0021 | 0.381 | 0.0215 | 33 | 0.68 |
| 2 | `169376a2...` | 1 | engineer | 0.3347 | 0.0021 | 0.381 | 0.0215 | 33 | 0.78 |
| 3 | `eb0265ad...` | 3 | ecologist | 0.2453 | 0.0006 | 0.019 | 0.0011 | 1 | 1.14 |
| 4 | `38d4c1d9...` | 1 | engineer | 0.1893 | 0.0001 | 0.245 | 0.0028 | 1 | 0.82 |
| 5 | `3e355975...` | 1 | physicist | 0.1893 | 0.0001 | 0.245 | 0.0028 | 1 | 0.78 |
### 3.1 Top-1 strategia (ispezione approfondita)
**System prompt** (engineer): *"Cerca segnali con rapporto S/N favorevole, filtri causali, robustezza a perturbazioni di calibrazione."*
**Strategia JSON** (3 regole, evaluation in ordine):
- **LONG**: `SMA(10) crossover SMA(30)` AND `realized_vol(20) > 0.3%` AND `RSI(14) < 45`.
- **SHORT**: `SMA(10) crossunder SMA(30)` AND `realized_vol(20) > 0.3%` AND `RSI(14) > 55`.
- **EXIT**: (`RSI(14) > 70` AND `close crossover SMA(50)`) OR `realized_vol(20) < 0.1%`.
**Lettura economica**: trend-following SMA-cross fast/slow modulato da filtro volatilità (entra solo quando il regime è abbastanza mosso, esce quando è troppo calmo) e filtro RSI come momentum confirmation (long solo se non già ipercomprato; short solo se non già ipervenduto). L'EXIT è sofisticato: esce su overbought confermato da break sopra MA50, OPPURE su collasso di volatilità.
**Performance**: 33 trade su 17545 candele (1 trade ogni 532 candele = 1 ogni 22 giorni). Sharpe positivo modesto, max drawdown 2.15% (basso). DSR praticamente zero (0.0021) — il segnale non è statisticamente significativo dopo correzione multiple testing, perché 33 trade su 2 anni è sample piccolo.
**Plausibilità**: pattern economicamente sensato, non casuale. Reminiscente di strategie trend-following classiche (Donchian, turtle-style) con filtri di regime. Lo stile cognitivo "engineer" (S/N favorable, filtri causali) si riflette nella struttura.
### 3.2 Top-2/3/4/5 brevemente
- Top-2 è una replica funzionale di Top-1 con metriche identiche. Plausibile elite duplicato o convergenza indipendente sulla stessa strategia (verifica per Phase 2: signal correlation fra duplicati).
- Top-3, 4, 5 hanno **1 trade ciascuno** su 2 anni. Sono "lucky shot": una posizione tenuta a lungo che casualmente termina con leggera vincita. Adversarial flagga MEDIUM `undertrading` ma non HIGH, quindi sopravvivono. La fitness function continua dà loro valore non-zero perché `tanh(sharpe)` è leggermente sopra 0.5 e penalty drawdown è quasi 1.0 (max_dd <0.5%).
### 3.3 Ratio top-1 / median
Median fitness su 98 evals: 0.0003.
Top-1 fitness: 0.3347.
**Ratio**: 1116x — Gate 3 soddisfatto con margine drammatico (soglia 1.5x).
---
## 4. Parser failure modes
### 4.1 Statistiche aggregate v5
- Evaluations totali: 98
- Parse success: **98 (100.0%)**
- Parse failure: **0 (0.0%)**
### 4.2 Confronto con iterazioni precedenti
| Run | Grammar | Parse success | Note |
|---|---|---|---|
| v1 | S-expression | 33% | LLM nesta indicators non supportati |
| v4 | S-expression (con arity check post-fix) | 36% | 89 di 98 errori = `indicator nested` |
| v5 | **JSON Schema** | **100%** | Refactor commit `44eb643` |
Il salto da 36% a 100% deriva interamente dal cambio di grammar. JSON è natively supported dal training dei modelli LLM moderni; S-expression è esotica e induce hallucination di sintassi creative.
### 4.3 Retry-with-feedback (commit `d4fcb42`)
Il sistema accetta 1 retry con error feedback. Nel run v5 il retry **non è mai stato usato** (zero retry per parse, dato il 100% di success). Il retry rimane comunque architetturalmente presente per Phase 2 / casi edge.
---
## 5. Costi reali vs preventivo
### 5.1 Breakdown costi LLM v5
| Tier | Calls | Input tokens | Output tokens | Cost USD |
|---|---|---|---|---|
| C (qwen3-235b) | 113 | 112369 | 60060 | $0.069 |
### 5.2 Costo cumulativo Phase 1 (5 run, inclusi bug-fix iterations)
| Run | Cost | Note |
|---|---|---|
| v1 (aborted) | $0.034 | 67% parse_error, max_dd bug |
| v2 (aborted) | $0.018 | macd 3 args, OHLCV cap discovery |
| v3 (aborted) | $0.015 | crash su indicator arity |
| v4 (completed FAIL) | $0.057 | 36% parse, fitness tutti 0 |
| v5 (completed PASS) | $0.069 | tutti gate passati |
| **Totale Phase 1** | **$0.193** | — |
### 5.3 Confronto con preventivo
- Preventivo originale (basato su pricing Anthropic Sonnet): $500-700.
- Spesa reale Phase 1 totale: **$0.19**.
- Deviazione: 99.97%.
La differenza non è dovuta a underuse — il run v5 ha fatto 113 chiamate LLM = full saturazione del budget previsto di calls. È un cambio di ordine di grandezza nei prezzi dovuto al pricing aggressivo di OpenRouter per modelli open-weights (qwen3-235b è 7.5x più economico di Sonnet su input, 37x su output). Il preventivo originale era calibrato su Sonnet 4.6.
### 5.4 Implicazioni per Phase 2
Il margine economico permette di pianificare Phase 2 con maggiore aggressività senza superare il cap ($700-1100):
- K=40 (×2), gen=15 (×1.5), tier mix 30% B / 70% C, ablation runs multiple.
- Estrapolazione lineare conservativa: $0.07 × 2 × 1.5 × ~3 (tier B factor) × 5 (ablation) = ~$3 totali. Possibile spingere a $30-50 senza preoccupazioni se serve per ablation più ricche.
**Rischio cost-trap inverso**: tentazione di sovra-dimensionare Phase 2 perché "tanto costa nulla". Mantenere disciplina budget invariata — investire i $700 cap in PIÙ ablation, non in run più grandi.
---
## 6. Diversity metrics
### 6.1 Entropy fitness per generazione
Vedi tabella sez. 2.1 colonna entropy. Mai sotto 0.5, picco a gen 4 (1.415).
### 6.2 Cognitive style sopravvissuti gen 9
| Stile | Count gen 9 | Avg fitness | Note |
|---|---|---|---|
| engineer | 3 | 0.0 | Dominante numericamente ma fitness 0 (genomi recent, non valutati su elite) |
| physicist | 1 | 0.0598 | Solo presente nel top-K |
| historian | 1 | 0.0002 | — |
| biologist | 0 | — | Estinto |
| meteorologist | 0 | — | Estinto |
| ecologist | 0 | — | Estinto |
**Lettura**: pressione selettiva ha eliminato 3 di 6 stili cognitivi alla generazione finale. Engineer è dominante numericamente, physicist domina nel valore (l'unico con fitness >0 della popolazione "live" gen 9). Phase 2 deve introdurre speciation esplicita per evitare questo collasso (minimum 2-3 specie protette).
### 6.3 Trade distribution sui 98 evals
| Categoria | n | % |
|---|---|---|
| Zero trade (HIGH no_trades, kill) | 42 | 42.9% |
| Undertrading (1-4 trade, MEDIUM) | 5 | 5.1% |
| Normal (5-100 trade) | 9 | 9.2% |
| Overtrading (>100 trade, NON flaggato) | 42 | 42.9% |
**Issue identificato**: il 42.9% di overtrading non viene catturato dall'Adversarial perché la soglia attuale è `n_trades > n_bars/5 = 3509` — troppo alta per essere triggerata su 1000-2000 trade. Phase 2 dovrebbe abbassare a `n_bars/20 = 877` o usare metrica relativa al regime.
### 6.4 Adversarial findings totali
| Finding | Severity | Count |
|---|---|---|
| no_trades | HIGH | 42 |
| undertrading | MEDIUM | 5 |
Niente `degenerate``overtrading` flaggato. Il primo è raro (richiede strategia sempre-LONG o sempre-SHORT puro), il secondo soffre della soglia troppo alta.
---
## 7. Threats to validity
Lista esplicita dei limiti metodologici da non sovra-interpretare:
1. **In-sample fitting**: tutto il backtest è in-sample. Il top-1 ha Sharpe 0.38 ottenuto guardando i dati su cui è stato selezionato. Phase 2 (walk-forward + hold-out Q1-Q2 2026 intoccabile) misura overfitting reale.
2. **Tier C unico**: nessun confronto contro tier B/S. Possibile underperformance del LLM economico vs Sonnet/Opus. Phase 2 introduce ablation multi-tier.
3. **Adversarial hand-crafted**: 4 check euristici (no_trades, degenerate, overtrading, undertrading). Phase 2 introduce 5 prompt LLM-driven dedicati (data snooping, lookahead, regime fragility, crowding, transaction cost erosion).
4. **Fitness function v1**: lineare in DSR + tanh(Sharpe) normalizzato + drawdown moltiplicativa. Non multi-livello (per-team, anti-collusion). Phase 2 introduce.
5. **No speciation, no novelty bonus**: cognitive style scendono da 6 a 3 a gen 9. Phase 2 deve mitigare.
6. **DSR del top-1 = 0.0021**: il "successo" del Gate 3 è guidato da Sharpe (positivo modesto), non da significatività statistica vera. Senza walk-forward + multiple testing rigoroso, non si può affermare alpha edge.
7. **Top-3/4/5 sono "lucky shot" 1-trade**: la fitness function continua li promuove perché drawdown bassissimo + sharpe leggermente negativo, ma sono artefatti. Phase 2 promuove undertrading a HIGH se `n_trades < 10`.
8. **Cerbero/Deribit data quality**: nessuna detection di gap, outlier, exchange downtime. Da affrontare prima di forward-test (Phase 3).
9. **Cost predictability inverso**: Phase 2 deve resistere alla tentazione di sovra-dimensionare perché Phase 1 è costata $0.19.
---
## 8. Conclusioni e implicazioni per Phase 2
**Hard gate sintesi**: ✅ 5 su 5 passati.
**Decisione finale**: **GO Phase 2** (formalizzata nel decision memo).
**Apprendimenti chiave per Phase 2**:
1. **JSON >> S-expression** per grammar LLM-generated. Phase 2 non rivisita.
2. **Fitness continua è essenziale** per dare gradient al GA, ma può promuovere strategie degeneri (1-trade) che vanno killate diversamente.
3. **OpenRouter qwen3-235b** è sorprendentemente capace per generare strategie strutturate, dato un prompt schema-rigoroso. Tier B (Sonnet) potrebbe non essere necessario al 30% come pianificato; ablation Phase 2 misurerà il vero contributo.
4. **Cerbero MCP come single source of truth** funziona: paginazione, cache parquet, audit log integrati senza fragility.
5. **Bug-fix discovery via run reale** è efficiente: 4 cicli, ognuno ha esposto un problema specifico (max_dd math, macd arity, validator arity, fitness clamp, grammar choice). Phase 2 può aspettarsi pattern simile per nuove componenti (speciation edge cases, OOS overfitting, multi-tier dispatch).
**Riusabilità del codebase Phase 1**: il design modulare (data, backtest, metrics, cerbero, protocol, genome, llm, agents, ga, persistence, orchestrator, dashboard) è riusabile direttamente. Estensioni Phase 2:
- `ga/speciation.py` (nuovo) — clustering cosine similarity prompt, quota tournament per specie.
- `ga/fitness.py` — versione v2 con novelty bonus + per-team aggregation.
- `orchestrator/run.py` — integrazione walk-forward.
- `agents/adversarial_llm.py` (nuovo) — 5 prompt LLM-driven.
- `baseline/random_forest.py` (nuovo) — RF baseline per benchmark.
**Costo stimato Phase 2**: $3-15 (estrapolazione molto conservativa). Cap rimane $700-1100 invariato per disciplina.
**Tempo stimato Phase 2**: 4-6 settimane di lavoro calendar, includendo i 3 aggiustamenti del decision memo (Adversarial soglie, speciation, walk-forward).
---
*Documento finalizzato 10 maggio 2026. Versione 1.0.*