Commit Graph

66 Commits

Author SHA1 Message Date
Adriano 8ec45c5c1b revert(config): rollback tier C a qwen-2.5-72b-instruct (qwen3-235b inferiore)
Run controllo phase2-qwen25-control-001 (seed 42, stessa pipeline Phase 2,
solo tier C switched) ha dimostrato che qwen-2.5-72b è qualitativamente
SUPERIORE a qwen3-235b sul nostro workload:

| metrica           | qwen3-235b | qwen-2.5-72b | delta |
| ----------------- | ---------- | ------------ | ----- |
| max fitness       | 0.0238     | 0.0311       | +30%  |
| median > 0 in gen | mai        | 4 gen su 10  | --    |
| entropy media     | 0.199      | 0.85         | 4.3x  |
| genomi fit > 0    | 5          | 10           | 2x    |
| parse success     | 97.7%      | 100%         | +     |
| durata            | 50 min     | 28 min       | 0.56x |
| LLM calls         | 148        | 90           | 0.61x |
| cost USD          | 0.0223     | 0.0122       | 0.55x |

Controintuitivo: 235B con context 262k era atteso superiore al 72B legacy.
In pratica qwen3-235b in tier C produce strategie meno diverse,
meno parsabili e meno ottimizzabili dal GA.

Ripristinati prezzi cost_tracker tier C a 0.40/0.40 (qwen-2.5-72b).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 23:45:52 +02:00
Adriano 9344395760 fix(dashboard): cost live durante run (era 0 fino a complete_run)
Bug: la dashboard mostrava \$0.0000 per Cost (USD) durante i run in corso
perché leggeva runs.total_cost_usd, che viene aggiornato solo dentro
Repository.complete_run a fine run. I record per-call esistevano già in
cost_records (124 record / \$0.019 sul run phase2-qwen3-001 attivo).

Fix: in _snapshot() se il run è status=running uso Repository.total_cost(run_id)
che fa SUM(cost_usd) live su cost_records. Per i run completed/failed continuo
a leggere total_cost_usd dal record runs (storico autoritativo).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:58:03 +02:00
Adriano 6f6fbb30a0 fix(dashboard): JSON config renderizzato come HTML colorato custom (no Prism/hljs)
Soluzione robusta al bug "chiavi JSON invisibili": invece di tentare
override CSS su Prism.js/highlight.js (che nelle build NiceGUI possono
non essere attivi o variare), il JSON viene serializzato server-side con
span colorati espliciti e renderizzato via ui.html.

Implementato helper _json_to_html(obj) che produce HTML con classi:
- .cb-key (chiavi)   → cyan #00D9FF
- .cb-string         → green #00E676
- .cb-number         → pink  #FF2D87
- .cb-bool / .cb-null → amber #FFB800
- .cb-punct (graffe, virgole, due punti) → muted

Stessa logica per system_prompt e raw LLM output in /genomes: sostituito
ui.code(language=text) con ui.html('<pre class="raw-block">') e
html.escape() per safety XSS. Background dedicato #1A1A24 e font
JetBrains Mono 13.5px, line-height 1.7, ottimo contrasto su qualsiasi
browser senza dipendere da syntax highlighter esterno.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:52:50 +02:00
Adriano 171f554916 fix(dashboard): icone Material rese come testo + JSON keys invisibili
Due bug visivi distinti:

1) Icone Material rotte ("arrow_drop_down" come testo nel selector):
   Il selettore CSS '*' applicava font Inter a tutti gli elementi inclusi
   gli .material-icons che richiedono il loro proprio font ligature.
   Sostituito '*' con whitelist esplicita di elementi UI; aggiunto override
   esplicito per .material-icons / .q-icon che forza font 'Material Icons'.

2) JSON keys invisibili nel code block config:
   NiceGUI ui.code usa Prism.js (non highlight.js) per il syntax highlighting.
   Aggiunti selettori .token.* coordinati con la palette neon:
   - .token.property / .token.attr-name → cyan (chiavi JSON)
   - .token.string → green (valori string)
   - .token.number / .token.boolean / .token.null → pink
   - .token.punctuation / .token.operator → muted
   - .token.keyword / .token.builtin → amber
   Più reset text-shadow per pre[class*=language-].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:48:53 +02:00
Adriano 9e740cbcbd fix(dashboard): leggibilità code block JSON config con syntax highlighting custom
Background code più chiaro (#1A1A24) e font 13.5px line-height 1.6 per
leggibilità migliore.

Override token highlight.js coordinati con palette neon:
- .hljs-attr (chiavi JSON) → cyan #00D9FF
- .hljs-string (valori stringa) → green #00E676
- .hljs-number, .hljs-literal (numeri/bool/null) → pink #FF2D87
- .hljs-keyword, .hljs-built_in → amber #FFB800
- .hljs-punctuation, .hljs-meta → muted #7A7A8C

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:45:18 +02:00
Adriano 2acba2077b style(dashboard): redesign Neon Trading Dashboard ispirato a screenshot riferimento
Sostituita palette Modern Fintech con look "neon trading" pink+cyan:
- BG #0A0A0F near-black con dual radial glow (pink top-left, cyan bottom-right)
- Surface #13131A card base, hover #1C1C26
- Primary pink #FF2D87 (max fitness, key metrics)
- Secondary cyan #00D9FF (median, entropy)
- Accent amber #FFB800 (p90, warnings)
- Success neon green #00E676, danger neon red #FF3D60

Effetti visivi aggiunti:
- Card top-border glow gradient (linea pink luminosa)
- Card hover: pink shadow esterno + border 0.5 opacity
- Inset shadow per dare profondità (subtle highlight top)
- Brand-dot pulsing animation 2s (glow pink pulsato)
- Header glassmorphic blur(20px) saturate(180%)
- Chart fill area gradient sotto le curve max/entropy
- Linee Plotly spline smoothing 0.6 (curve morbide)
- Marker bordo bianco per pop

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:43:48 +02:00
Adriano 0486e19829 style(dashboard): redesign moderno con palette Modern Fintech Dark
Sostituita palette Inter FC con design language fintech moderno tipo
Linear/Tremor/Plane:

Palette:
- BG #0A0E1A deep blue-black con radial gradient sottile
- Surface #131829 / surface-2 #1A2138 per hover/active
- Primary cyan #06B6D4 (highlight performance)
- Secondary purple #A78BFA (median curves)
- Accent amber #F59E0B (warnings, p90)
- Success #10B981, danger #EF4444

Typography:
- Inter da Google Fonts (peso 400-700)
- JetBrains Mono per code/numeri tabulari
- letter-spacing negativo + tnum font-feature

Component refinement:
- Card: border sottile rgba + hover cyan glow, no gradient pesante
- Header: backdrop-blur 12px + glass effect
- Nav link: underline animato bottom su active
- Brand: dot pulsante cyan con glow
- Progress bar: 8px rounded, track surface-2
- Metric card: layout left-aligned, label uppercase tracked, value 26px
  con accent class (cyan/purple/amber/green) per coding semantico
- Tabella: header uppercase tracked, row hover cyan-tinted
- Code block: surface scuro + border + JetBrains Mono

Plot Plotly:
- paper_bgcolor → surface (no più sfondo full-bleed)
- gridcolor neutral rgba(slate, 0.08)
- Legend bg surface 0.95 opacity

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:39:59 +02:00
Adriano 2f38562e23 feat(dashboard): NiceGUI Genomes page con top-K + ispezione singolo genoma
Aggiunta route /genomes:
- Run selector + Top K (10/25/50)
- Tabella sortable con fitness, DSR, Sharpe, max DD, trades, style, T, lookback
- Selezione riga → pannello ispezione con 6 metric card e blocchi code per
  system_prompt + raw_text + parse_error eventuale
- Auto-refresh ogni 3s (mantiene selezione corrente se ancora valida)
- Header nav aggiornato con link Genomes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:35:52 +02:00
Adriano 56e22584d9 feat(dashboard): NiceGUI GA Convergence + Inter FC dark theme
Aggiunta route /convergence con due grafici Plotly live:
- Fitness convergence (max, p90, median) — auto-refresh ogni 3s
- Diversity entropy con gate threshold 0.5
- Tabella generazioni ordinabile

Applicata palette Inter FC su entrambe le pagine:
- Sfondo nero #000000
- Surface dark navy #010E80 (heritage Inter)
- Primary blu #1E5BC6, secondary blu #0068A8, accent oro #FFD700

Custom CSS via ui.add_head_html + ui.colors() quasar override.
Header navigazione condiviso con link attivo evidenziato.
Plotly: template plotly_dark + paper/plot bg neri + gridcolor rgba.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:33:53 +02:00
Adriano 5f28884974 feat(dashboard): NiceGUI port — pagina Overview con auto-refresh live
Prima fase migrazione da Streamlit a NiceGUI. Pagina indice riproduce
l'Overview con:
- run selector reattivo
- 2 progress bar live (generations, evaluations) con WebSocket push
- 4 metric card (top fitness, median, parse success %, cost)
- timer auto-refresh ogni 3s (no click manuale)
- status badge colorato (running/completed/failed)
- config JSON code block

Avvio: uv run python -m multi_swarm.dashboard.nicegui_app (porta 8080)
Streamlit resta attivo su 8501 durante la migrazione. Backend invariato:
riusa dashboard/data.py senza modifiche.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:28:19 +02:00
Adriano 7b790b1bc3 feat(dashboard): progress bar live + top fitness sulla pagina Overview
Aggiunto blocco "Progresso run" sopra le metriche statiche con:
- progress bar generazioni (gens_done / n_generations)
- progress bar evaluations (evals_done / pop × gen) con percentuale
- metric top fitness / median fitness / cost so far
- pulsante Refresh manuale + timestamp ultimo update
- emoji status (🟢 running /  completed /  failed)

Niente nuove dipendenze: solo st.progress + st.rerun standard Streamlit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:21:04 +02:00
Adriano 9c53995f23 feat(config): align tier defaults to cost-conscious models + qwen3-235b on tier C
- Tier S → google/gemini-3-flash-preview ($0.50/$3.00)
- Tier A/B → deepseek/deepseek-v4-flash ($0.14/$0.28)
- Tier C → qwen/qwen3-235b-a22b-2507 ($0.071/$0.10) — Phase 2 target
- Tier D → openai/gpt-oss-20b ($0.03/$0.14)

Aggiornato cost_tracker con prezzi reali per tier. Defaults config.py
ora rispecchiano .env corrente per evitare divergenze dead-code.

Tier S/A/B/D restano cablati ma non ancora invocati nel loop Phase 2
(solo Hypothesis tier C attivo).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:13:49 +02:00
Adriano 68637d1102 feat(hypothesis): aggiungi feature temporali al prompt con 2 esempi few-shot 2026-05-11 17:04:07 +02:00
Adriano 9d1f97cff3 feat(protocol): dispatcher temporal features (hour) in compiler 2026-05-11 16:59:26 +02:00
Adriano 3e9a4efcc2 feat(protocol): extend KNOWN_FEATURES with temporal feature names 2026-05-11 16:56:36 +02:00
Adriano 9d0deb3ae0 fix(llm): handle empty completions + missing usage (nemotron-friendly)
EmptyCompletionError ora retryable. resp.usage può essere None su
provider :free (es. nemotron-3-super-120b-a12b:free) → no assert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 09:45:49 +02:00
Adriano d3662f6098 feat(adversarial): time_in_market_too_high HIGH (>80% always-in-market)
Simmetrico opposto di flat_too_long: penalizza strategie LONG/SHORT su
piu' dell'80% delle bar. Una sempre-in-market e' leveraged B&H camuffato,
esposto a funding cumulato (perp ogni 8h), tail risk eventi notturni e
nessuna opportunity-cost flexibility. Sweet spot fitness positiva: 5-80%
time in market.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:54:46 +02:00
Adriano 56a631f38a feat(adversarial): phase 1.5 hardening (tighter thresholds + flat_too_long + fees_eat_alpha)
Stringe le soglie esistenti e aggiunge due check HIGH per killare le
strategie degeneri scoperte nel run v5 (top-1 +2.66% vs BTC B&H +106%,
flat 99.8% del tempo, fees 69% del lordo).

- overtrading: soglia da n_bars/5 a n_bars/20 (MEDIUM)
- undertrading: HIGH se n_trades < 10 (era MEDIUM <5) — sample troppo
  piccolo per distinguere edge da rumore (lucky shot)
- flat_too_long (NEW, HIGH): signal attivo per <5% delle bar — la
  strategia ha mancato il regime, e' una non-strategia
- fees_eat_alpha (NEW, HIGH): gross_pnl > 0 ma fees > 50% del lordo —
  margine sottile non sostenibile in produzione

Test count: 141 -> 145 (+4 nuovi test deterministici via monkeypatch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:36:35 +02:00
Adriano d159075182 feat(ga): fitness continua v1 con tanh(sharpe) + penalita' moltiplicativa di drawdown
Phase 1 v0 usava `max(0, dsr - 0.5*max_dd)` che azzerava brutalmente la fitness
quando max_dd > 2*dsr. Real run v4 aveva 55/55 strategie a fitness=0 (DSR ~0.001,
max_dd > 0.5), zero pressione selettiva sul GA.

v1: base = 0.5*dsr + 0.5*0.5*(tanh(sharpe)+1) in [0,1], modulata da penalty
moltiplicativa 1/(1+k*max_dd) in (0,1]. Hard kill (no-trade, HIGH adversarial)
preservati. Fitness sempre >0 per strategie con almeno 1 trade -> il GA
puo' preferire "meno cattivo" a "catastrofico" anche su sharpe negativo.

Tests: +3 nuovi (continuous mediocre, bounded, monotonic drawdown), 4 esistenti
restano verdi. Suite 138 -> 141 passed. ruff + mypy strict puliti.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 21:24:05 +02:00
Adriano d4fcb42fc5 feat(agents): hypothesis retry-with-error-feedback (max 1 retry)
HypothesisAgent.propose ora riprova una volta in caso di parse o
validation error: il prompt user del retry include l'output precedente
(troncato a 800 char) e il messaggio di errore, così l'LLM può
auto-correggersi. Configurabile via max_retries (default 1).

Cambia il modello dati di HypothesisProposal: completion (singolare)
diventa completions: list[CompletionResult] con n_attempts. L'orchestrator
itera su completions per registrare il costo di ogni chiamata LLM,
incluse le retry.

Phase 1 v4 mostrava 64% di parse failure recuperabili: il retry punta
a tagliare quel tasso senza inflazionare i token oltre 2x worst-case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 21:20:47 +02:00
Adriano 44eb6436c1 refactor(protocol): swap S-expression grammar for strict JSON Schema
Sostituisce la grammatica S-expression con uno schema JSON stretto. La
grammatica S-expression falliva il parsing nel 64% delle generazioni del
modello Qwen3-235B sul run reale; JSON e' nativo per gli LLM moderni e
si parsa con json.loads.

Cambiamenti principali:
- grammar.py: costanti rinominate LOGICAL_OPS / COMPARATOR_OPS /
  CROSSOVER_OPS / ACTION_VALUES / KIND_VALUES.
- parser.py: nuovo AST a dataclass tipizzato (OpNode, IndicatorNode,
  FeatureNode, LiteralNode, Rule, Strategy); parse_strategy ora consuma
  JSON tramite json.loads.
- validator.py: walk dispatchato per tipo (isinstance) invece di
  pattern-matching su 'kind'; arity check su operatori e indicator.
- compiler.py: traversal del nuovo AST tipizzato, dispatch per
  isinstance; logica indicator/feature/literal invariata.
- hypothesis.py: prompt SYSTEM riscritto con esempi JSON e vincoli
  espliciti su no-nesting; estrazione via fence ```json``` + fallback
  brace-balanced.
- __init__.py: re-export pubblico delle entita' del protocollo.
- Tutti i test (parser, validator, compiler, hypothesis_agent,
  falsification, adversarial, e2e, smoke_run) migrati a JSON.
- Rimossa dipendenza sexpdata da pyproject.toml + uv.lock.

Test: 135 passed (era 122; aggiunti casi parser/validator).
ruff + mypy strict clean. Smoke run end-to-end OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 21:17:26 +02:00
Adriano df76906505 fix(protocol): arity check stretto per indicator + reject nested expressions
Run reale phase1-real-003 ha rivelato: l'LLM genera occasionalmente
"(indicator sma 20 50)" o "(indicator sma (feature close) 20)". Il primo
crashava _ind_sma con TypeError. Il secondo passava attraverso il
validator ma non era supportato dal compiler.

Validator ora:
- Aggiunge INDICATOR_ARITY: sma/rsi/atr/realized_vol = 1 arg, macd = 0-3.
- Rifiuta esplicitamente Node fra gli args di indicator (no-nesting Phase 1).
- Rifiuta arity fuori range con messaggio chiaro.

Strategie con questi pattern vengono ora rigettate dal validator come
parse_error invece di crashare il run. Test suite resta 122 PASSED.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 11:35:54 +02:00
Adriano d9423a1ab5 fix(data,protocol): paginazione OHLCV + macd accetta signal param
Run reale phase1-real-002 ha rivelato:

1. Cerbero/Deribit cap ~5000 candele per call. Una richiesta di 2 anni
   1h (17500 candele) ritorna troncata. CerberoOHLCVLoader._fetch ora
   pagina in chunk da 4500 barre, concatena e dedupe.

2. _ind_macd accettava solo (df, fast, slow). Il prompt suggerisce
   "(indicator macd 12 26 9)" con 3 numeri (fast/slow/signal). Aggiunto
   signal=9 default e calcolo histogram (macd_line - signal_line).

Test suite 122 PASSED, ruff e mypy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 11:27:27 +02:00
Adriano 15a4138bbd fix(agents): tighten hypothesis prompt + normalize max_drawdown
Run reale phase1-real-001 ha rivelato due problemi:

1. 67% parse_error perche' qwen3 nestava indicatori non supportati
   (es. "(sma (indicator realized_vol 30) 150)"). Il prompt SYSTEM
   ora esplicita le regole strette: indicator non e' annidabile,
   sma/rsi/etc. esistono solo come 1o argomento di indicator,
   crossover/crossunder accetta espressioni-serie come (feature close)
   o (indicator sma N).

2. max_drawdown calcolato su equity assoluta (P&L in unita' BTC) +1.0
   produceva drawdown nominali enormi (>89000) per strategie con
   posizioni perdenti su BTC a $96k. Normalizziamo dividendo per il
   notional iniziale (close[0]), cosi' max_dd diventa drawdown
   relativo al wealth iniziale.

Test suite resta 122 PASSED, ruff e mypy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 11:23:50 +02:00
Adriano 370acb4893 refactor(data): replace ccxt OHLCV loader with CerberoOHLCVLoader (deribit default)
Cerbero MCP diventa unica fonte di verità per dati di mercato Phase 1.
Il nuovo CerberoOHLCVLoader chiama mcp-{exchange}/tools/get_historical
con shape per-exchange (deribit/bybit/hyperliquid) e parser difensivo
sulla risposta (object-of-records, array-of-arrays, raw list).

- src/multi_swarm/data/cerbero_ohlcv.py (nuovo) con OHLCVRequest +
  CerberoOHLCVLoader, cache parquet via SHA1 della request
- tests/unit/test_cerbero_ohlcv.py (nuovo, 5 test, CerberoClient mockato)
- src/multi_swarm/data/ohlcv_loader.py + test ccxt rimossi
- scripts/run_phase1.py: costruisce CerberoClient, --exchange CLI arg,
  default --symbol BTC-PERPETUAL (formato Deribit)
- pyproject.toml: rimosso ccxt>=4.4 (uv sync ha rimosso 16 transitivi)
- .env.example: CERBERO_BASE_URL=https://cerbero-mcp.tielogic.xyz +
  nota su MAINNET vs TESTNET token

Schema confermato via OpenAPI di Cerbero (instrument/start_date/end_date
+ resolution opzionale). Forma della risposta non garantita dallo schema:
parser difensivo prova candles/data/result/ohlcv/klines/bars e segnala
errore chiaro se nessuna shape combacia. Live verification skippata
(nessun token in .env).

Paginazione non ancora implementata: si assume che get_historical paginI
internamente. Da rivedere se una live call mostra cap (~1000 candele).

Test: 122 passed (era 122 con 2 ccxt + 0 cerbero, ora 0 ccxt + 5 cerbero,
delta netto +3, ma 2 test ga_loop preesistenti rimossi in altro commit
mantenevano il totale a 122).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 10:58:16 +02:00
Adriano 3688611a40 feat(dashboard): aquarium click handler with info panel + ancestor lineage
Rimuove sidebar acquario (slider max-pesci, toggle label): la dimensione
popolazione è già definita dal GA, le label sono ridondanti col pannello
di ispezione. Mostra tutti i pesci della generazione selezionata.

Aggiunge `build_lineage_index` (mappa ogni genome_id della run ai suoi
attributi) e `trace_ancestors` (BFS sui parent_ids fino a max_levels,
guardia su cicli). `build_fish_dataset` accetta ora il lineage_index e
allega il campo `ancestors` ad ogni pesce; conserva la firma legacy per
compat con i fixture di test esistenti.

`build_aquarium_html` perde `show_labels`. Embedda click handler con
hit-test in canvas pixel space (account per CSS scaling) + pannello
info top-right con stile, fitness/DSR/Sharpe/maxDD/trades, prompt e
albero discendenza colorato per cognitive_style.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:47:10 +02:00
Adriano 4dad8be36b refactor(llm): route all tiers via OpenRouter, drop Anthropic SDK
Tutti i tier (S/A/B/C/D) ora passano per OpenRouter via OpenAI SDK.
Modelli Anthropic raggiungibili via prefisso `anthropic/...`.

- pyproject: rimosso `anthropic>=0.39` da deps + uv.lock
- config: rimosso `anthropic_api_key` field
- LLMClient: dispatch unico, single client OpenAI con base_url OpenRouter
- defaults S/A/B → `anthropic/claude-{opus-4-7,sonnet-4-6}`
- retry exceptions: solo openai.* (drop anthropic.*)
- test rinominati e adattati: tier S/A/B mockano OpenAI con prefisso `anthropic/`
- rimosso test `tier_S_without_anthropic_key_raises` (non più rilevante)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:39:23 +02:00
Adriano 70b8bc3d6c feat(dashboard): aquarium 2D visualization (fish per agent, size by fitness)
Nuova pagina Streamlit "Aquarium" che renderizza ogni genoma come pesce
animato su canvas HTML5: dimensione proporzionale alla fitness, colore
per cognitive_style, halo per i top-3. Helper puro-Python testabile per
costruire dataset e HTML self-contained (no CDN).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:26:53 +02:00
Adriano 33d8e275e7 feat(llm): full multi-tier S/A/B/C/D with routing + pricing
Estende ModelTier a 5 livelli (S/A/B/C/D) con routing automatico:
S/A/B via Anthropic SDK, C/D via OpenRouter (OpenAI SDK). Aggiunge
prezzi per tier S (Opus), A (Sonnet placeholder) e D (Llama). Refactor
LLMClient.complete con dispatch tramite tier_models map e helper
_call_anthropic / _call_openrouter. Settings esposte per tutti e 5
i modelli env-configurabili.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:18:57 +02:00
Adriano 7482600146 feat(llm): make tier-C/tier-B model + OpenRouter URL configurable from .env
LLM_MODEL_TIER_C, LLM_MODEL_TIER_B e OPENROUTER_BASE_URL ora override-abili
via env. Default invariati (back-compat). LLMClient accetta i tre valori
come kwargs opzionali; run_phase1 li propaga da Settings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:13:14 +02:00
Adriano ea403ec2d5 feat(llm): retry tenacity su errori transient connection/timeout/5xx
Avvolge LLMClient.complete con tenacity (3 attempts, backoff esponenziale
2-10s) che ritenta solo su errori transient di OpenAI/Anthropic SDK
(APIConnectionError, APITimeoutError, InternalServerError). RateLimit,
Authentication e 4xx non vengono ritentati. reraise=True preserva
l'eccezione originale dopo l'esaurimento dei tentativi.

Aggiunti 2 test (marker slow): esaurimento retry su APIConnectionError
e successo al secondo tentativo dopo APITimeoutError.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 22:32:34 +02:00
Adriano 18259325a1 chore(dashboard): mypy ignores + parse-success metric in Overview
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:45:06 +02:00
Adriano 846c68d2f5 feat(scripts): Phase 1 runner CLI entry point
Aggiunge scripts/run_phase1.py come entry point CLI per eseguire un run
end-to-end di Phase 1 con parametri configurabili via argparse (popolazione,
generazioni, simbolo, finestra temporale, fees, seed). Aggiunge marker
py.typed al package multi_swarm per esporre i tipi a consumatori esterni
(scripts/) sotto mypy --strict.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:37:38 +02:00
Adriano 188a1f0ef0 feat(dashboard): Genomes page (top-10 + inspection)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:35:10 +02:00
Adriano 95dcf4c232 feat(dashboard): GA convergence page (median/max/p90 + entropy)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:34:17 +02:00
Adriano 889903fdae feat(dashboard): streamlit skeleton + Overview page + data layer
Aggiunge scheletro multipage Streamlit per Phase 1:
- modulo data.py con helper (list_runs_df, get_run_overview,
  generations_df, evaluations_df, genomes_df) sopra Repository.
- streamlit_app.py entry point con DB_PATH da env.
- pages/01_overview.py per elenco run + metriche + config JSON.
- smoke test import di multi_swarm.dashboard.data.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:33:08 +02:00
Adriano 91d160be6f feat(orchestrator): end-to-end Phase 1 runner with persistence
Loop GA completo: build_initial_population -> hypothesis.propose ->
falsification + adversarial -> compute_fitness -> persistenza ->
next_generation. Stato run/gen/genomes/evals/cost/findings su SQLite,
elite skip-eval, run marcato failed su eccezione.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:28:35 +02:00
Adriano 430b874b26 feat(agents): market summary builder for hypothesis prompt
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:24:23 +02:00
Adriano 0f06b056f2 feat(ga): initial population generator with cognitive style coverage
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:22:04 +02:00
Adriano c2a7a62763 feat(ga): generation summary stats (median/max/p90/entropy)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:20:12 +02:00
Adriano 34f88865da feat(persistence): SQLite schema + repository for runs/genomes/evals/cost
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:18:08 +02:00
Adriano 65dda09aff feat(ga): next_generation step (elitism + tournament + mutate/crossover)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:15:21 +02:00
Adriano 3f36ad65dd feat(ga): tournament selection + elitism
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:12:51 +02:00
Adriano 71cfcf786f feat(ga): fitness v0 (DSR - dd_penalty * max_dd, kill on adversarial high)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:11:13 +02:00
Adriano 3fbd5eba5e feat(agents): hand-crafted adversarial with heuristic checks
Implementa AdversarialAgent con check euristici hand-crafted:
no_trades (HIGH), degenerate (HIGH), overtrading/undertrading (MEDIUM).
Severity come StrEnum (UP042 clean), pipeline AST -> compile -> backtest
-> findings allineata a FalsificationAgent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:07:56 +02:00
Adriano 15cb6b37aa feat(agents): hand-crafted falsification (compile→backtest→DSR)
Pipeline AST -> compile_strategy -> BacktestEngine -> Sharpe/DSR/DD.
Caso zero-trade ritorna report tutto-zero. n_trials_dsr correzione
multiple-testing parametrizzata via init.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:05:01 +02:00
Adriano 654ab7b6d9 feat(agents): hypothesis agent with prompt template + s-expr extraction
Aggiunge HypothesisAgent che invoca LLMClient con system/user template
parametrizzati sul genoma e sul MarketSummary, poi estrae la S-expression
(da fence markdown lisp/scheme/sexp o testo nudo), la parsa e la valida.
Restituisce HypothesisProposal con strategy=None + parse_error in caso di
output malformato, mantenendo sempre il CompletionResult per accounting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:01:31 +02:00
Adriano a6f32dd4d8 feat(llm): cost tracker with per-tier pricing and breakdown
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:57:51 +02:00
Adriano a9261452e0 feat(llm): unified client for OpenRouter (Qwen) + Anthropic (Sonnet)
LLMClient instrada richieste in base a ModelTier del genome:
- Tier C -> Qwen 2.5 72B via OpenRouter (chat completions)
- Tier B -> Sonnet 4.6 via Anthropic (messages API)
CompletionResult dataclass frozen con text, tokens, tier, model.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:54:39 +02:00
Adriano 93d0a9e848 feat(genome): uniform crossover for hypothesis genomes
Aggiunge `uniform_crossover` che eredita ogni campo da p1 o p2
con probabilita' 0.5, popola `parent_ids=[p1.id, p2.id]` e incrementa
la generazione. Deterministico dato lo stesso `random.Random` seed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:51:44 +02:00