Commit Graph

46 Commits

Author SHA1 Message Date
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
Adriano 80f4477f72 feat(genome): deterministic mutation operators (numeric + categorical)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:48:22 +02:00
Adriano 42a95a52b5 feat(genome): HypothesisAgentGenome with deterministic id and serde
Dataclass per genoma agente ipotesi con campi prompt/feature/temperature/
top_p/model_tier/lookback/style + parent_ids/generation. Id sha1[:16]
deterministico su contenuto canonico (feature_access ordinate, float
arrotondati). to_dict/from_dict per persistenza.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:45:07 +02:00
Adriano 26c328d541 feat(protocol): AST compiler to (df -> Series[Side]) signal fn
Implementa compile_strategy che produce funzione df -> Series[Side]
con valutazione regole in ordine, prima-che-matcha vince, FLAT default
e NaN per warmup degli indicatori.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:40:28 +02:00
Adriano 052f323790 feat(protocol): semantic validator for AST
Aggiunge validatore semantico per AST Strategy: arity check su
verbi logici/comparatori/data, whitelist indicatori
(sma, rsi, atr, macd, realized_vol) e feature OHLCV.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:34:03 +02:00
Adriano 19035812c3 feat(protocol): grammatica S-expression (15 verbi) + parser
Aggiunge il modulo `multi_swarm.protocol` con la grammatica del DSL di
strategia (15 verbi: 4 azioni, 3 logici, 3 comparatori, 4 dati, `when`
e `strategy`) e un parser che produce un AST tipizzato (Strategy/Rule/
Node). Lessing delegato a sexpdata, validazione del set di verbi e
forma `(when <cond> <action>)` gestita dal parser. Sollevata ParseError
su top-level malformato, strategia vuota, verbi sconosciuti o azioni
non terminali.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:30:54 +02:00
Adriano 7290900dc7 feat(cerbero): tools wrapper for Phase 1 indicator subset
Espone sma/rsi/atr/macd/realized_vol/funding_rate sopra CerberoClient
delegando a call_tool(exchange, tool, args).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:27:34 +02:00
Adriano 14b1b84a47 feat(cerbero): HTTP client with bearer + bot-tag + retry
Client minimale verso Cerbero MCP unified server con header
Authorization Bearer e X-Bot-Tag su ogni richiesta. Retry esponenziale
solo su ConnectionError (non su 4xx). 4xx/5xx -> RuntimeError.

Switch da httpx a requests per allineamento con libreria mock
`responses` (httpx richiederebbe respx). httpx resta in deps per usi
futuri. Aggiunto types-requests ai dev deps per mypy strict.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:25:00 +02:00
Adriano b61bbaf13c feat(metrics): Deflated Sharpe Ratio (Bailey & Lopez de Prado)
Aggiunge expected_max_sharpe e deflated_sharpe_ratio per correggere
multiple testing nella valutazione di strategie. Considera skewness,
kurtosis e numero di trial.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:21:35 +02:00
Adriano 2687ce7dd2 feat(metrics): Sharpe + max drawdown + total return
Metriche base per valutazione strategie: Sharpe annualizzato
(default 8760 periodi/anno per dati orari), max drawdown
percentuale dalla curva equity, total return cumulativo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:18:48 +02:00
Adriano 9301ab9051 feat(backtest): event-driven engine with 1-bar exec delay
Engine sincrono bar-per-bar con delay 1: segnale a t-1 esegue a open di t
per evitare lookahead. Position sizing 1 unit, fees su entry+exit,
mark-to-market su close, chiusura forzata posizione open a fine serie.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:15:05 +02:00
Adriano 36e05233d0 feat(backtest): Order/Position/Trade dataclasses with fees
Side StrEnum (long/short/flat), frozen dataclasses con calcolo
unrealized_pnl per Position e gross/fees/net_pnl per Trade
(fees in basis point, default 5bp). 4 test TDD passing,
ruff + mypy strict clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:11:27 +02:00
Adriano d30f981421 feat(data): expanding walk-forward splits
Aggiunge expanding_walk_forward e dataclass Split per generare fold
walk-forward con train che cresce e test sulla finestra successiva.
Rispetta min_train_days e ritorna lista vuota su fold troppo piccoli.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:08:43 +02:00
Adriano 116879400a fix(data): restore pagination early-break + update test count
Code review on b977c37 flagged: with dataset smaller than limit=1000
(typical Phase 1 case), the loop made an extra HTTP request that
returned duplicate rows. Restored `if len(rows) < limit: break`
after extending. Test assertion adjusted from 2 to 1 calls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:06:50 +02:00
Adriano b977c371e5 feat(data): OHLCV loader via ccxt with parquet cache
Adjust .gitignore to keep src/multi_swarm/data/ tracked (only
top-level /data/ cache directory remains ignored).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:01:25 +02:00
Adriano b73416f482 feat(config): pydantic settings loader from .env
Aggiunge Settings (BaseSettings) che carica configurazione da
variabili d'ambiente / file .env, con validazione obbligatoria
dei segreti Cerbero testnet e OpenRouter.

Test:
- test_settings_loads_from_env: happy path via monkeypatch.setenv
- test_settings_requires_tokens: ValidationError quando token
  obbligatori mancano (forza _env_file=None per isolare il test
  da eventuale .env locale popolato).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 18:55:04 +02:00
Adriano 362ffb33a8 chore: project skeleton with uv + pyproject + deps
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 18:49:27 +02:00