Commit Graph

140 Commits

Author SHA1 Message Date
Adriano Dal Pastro 6655e425fa fix(paper): ETH 5m allineato al tick + hardening GUI/compose
Bug principale: in scripts/run_paper_trading.py il fetch usava
end = now.replace(minute=0,...), troncando sempre all'ora. ETH è
dichiarato timeframe=5m (commit 23b7273) ma di fatto veniva
valutato 1 volta ogni 60 min — 502 poll del run 39e027df hanno
prodotto solo 43 evaluazioni/asset, tutte a HH:00. Il commento
in load_assets segnala esplicitamente che a 1h la strategia
perde -33% su 7y: regressione vs backtest.

Fix: helper _align_end_to_timeframe(now, timeframe) snappa end
al boundary nativo dell'asset. Mappa 1m/5m/15m/30m/1h/4h/1d.
Test regression in src/strategy_crypto/tests con 9 casi.

Hardening accessorio incluso nello stesso commit:
- docker-compose.yml: state/ in RW per strategy-crypto-gui
  (SQLite WAL richiede SHM writable anche da reader).
- multi_swarm_core/dashboard/nicegui_app.py: ui.timer ora
  deactivate on_disconnect su 3 pagine (index/convergence/genomes)
  per evitare leak di timer dopo client disconnect.
- strategy_crypto/frontend/data.py: retry 5s su sqlite.connect
  per cold-start race quando GUI parte prima del paper writer.
- state/validation-hardened-001.json: output WFA tooling
  multi-fold del run phase1-hardened-001.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:04:15 +00:00
Adriano Dal Pastro 23b7273e71 feat(paper): ETH a tick 5m + tooling per-year/per-tick analysis
scripts/run_paper_trading.py: AssetConfig ETH ora usa timeframe="5m" invece
del default 1h. Il winner c04dff7086 e' stato trovato dal GA su dati 5m
e a 1h la strategia perde:
- ETH @ 5m (native): +359.50% cum 7y, 77% winrate, max DD/yr 19%
- ETH @ 1h (precedente): -33.03% cum 7y, 67% winrate, max DD 74%
BTC resta a 1h (winner 238e4812 native a 1h, +104% 7y, Sharpe 2+ in 3 anni).

Nuovi script di analisi:
- scripts/yearly_strategies.py: breakdown per anno (2019-2025) di 4
  strategie su tick di discovery (trade/winrate/return/maxDD/Sharpe).
- scripts/multi_tick_strategies.py: confronto cross-tick (5m/15m/1h)
  per i 2 winner correnti. Documenta la divergenza tick-paper di ETH.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 22:10:38 +00:00
Adriano Dal Pastro 9c871d1d86 feat(validation): WFA tooling + multi-fold results phase1-100 runs
Aggiunge 2 script di analisi per validare i top-K genomi cross-fold:

- scripts/analyze_btc_winners.py: per-trade dump (wins/losses/winrate/
  avg_win/avg_loss/return/maxDD/Sharpe) per ogni top-K × 4 fold
  expanding-window WFA. Usato per identificare i winner robusti vs
  i lucky-shot overfit.

- scripts/compare_winners.py: cross-run comparison di 5 winner
  candidate (BTC 1h + ETH 1h + BTC 5m + ETH 5m) sui medesimi 4 fold,
  con totali cumulativi.

Risultati WFA freezati:
- validation-btc-100-001.json: BTC 1h baseline (undertrading=10)
- validation-btc-100-001-thr3.json: BTC 1h con threshold=3 (rilassato
  per strategie ultra-selettive)
- validation-btc-100-5m-thr3.json: BTC 5m con threshold=3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:48:55 +00:00
Adriano Dal Pastro 8b767da5e7 feat(strategy): swap paper a 238e4812 (BTC) + c04dff7086 (ETH) — phase1-100 winners
Risultati phase1-{btc,eth}-100-001 (1h) + phase1-{btc,eth}-100-5m-001 (5m, 770K bars)
con 100-agent GA × 10 generazioni × fitness v2 hardened + WFA 0.7 split.

BTC (238e4812, meteorologist Gen 7 winner del run 1h):
- IS f=0.2604, Sharpe=0.437, 25 trades
- OOS: f=0.4184, Sharpe=1.296, +22.15% return fold 3, DD 7.4%
- WFA 4-fold: cum_ret +31.65%, 58.6% winrate, 2 fold Sharpe 2+

ETH (c04dff7086, mean-reversion oversold del run 5m):
- IS f=0.1881, OOS f=0.1789 (no overfit), Sharpe_OOS=0.171
- WFA 4-fold: cum_ret +23.83%, 77.8% winrate, 2 fold @ 100% winrate
- Primo ETH winner che sopravvive hard-kill v2 in tutta la storia progetto

Archive: btc_9cf506b8.json (precedente winner hardened-001), eth_facd6af85d5d.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:48:42 +00:00
Adriano Dal Pastro 1c0058ec3b feat(strategy): swap BTC paper strategy a 9cf506b8 (hardened-001 robust winner)
Sostituisce btc_fb63e851 (in produzione dal 13 maggio, net +$9.9k su 7y BTC,
Sharpe medio -0.20) con btc_9cf506b8, vincitore del run phase1-hardened-001
(K=50 G=15 7y, fitness-v2 con hard-kill su fees_eat_alpha + negative_net_pnl).

Performance comparate su 7y BTC continui:
- btc_fb63e851:   Net +$9,951  Sharpe medio -0.20  4/8 anni positivi
- btc_9cf506b8:   Net +$30,538 Sharpe medio +0.31  5/8 anni positivi
                  Best year 2021: +$18,938 (vs prod +$6,835)
                  Best Sharpe annuale: 2023 +1.27 (vs prod 2024 +1.16)
                  Zero adversarial findings su 7y continui.

Performance cross-asset (test su ETH 6.8y):
- btc_fb63e851 su ETH: -$120 (pseudo-flat, nessun segnale)
- btc_9cf506b8 su ETH: +$2,059 (4/7 anni positivi)
La strategia generalizza out-of-asset, indicatore di robustezza non-ETH-overfit.

DSL: physicist style, lookback 150 bar (~6 giorni). Triple-AND condition su
realized_vol + atr_pct + sma_pct per entry (long o short). Exit su sma_pct=0
o vol collasso (<0.1%). Selettivo: 502 trade in 7y = 1.4 trade/giorno medio.

btc_fb63e851 archiviato in strategies/archive/ per consultazione futura.
Il glob loader `btc_*.json` e' non-ricorsivo, quindi archive/ non viene
caricato automaticamente.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 13:21:37 +00:00
Adriano Dal Pastro 220e510d5e fix(orchestrator): escludi prompt_library dal config_dict JSON
PromptLibrary e' un frozen dataclass non JSON-serializable. Quando passata in
cfg.prompt_library e poi spread via **cfg.__dict__ in config_dict, faceva
fallire repo.create_run() con TypeError al primo run dopo refactor.

Fix: filtra cfg.__dict__ escludendo prompt_library, e salva separatamente la
lista degli stili (prompt_library_styles) per reproducibility.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 13:21:08 +00:00
Adriano Dal Pastro 9742df3a1f fix(fitness): hardening anti-overfit post-7y incident — 3 correzioni
Incident: extended run elite (Sharpe IS 1.93) net-negativo su 7y
continuous (fees=101% del gross). Multi-fold validation NON sufficiente:
ogni fold restarta equity, mascherando accumulo fees compound.

Correzioni:

1) Default --start esteso a 2018-09-01 (7.3 anni)
   - Copre bear 2018-19, halving 2020, COVID, ATH 2021, winter 2022,
     ETF rally 2024, regime corrente.
   - Una finestra corta (2y) lasciava il GA libero di overfit single-regime.

2) fees_eat_alpha promosso a hard-kill in fitness v2
   - Da soft-penalty 0.4x a hard-kill 0 fitness.
   - Una strategia con fees > 50% del gross non e' recuperabile via
     selection: il prodotto del GA non puo' deployare con quel cost burden.

3) Nuovo finding negative_net_pnl (HIGH, hard-kill)
   - Fires quando sum(trade.net_pnl) < 0 sul training window.
   - Cattura: gross negativo (no edge direzionale) E gross positivo ma
     fees > gross (edge insufficiente).
   - Sintesi del net-after-fees su finestra continua come "deal-breaker"
     non negoziabile via soft penalty.

CLI:
- --fitness-hard-kill <csv> per override esplicito.
- Default v2: no_trades,degenerate,undertrading,fees_eat_alpha,negative_net_pnl.

Test:
- 252 pass (251 + 1 nuovo: test_negative_net_pnl_fires_on_negative_gross).
- Test e2e WFA aggiornato: passa fitness_hard_kill_findings=('no_trades',)
  perche' il fixture sintetico non produce strategie profittevoli.
- test_no_findings_on_reasonable_strategy rinominato:
  test_rsi_mean_reversion_loses_money_on_synthetic_data (riflette
  semantica reale: RSI mean-rev su synthetic ohlcv ha net negativo).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 11:07:40 +00:00
Adriano Dal Pastro 21b5cf1eae feat(validation): add validation data for phase1-extended-001 with detailed results 2026-05-16 10:55:35 +00:00
Adriano Dal Pastro a29748e3d8 perf(backtest): vectorize engine + parallel LLM propose + multi-fold validation tool
- backtest/engine.py: state machine numpy invece di pd.iterrows()
  - 16.8x speedup su 2y (470ms -> 28ms), 11.3x su 7y (1744ms -> 154ms)
  - 7 parity test parametrici vs reference iterrows assicurano equivalenza
- orchestrator/run.py + run_phase1.py: --llm-concurrency N
  - ThreadPoolExecutor parallelizza hypothesis_agent.propose() per generazione
  - 5-8x speedup wall time GA loop (OpenRouter qwen-2.5 regge 6-10 concorrenti)
  - default 1 = backward-compat sequenziale
- scripts/validate_run.py: validation multi-fold standalone
  - prende run_id + top-K + N-folds expanding-window su dataset esteso (7y)
  - rivela overfitter mascherati da fitness IS alta (vedi
    phase1-extended-001: elite IS Sharpe 1.93 collassa OOS a -1.00)
  - ranking per robust_score = min(fitness_oos) su tutti i fold

Test 250/250 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 10:53:48 +00:00
Adriano Dal Pastro fa11cca2bc docs(readme): allinea a stato finale post-refactor sessione 2026-05-15
Aggiornato per riflettere i 12 commit di refactor della sessione:

  - Layout: 3 servizi Docker (strategy-crypto-paper + strategy-crypto-gui
    + multi-swarm-core-gui), GUI split (core GA / strategy paper)
  - Test: 238 attesi (era 186)
  - Architettura prompt: SYSTEM compositor v3.2 documentato (9 sezioni
    iniettate da scaffold core + contenuto strategy via prompts.json)
  - Grammar: 8 indicatori (5 base + 3 _pct: atr_pct, sma_pct, macd_pct)
  - Input MarketSummary: 14 metriche (5 base + 4 regime + 5 geometria)
  - 7 stili cognitive in prompts.json (era 6, +military_strategist e
    psychologist), con focus_metrics + lookback consigliato + archetipo
  - Deploy: 2 URL distinti (/multi_swarm_core_gui + /strategy_crypto_gui),
    Traefik replacepathregex (NON stripprefix per evitare doppio root_path)
  - Note operative: chown 1000:1000 anche per strategies/ post git mv
  - 3 regression guard test ASCII/archetype/lookback documentati

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 22:05:06 +00:00
Adriano Dal Pastro 6526c6e6e3 refactor(prompts): strategy_crypto v3.2 — consolidamento + 3 invariant tests
Patch di consolidamento post-diagnosi v3.1, divisa in REGRESSIONI ripristinate
+ MIGLIORAMENTI opportunistici + INVARIANTI permanenti.

Regressioni v3.0 -> v3.1 ripristinate:
  1. ASCII-strict: caratteri circa-uguale (U+2248) sostituiti con 'vicino a' in 3 stili
     (historian, engineer, psychologist). Critico per encoding robustness.
  2. 'Archetipo dominante: <metafora>': chiusa identitaria reintrodotta in
     tutte le 7 directive. Ancora semantica resistente a mutate_prompt_llm.
  3. 'Lookback consigliato: X-Y barre': hint range differenziato per stile
     (physicist 150-300, biologist 80-200, historian 200-500, meteorologist
     50-150, engineer 60-120, military 100-200, psychologist 50-120) per
     orientare il parametro evoluto lookback_window del genoma.

Miglioramenti opportunistici:
  4. Voce attiva rinforzata: +verbi generativi ('costruisci', 'combina',
     'cattura', 'diagnostica', 'preferisci') in tutte le directive
  5. anti_patterns 5 -> 7 voci: aggiunti (6) chattering crossover same-type
     same-lookback, (7) soglie hard senza isteresi entry/exit
  6. output_priorities 4 -> 5 voci: aggiunta in cima (#1) 'coerenza con
     lente cognitiva' (fondamento del design swarm)
  7. domain_warnings: +frase 'seasonality > 0 non significa significativa, gate a 0.05'
  8. NEW _design_invariants metadata: documenta gli invarianti che future
     versioni DEVONO preservare (utile per chi edita + mutate_prompt_llm)

NEW invariant tests (regression guards permanenti):
  - test_strategy_crypto_directives_ascii_safe
  - test_strategy_crypto_directives_have_archetype_marker
  - test_strategy_crypto_directives_have_lookback_hint

Statistiche v3.2:
  - directive: 800-950 char (era 545-614 in v3.1, troppo snellite)
  - physicist 890, biologist 867, historian 887, meteorologist 884,
    engineer 904, military_strategist 898, psychologist 909

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:54:13 +00:00
Adriano Dal Pastro ccf9f7a33c refactor(prompts): strategy_crypto v3.1 — pulizia post-diagnosi
Pulizia contenuto prompts.json risolvendo le 9 debolezze identificate
in diagnosi v3.0 -> v3.1:

  - agent_role: + frase swarm awareness ("la diversita e' asset critico,
    esplora territori meno ovvi")
  - pattern_guidance: riscritto astratto (rimossi tutti i nomi di
    indicatori; SMA(short)>SMA(long), RSI>70, ecc -> "trend strutturale",
    "compressione vol", "mean reversion strutturale"). Il GA scopre
    l'incarnazione, le directive sono BIAS non template.
  - domain_warnings: riformulato come "NON assumere" (rimosso hint
    inferenziale su funding rate che avrebbe indotto hallucination)
  - directive: trimmate tutte sotto 900 char (era 922-975)
  - focus_metrics: standardizzati a 4 per stile (era 4-5, asimmetria
    estetica); rimosse ridondanze:
      * historian: rimosso autocorr_baseline (gia' visibile in
        Regime recente -> usare solo autocorr_recent come delta proxy)
      * psychologist: kurt/skew (gia' in base statistics) sostituiti
        con autocorr_recent + spectral_entropy (piu informativi)
  - NEW anti_patterns: lista esplicita (5 voci) per ridurre overfitting
    nel design della strategia (no > 4 AND, no singolo evento, no
    correlazione=causalita, no stazionarieta perfetta, no temporal
    features con seasonality < 0.05)
  - NEW output_priorities: trade-off espliciti (robustezza > ottimalita,
    semplicita > complessita, selettivita > attivita)
  - NEW _focus_metrics_design metadata: documenta l'intento delle scelte

Effetto atteso al prossimo Phase 1/2 run: ipotesi piu robuste
(meno overfitting cross-regime), strategie piu semplici (no 5+ AND),
maggior diversita di esplorazione (swarm awareness nel role), zero
inferenze su feature non accessibili.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:40:58 +00:00
Adriano Dal Pastro 19a3592a20 feat(prompt): PromptLibrary v3.1 — anti_patterns + output_priorities
Estende il compositor del SYSTEM con 2 sezioni opzionali iniettate
DOPO i VINCOLI core e PRIMA dell'EXAMPLE:

  ANTI-PATTERN DA EVITARE: lista esplicita di cose da evitare (overfitting,
    correlazione=causalita, > 4 AND, singolo evento estremo, ecc.)
  PRIORITA' DI OUTPUT: trade-off come "robustezza > ottimalita su singolo
    regime", "semplicita > complessita raffinata", "selettivita > attivita"

Razionale: ridurre la varianza non-utile nelle strategie generate
quando il LLM affronta trade-off, e prevenire overfitting nel design.
Entrambi i campi sono opzionali (skip se "") -> backward-compatible
con prompts.json v3.0.

PromptLibrary v3.1: +2 fields top-level (default "").
_build_system_prompt: 2 sezioni condizionali post-VINCOLI.

Test: +3 unit (compositor inject/skip + from_json parsing).
Tot: 235 test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:38:35 +00:00
Adriano Dal Pastro 5202eb517b refactor(prompt): SYSTEM_TEMPLATE diventa compositor — strategy controlla agent_role/pattern_guidance/instruction
Refactor architetturale: il prompt non e' piu' un template hardcoded ma viene
COMPOSTO at-runtime da scaffold core + contenuto strategy.

CORE scaffold (universal, fisso):
  - Grammar JSON spec (legato al protocol/compiler)
  - UNITA' regole semantiche
  - VINCOLI del validator
  - Esempio output

STRATEGY content (tunable in prompts.json):
  - agent_role: "Sei un agente generatore di ipotesi ... [crypto/forex/equity]"
  - pattern_guidance: sezione di archetipi tecnici, ora crypto-specific
  - instruction: frase finale del USER ("Genera una strategia ... [crypto]")
  - domain_warnings: NEW opzionale, per disclaimer di dominio (es. crypto 24/7)

Implementazione:
  - PromptLibrary v3.0: 4 nuovi campi top-level (agent_role, pattern_guidance,
    instruction, domain_warnings), parsati da prompts.json, default fallback in default()
  - hypothesis.py: SYSTEM_TEMPLATE constant rimossa, sostituita da
    _build_system_prompt(lib, genome) che compone scaffold + content
  - USER_TEMPLATE: ultima riga ora ha placeholder {instruction}
  - prompts.json v3.0 in strategy_crypto: agent_role + pattern_guidance +
    instruction + domain_warnings popolati con flavor crypto-specific

Pattern: "core = framework, strategy = contenuto". Per future strategie
(forex, equity), basta creare un prompts.json con flavor diverso, zero
modifiche al core. Universal scaffold (grammar, vincoli, units) e'
condiviso e mantiene la garanzia di parse/validate.

Test: +5 unit (compositor + PromptLibrary fields).
Tot: 232 test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:18:54 +00:00
Adriano Dal Pastro 898b24b6a3 fix(orchestrator): definisci prompt_library PRIMA di istanziare HypothesisAgent
Bug introdotto in b6f48e4: HypothesisAgent(prompt_library=prompt_library) era
chiamato a riga 109, ma prompt_library veniva definito a riga 123 -> NameError
a runtime quando run_phase1 viene eseguito.

Spostato il blocco di setup prompt_library + set_cognitive_styles PRIMA della
istanziazione di HypothesisAgent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:05:39 +00:00
Adriano Dal Pastro b6f48e46fc feat(agents): 5 metriche geometrico-frattali + style-aware focus block
Aggiunge al MarketSummary 5 metriche regime-aware:
  - efficiency_ratio (Kaufman): discriminatore trending/ranging
  - tail_index_left/right (Hill): pesantezza code, robust vs kurtosis
  - structural_uptrend (HH/HL Dow-style): trend strutturale senza lag MA
  - compression_ratio: vol coil pre-breakout
  - spectral_entropy + dominant_cycle (gated): struttura ciclica nel FFT

Architettura "Style-aware focus, no filtering":
  - Tutte le 5 metriche restano visibili a tutti gli stili (landscape GA smooth)
  - prompts.json v2.2: ogni stile dichiara focus_metrics: list[str]
  - USER_TEMPLATE renderizza "Focus per la tua lente: ..." con i valori prioritari
  - Mutation cognitive_style preserva accesso a tutte le metriche (no discontinuita)

PromptLibrary esteso con focus field (parsato da JSON entry styles).
HypothesisAgent accetta prompt_library nel costruttore; orchestrator lo passa.

7 directive aggiornate per interpretare i 5 nuovi input attraverso la lente:
  - physicist: efficiency_ratio + dominant_cycle (modi armonici)
  - engineer: efficiency_ratio < 0.2 = no signal
  - psychologist: tail_left/right = paura/euforia ricorrente
  - ecc.

Test: +19 unit (metriche + focus rendering), +smoke MarketSummary.
Tot: 216 test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:04:06 +00:00
Adriano Dal Pastro 0fd31d52ec feat(agents): estendi input LLM con 4 statistiche regime-aware + directive v2.1
Aggiunge al USER_TEMPLATE dell'HypothesisAgent 4 metriche calcolate su rolling
window 500 barre (no backward bias del full sample):
  - autocorr_lag1_recent vs autocorr_lag1_baseline (AR(1) delta vs storico)
  - hurst_recent (R/S analysis, persistenza di scala)
  - vol_percentile (0-100, posizione vol corrente nella distribuzione storica)
  - seasonality_hour, seasonality_dow (0-1, varianza spiegata da feature temporali)

Razionale: skew/kurt da soli sono ambigui — un AR(1) discrimina momentum vs
mean-reversion meglio di tutta la guidance sui momenti.

NEW funzioni in metrics/basic.py:
  - autocorr_lag1(returns)
  - hurst_exponent(returns) via R/S a scale multiple
  - vol_percentile_historical(returns, current_window=24, ref_window=2000)
  - seasonality_strength(returns, by={"hour"|"dow"})

MarketSummary esteso con 6 nuovi campi (con default); build_market_summary calcola
rolling-500 per "recent", full sample per "baseline".

prompts.json v2.1: tutte le 7 directive estese con frase di interpretazione
style-specific dei 4 nuovi input (no style collapse). Es:
  - physicist: "AR(1) sopra baseline = sistema con memoria fuori equilibrio"
  - engineer: "AR(1) > 0.05 con std contenuta = SNR favorevole"
  - psychologist: "AR(1) recente >> baseline = euforia coordinata"

Tests: +16 unit per le metriche, +1 smoke per MarketSummary populated.

Verifica: 207 test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 20:43:58 +00:00
Adriano Dal Pastro a43157cd44 refactor(gui): split dashboard in core (GA) + strategy_crypto (paper)
- NEW src/multi_swarm_core/multi_swarm_core/dashboard/ con theme.py + data.py + nicegui_app.py
- theme.py condiviso (CSS + colors + _apply_theme + _json_to_html + _build_header parametrico)
- core GUI: pagine /, /convergence, /genomes — legge SOLO runs.db
- strategy GUI slim: solo /, legge SOLO strategy_crypto.db — importa theme dal core
- Aggiunto nicegui+plotly al core pyproject (uv.lock rigenerato)
- docker-compose: nuovo servizio multi-swarm-core-gui su /multi_swarm_core_gui
  (Traefik PathPrefix + replacepathregex, NO stripprefix per evitare doppio root_path)
- .env.example: DASHBOARD_ROOT_PATH ora per-servizio

Pattern: ogni modulo possiede la sua GUI, ogni GUI legge solo il proprio DB.
N strategie future = duplica lo scheletro strategy_crypto/frontend/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 19:23:12 +00:00
Adriano Dal Pastro 436613bfde fix(traefik): sostituisci stripprefix con replacepathregex per evitare doppio root_path
Bug: la dashboard NiceGUI mostrava "Your browser does not support ES modules"
perche' le asset URL nell'HTML erano doppio-prefissate:
  /strategy_crypto_gui/strategy_crypto_gui/_nicegui/...

Root cause: il middleware traefik.stripprefix aggiunge automaticamente
X-Forwarded-Prefix header. uvicorn/Starlette legge il header e setta
root_path automaticamente, raddoppiando con quello passato esplicitamente
a ui.run(root_path="/strategy_crypto_gui").

Fix: traefik.replacepathregex strippa il prefix senza propagare il header.
uvicorn vede solo il root_path da ui.run -> asset prefissati una sola volta.

  - replacepathregex.regex=^/strategy_crypto_gui(/.*|$)
  - replacepathregex.replacement=$1

Verifica end-to-end:
- page: HTTP 200, asset prefix singolo
- /strategy_crypto_gui/_nicegui/3.12.0/static/socket.io.min.js: 200
- / (root): 404 (atteso)

NB: dopo cambio label, necessario `docker restart traefik-traefik-1` per
forzare refresh discovery (problema noto Traefik con label durante recreate
container nello stesso ciclo). Annotare per future modifiche middleware.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 19:10:18 +00:00
Adriano Dal Pastro f55e4f00c5 fix(deploy): rimuovi PYTHONPATH, member come runtime deps, StripPrefix per NiceGUI subpath
Tre fix di deploy emersi al primo build/up del nuovo compose:

1. Dockerfile: rimosso PYTHONPATH=/app/src
   Con layout uv workspace doppio-nest, PYTHONPATH=/app/src faceva ombra
   alla venv risolvendo le member-dir (multi_swarm_core/, strategy_crypto/)
   come namespace packages PEP 420 senza i sub-package del codice
   (cerbero, persistence, frontend, ecc.). I package sono installati come
   editable dal `uv sync --frozen` nella venv: niente PYTHONPATH necessario.

2. pyproject root: aggiunto [project] dependencies = [multi-swarm-core, strategy-crypto]
   I due member workspace erano in [dependency-groups.dev], escluse da
   `uv sync --frozen --no-dev` del builder Docker -> "ModuleNotFoundError:
   No module named multi_swarm_core". Spostati come dipendenze runtime del
   deployable app root; dev group ora contiene solo pytest/ruff/mypy.
   uv.lock rigenerato.

3. docker-compose.yml: aggiunto Traefik middleware StripPrefix
   NiceGUI con root_path="/strategy_crypto_gui" assume che il proxy
   strippi il prefix prima di girare al container (FastAPI route restano
   "/", "/paper", ecc.). Senza StripPrefix, NiceGUI riceveva
   "/strategy_crypto_gui/" e rispondeva 404. Aggiunte 2 label:
   - strategy-crypto-stripprefix middleware
   - router.middlewares = strategy-crypto-stripprefix

Verifica end-to-end:
- https://swarm.tielogic.xyz/strategy_crypto_gui/ -> HTTP 200 (31KB)
- https://swarm.tielogic.xyz/ -> HTTP 404 (root libera, atteso)
- paper run phase3-baseline-001 (fcf271d0...) tick=1 OK, $1000 equity
- state/strategy_crypto.db creato con 5 tabelle paper_trading_*

NB: permission fix per `src/strategy_crypto/strategy_crypto/strategies/`
fatto manualmente (chown 1000:1000) — i JSON migrati da git mv erano
root:root, container gira come uid 1000. Annotare per future strategies.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:59:14 +00:00
Adriano Dal Pastro 96e08ff78f feat(protocol): aggiungi sma_pct + macd_pct per completare la famiglia *_pct
Estende il fix atr_pct (commit f875df3 / 9c3b5ad) coprendo anche SMA e MACD:

protocol/compiler.py:
- _ind_sma_pct(length) = (close - sma) / sma
  Deviazione frazionale del close dalla SMA. Range tipico ±0.1.
  NB: NON e' sma/close (sempre ~1.0, inutile per literal). Uso ideale:
    sma_pct(50) > 0.05 -> "close 5% sopra media a 50 barre" (mean reversion)
- _ind_macd_pct(fast, slow, signal) = macd / close
  MACD come frazione del prezzo. Range tipico ±0.02. Uso ideale:
    macd_pct(12,26,9) > 0.005 -> "momentum > 0.5% del prezzo"

protocol/grammar.py: KNOWN_INDICATORS estesa con sma_pct + macd_pct
protocol/validator.py: arity (1,1) per sma_pct, (0,3) per macd_pct (come macd)

agents/hypothesis.py (system prompt LLM):
- Lista indicatori include sma_pct e macd_pct con annotazioni unita'
- Esempi corretti/errati estesi: sma_pct > 0.05, macd_pct > 0.005
- Pattern guidance: "Mean reversion: sma_pct(long) > 0.05" e
  "Momentum positivo conferma: macd_pct(12,26,9) > 0.005"

genome/mutation_prompt_llm.py: keyword whitelist estesa con sma_pct + macd_pct

Tests (+3):
- test_sma_pct_is_close_deviation_from_sma: identita' algebrica + sign
- test_macd_pct_is_macd_divided_by_close: identita' + scala (rapporto ~close)
- test_sma_pct_and_macd_pct_in_validator: regression validator

Verifica: 191 pass (era 188).

Closes [[protocol_unit_bug]] in full. Family *_pct ora completa per atr/sma/macd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:28:21 +00:00
Adriano Dal Pastro 9c3b5ad586 feat(prompt): integra atr_pct nel system prompt LLM dell'Hypothesis Agent
Il LLM ora genera strategie sapendo distinguere quando usare atr (unità
prezzo) vs atr_pct (frazione del close) per evitare il bug protocol_unit.

agents/hypothesis.py:
- Lista indicatori: aggiunto atr_pct con annotazione unità inline
- NEW sezione "UNITÀ — REGOLA CRITICA": esempi positivi/negativi su
  literal frazionali (atr_pct > 0.02 ✓) vs literal in unità prezzo
  (atr > 0.02 ✗ sempre TRUE su asset >$1)
- PATTERN GUIDANCE: "Compressione di volatilità" ora suggerisce atr_pct(N) < 0.01
  invece di "ATR(N) < soglia bassa" generico
- "Espansione di volatilità": atr_pct(N) > 0.03 OPPURE confronto relativo

genome/mutation_prompt_llm.py:
- _VALID_KEYWORDS: aggiunti atr_pct + realized_vol (per validazione prompt mutato)

Closes open item da commit f875df3. Prima del prossimo Phase 2.x run il
modello qwen-2.5-72b ricevera' il prompt aggiornato e genera strategie
unit-aware. Vedi src/multi_swarm_core/docs/decisions/2026-05-15-atr-pct-fix.md.

Verifica: 188 test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:19:46 +00:00
Adriano Dal Pastro f875df31b4 fix(protocol): aggiungi atr_pct per risolvere bug unità ATR vs literal frazionali
Bug: ATR ritorna unità prezzo assoluto (~30 su ETH @ 3000 USDT), confronti
con literal 0.02/0.01 generavano dead branches (sempre TRUE / sempre FALSE).
Phase 3 baseline-001 abortita per questo motivo.

Fix chirurgico (no breaking change):
- compiler.py: nuovo _ind_atr_pct(df, length) = atr/close (frazione del prezzo)
- grammar.py: atr_pct aggiunto a KNOWN_INDICATORS
- validator.py: arity (1,1) per atr_pct
- atr classico preservato (usato in confronti relativi tipo `atr > sma`)

Strategy patch:
- eth_facd6af85d5d.json: 2 `atr` → `atr_pct` (le 2 condizioni con literal
  0.02 e 0.01 ora producono branch vivi)
- btc_fb63e851.json invariato (usa `atr > sma`, confronto relativo OK)

Tests:
- test_atr_pct_is_atr_divided_by_close: identita' algebrica + ranges expected
- test_atr_pct_in_strategy_eval: branch attivabile con literal frazionali
- 188 pass totale (186 + 2 nuovi)

Decision log: src/multi_swarm_core/docs/decisions/2026-05-15-atr-pct-fix.md

Open: aggiornare il system prompt LLM (mutation_prompt_llm) per includere
atr_pct PRIMA del prossimo Phase 2.x run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:15:01 +00:00
Adriano Dal Pastro 720b2d58d7 Merge branch 'restructure/strategy-crypto-monorepo' 2026-05-15 18:10:25 +00:00
Adriano Dal Pastro 96bbd716ec docs(readme): allinea a monorepo unificato (workspace uv + strategy_crypto subpath)
- Sezione "Layout monorepo (uv workspace)": ridisegna la struttura per chiarire
  i due workspace member (multi-swarm-core + strategy-crypto), DB separati,
  pattern per N strategie future.
- Comandi aggiornati: paper runner ora importa da strategy_crypto.backend,
  dashboard via 'python -m strategy_crypto.frontend.nicegui_app'.
- Backtest cmd punta al nuovo path strategie src/strategy_crypto/strategy_crypto/strategies/.
- Variabili .env: GA_DB_PATH + STRATEGY_CRYPTO_DB_PATH + DASHBOARD_ROOT_PATH.
  Mantenuto nota backcompat su DB_PATH legacy.
- Dashboard: nuova pagina /paper + URL prod /strategy_crypto_gui/.
- Deploy: servizi rinominati strategy-crypto-paper / strategy-crypto-gui,
  bind strategies dal package, image rinominata multi-swarm-coevolutive:dev.
- Rimossi link a doc cancellati (poc_trading_swarm.md, superpowers/, phase1-technical-report).
- Doc rimanenti riposizionati sotto src/multi_swarm_core/docs/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:03:31 +00:00
Adriano Dal Pastro 30add35906 refactor(compose): rinomina servizi + Traefik subpath + dual-DB + bind strategies dal package
Rinomina servizi (era multi-swarm-paper / multi-swarm-dashboard):
- strategy-crypto-paper  — paper runner (container + service + image name)
- strategy-crypto-gui    — NiceGUI dashboard

Routing Traefik:
- Rule: Host(swarm.\${DOMAIN_NAME}) && PathPrefix(/strategy_crypto_gui)
- NESSUN StripPrefix middleware: NiceGUI gestisce root_path internamente
- URL prod: https://swarm.tielogic.xyz/strategy_crypto_gui/
- Root del dominio libera per future GUI di altre strategie

Env block x-swarm-env aggiornato:
- DB_PATH=/app/state/runs.db rimosso
- GA_DB_PATH=/app/state/runs.db (universale GA)
- STRATEGY_CRYPTO_DB_PATH=/app/state/strategy_crypto.db (paper crypto)
- DASHBOARD_ROOT_PATH=/strategy_crypto_gui (passato a ui.run(root_path=...))

Volumi:
- bind strategies dal package: ./src/strategy_crypto/strategy_crypto/strategies:/app/strategies:ro
- image rinominata: multi-swarm:dev → multi-swarm-coevolutive:dev (allineato a wheel)

Entrypoint dashboard: python -m strategy_crypto.frontend.nicegui_app
                      (era multi_swarm.dashboard.nicegui_app)

Verifica: docker compose config parse OK; 2 servizi presenti.

NOTA OPERATIVA: in produzione aggiornare il file .env reale (non in repo)
                per allinearsi a GA_DB_PATH/STRATEGY_CRYPTO_DB_PATH/DASHBOARD_ROOT_PATH.
                Backcompat: DB_PATH legacy ancora letto come alias di GA_DB_PATH.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:02:21 +00:00
Adriano Dal Pastro 8caa526727 test(strategy_crypto): smoke regression + import-mode importlib per workspace
NEW src/strategy_crypto/tests/test_imports.py:
- test_backend_imports — verifica re-export PaperExecutor/Portfolio/PaperRepository + schema
- test_frontend_imports — strategy_crypto.frontend.{data,nicegui_app} importabili
- test_strategies_json_loadable — i JSON sono in importlib.resources e ben formati
- test_init_schema_creates_tables — PaperRepository.init_schema() crea 5 tabelle

Fix pytest collection: add --import-mode=importlib agli addopts per evitare
collisione dei due tests/__init__.py (core + strategy_crypto) sotto stesso
nome module 'tests'.

Verifica: uv run pytest → 186 passed (182 core + 4 strategy_crypto)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:01:30 +00:00
Adriano Dal Pastro 289df4b81f refactor(layout): docs+tests core sotto modulo, cleanup superflui, README strategy
Ownership per modulo:
- Move docs/ root → src/multi_swarm_core/docs/{design,decisions,reports}/
  * 00_documento_zero.md + coevolutive_swarm_system.md → docs/design/
  * decisions/* → docs/decisions/
  * reports/2026-05-14-stato-progetto-e-roadmap.md → docs/reports/
- Move tests/ root → src/multi_swarm_core/tests/

Cleanup superflui consumati (audit trail preservato in docs/decisions):
- poc_trading_swarm.md (POC superato — Phase 3 attiva in prod)
- docs/reports/2026-05-10-phase1-technical-report.md (superato dal 14-mag)
- docs/superpowers/plans/*.md (3 file, plan consumati)
- docs/superpowers/specs/*.md (2 file, spec consumate)
- tests/unit/paper_trading/ (vuota, paper_trading e' migrato in strategy_crypto)
- Directory docs/ root cancellata

NEW: src/strategy_crypto/README.md — overview strategia (scope, layout,
     run, DB schema, pattern N strategie future)

Root resta minima: README.md, pyproject.toml, docker-compose.yml,
                   Dockerfile, .env*, uv.lock + data/series/state/scripts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:59:28 +00:00
Adriano Dal Pastro 2b5da4d1fc refactor(strategies): move JSON freezate sotto strategy_crypto + patch runner
- git mv strategies/{btc,eth}_*.json → src/strategy_crypto/strategy_crypto/strategies/
- Cancellata directory root strategies/ (ora package data del member strategy_crypto)
- I JSON sono inclusi nella wheel via force-include nel pyproject del member
- scripts/run_paper_trading.py:
  * Import paper_trading.* → strategy_crypto.backend
  * Default --strategies-dir letto da importlib.resources.files('strategy_crypto') / 'strategies'
  * PaperRepository(settings.strategy_crypto_db_path) + init_schema()
  * Rimosso Repository(settings.db_path).init_schema() (GA init non e' responsabilita' del paper)
- Verifica: importlib.resources trova i 2 JSON nel package

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:58:03 +00:00
Adriano Dal Pastro 37bf64012b refactor(dashboard): move multi_swarm_core/dashboard → strategy_crypto/frontend
- git mv data.py + nicegui_app.py al frontend strategy_crypto
- Cancellato src/multi_swarm_core/multi_swarm_core/dashboard/
- Patch import in data.py: ..persistence → multi_swarm_core.persistence
- Patch nicegui_app.py:
  * Import: multi_swarm_core.dashboard.data → strategy_crypto.frontend.data
  * Dual-DB: split DB_PATH in GA_DB_PATH + PAPER_DB_PATH (env separati)
  * Subpath routing: DASHBOARD_ROOT_PATH passato a ui.run(root_path=...)
  * Header dashboard mostra entrambi i DB
  * Docstring di avvio aggiornata: python -m strategy_crypto.frontend.nicegui_app
  * Title rinominato "Strategy Crypto Dashboard"
- 6 occorrenze get_repo(DB_PATH) → get_repo(GA_DB_PATH)
- 6 occorrenze paper_*_df(DB_PATH, ...) → paper_*_df(PAPER_DB_PATH, ...)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:56:55 +00:00
Adriano Dal Pastro b02be64831 refactor(paper_trading): move multi_swarm_core/paper_trading → strategy_crypto/backend
- git mv executor.py, portfolio.py, persistence.py al backend strategy_crypto
- Cancellato src/multi_swarm_core/multi_swarm_core/paper_trading/
- Patch import: from ..backtest/protocol → from multi_swarm_core.backtest/protocol
- persistence.py:
  * usa schema locale strategy_crypto.backend.schema (no piu' core)
  * docstring aggiornata: DB dedicato state/strategy_crypto.db isolato dal core
  * PaperRepository.init_schema() crea le tabelle paper_trading_*
- backend/__init__.py: re-export pubblico (PaperExecutor, Portfolio, PaperRepository, ...)
- config.py:
  * NEW: ga_db_path (alias DB_PATH legacy + GA_DB_PATH preferito)
  * NEW: strategy_crypto_db_path (STRATEGY_CRYPTO_DB_PATH)
  * db_path conserva come property proxy di ga_db_path per backcompat
- Test: import in venv workspace OK; load_settings() resolve entrambi i path

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:54:31 +00:00
Adriano Dal Pastro 08f1585ab2 refactor(schema): split persistence schema — core GA + strategy_crypto paper
- multi_swarm_core/persistence/schema.py: rimuove tabelle paper_trading_*
  (5 CREATE TABLE + 3 indici idx_paper_*). Restano solo le tabelle GA universali
  (runs, generations, genomes, evaluations, cost_records, adversarial_findings).
- strategy_crypto/backend/schema.py NEW: PAPER_SCHEMA_SQL standalone + init_schema()
  con mkdir parent, scrive su state/strategy_crypto.db.

Ownership: ogni strategia possiede il proprio schema, isolato dal core.
Pattern replicabile per strategy_forex, strategy_equity, ecc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:46:50 +00:00
Adriano Dal Pastro cd4c3131d9 feat(workspace): setup uv workspace con 2 member (multi-swarm-core + strategy-crypto)
- Root pyproject.toml come workspace coordinator (no codice, dev deps + tool config)
- src/multi_swarm_core/pyproject.toml: package core con dipendenze (pandas, openai, pydantic, ...)
- src/strategy_crypto/pyproject.toml: package strategia con multi-swarm-core come workspace dep
- Aggiunte env var GA_DB_PATH, STRATEGY_CRYPTO_DB_PATH, DASHBOARD_ROOT_PATH in .env.example
- Patch Dockerfile (commento, label, healthcheck per workspace)
- .gitignore: aggiunto .omc/ + state/*.db generico
- Rigenerato uv.lock dal workspace

uv tree mostra:
  strategy-crypto v0.1.0
  ├── multi-swarm-core v0.1.0
  ├── nicegui v3.12.0
  └── ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:45:53 +00:00
Adriano Dal Pastro b6539802e0 refactor(layout): rename multi_swarm → multi_swarm_core con doppia nidificazione uv workspace
- mv src/multi_swarm → src/multi_swarm_core/multi_swarm_core (member layout)
- sed-replace globale degli import: from/import multi_swarm.* → multi_swarm_core.*
- 115 occorrenze aggiornate in src/ scripts/ tests/
- multi_swarm_coevolutive (nome repo) preservato dal word boundary

Pre-condizione per il setup uv workspace della Fase 3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:43:48 +00:00
Adriano Dal Pastro 7d766173a4 chore(structure): bootstrap scheletro src/strategy_crypto member
Pre-condizione per la riorganizzazione in uv workspace: crea il layout
member del nuovo pacchetto strategy_crypto con __init__.py vuoti.
Il contenuto (backend, frontend, strategies, tests) arriva nelle fasi
successive del piano di migrazione.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:43:01 +00:00
Adriano Dal Pastro 4d79e66d68 feat(api): esponi API library pubblica via __all__ in protocol/backtest/cerbero/data
Cristallizza la library surface che il nuovo repo figlio
Swarm_Strategy_Crypto consumerà via git submodule:
- multi_swarm.protocol.{compile,parse,validate}_strategy + AST nodes
- multi_swarm.backtest.{Side, Trade, Order, Position, BacktestEngine}
- multi_swarm.cerbero.CerberoClient
- multi_swarm.data.{CerberoOHLCVLoader, OHLCVRequest}

Cambi a queste signature dovranno essere considerati breaking
per il consumer downstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.1.0-pre-split
2026-05-15 10:33:52 +00:00
Adriano Dal Pastro 4b9cded966 fix(dashboard): leggi righe selezionate da e.args nel callback selection
Il callback registrato via top_table.on("selection", ...) riceve un
GenericEventArguments di NiceGUI, non un TableSelectionEventArguments,
quindi l'attributo .selection non esiste e il click su una riga della
tabella "Top genomi" generava AttributeError. Le righe selezionate
arrivano nel payload Quasar come e.args["rows"].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 05:38:42 +00:00
Adriano Dal Pastro 14f130aa5a feat(dashboard): pagina /paper per monitoring forward-test
Nuova pagina NiceGUI "Paper" che legge le tabelle paper_trading_*:

- 4 metric card: Equity, P/L cumulato %, Trades chiusi, Open/Tick count
- Equity curve plotly con hline initial capital
- Tre tabelle: open positions, ultimi 30 tick (ts/bar/symbol/signal/action),
  trades chiusi (entry/exit/pnl/fees)
- Run selector dropdown + status badge + auto-refresh REFRESH_INTERVAL_S

dashboard/data.py: aggiunti 6 helper read-only su SQLite (paper_runs_df,
paper_equity_df, paper_positions_df, paper_trades_df, paper_ticks_df,
paper_run_summary). Connessione separata da Repository per usare
direttamente lo schema paper_trading_* senza passare per la classe di
write PaperRepository.

dashboard/nicegui_app.py: aggiunto import pandas (necessario per
to_datetime nell'equity curve), nav link "Paper" nell'header,
@ui.page("/paper") con helper _paper_runs_options + _paper_equity_figure.

Chiude il primo TODO della roadmap sez 10.1 ("Pagina dashboard
paper-trading").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 19:52:02 +00:00
Adriano Dal Pastro b86dbdc9ee docs(readme): allinea a stato attuale (Phase 3, NiceGUI, Docker deploy)
- "Stato del progetto" riscritto: Phase 3 paper-trading in corso, link al
  report di sintesi del 14 maggio, strategie freezate BTC/ETH e costo
  cumulato $3.74 su 30 run GA.
- Architettura: aggiunti splits.py (WFA), diversity.py, mutation_prompt_llm.py
  (5° operatore), paper_trading/ (portfolio/executor/persistence); commenti
  su fitness.py/adversarial.py aggiornati a v2 soft-kill + 5 check HIGH.
- Nuova lista CLI knobs accumulati Phase 2.5 → 2.7.
- Setup: test count ~180, .env include DOMAIN_NAME e SWARM_DASHBOARD_PORT.
- Comandi: aggiunti backtest_strategy.py e run_paper_trading.py; esempio
  run_phase1.py ora usa --prompt-mutation-weight e --fitness-v2.
- Nuova sezione Deploy: docker-compose con due servizi su rete traefik
  external, bind-mount + chown 1000:1000, override paper via env.
- Costi: da Phase 1 only a cumulato $3.74 + Phase 3 LLM-free.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 13:45:25 +00:00
Adriano Dal Pastro a66f97fb0e docs(reports): chiudi item 10.3 port dashboard a NiceGUI
Aggiorna stato-progetto-e-roadmap riflettendo le modifiche del 14 maggio:
- diagramma architettura (sec 9): dashboard/ ora elenca solo nicegui_app.py
  + data.py; rimosso Streamlit legacy e aquarium.py
- item 10.3 "Port completo dashboard a NiceGUI": marcato [x] con
  riferimenti ai commit 03f723f (cleanup) e 8e5efde (deploy Docker
  via Traefik su swarm.tielogic.xyz). Annotata la scelta esplicita di
  non riportare l'Aquarium su NiceGUI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 13:30:35 +00:00
Adriano Dal Pastro 073200313c docs(reports): stato progetto e roadmap al 14 maggio 2026
Riepilogo cumulato delle Phase 1 → 3: 30 run GA completate, $3.74 di
costo LLM, paper-trading runner operativo su BTC+ETH con strategie
freezate fb63e851 (BTC, true alpha hour-gated) e facd6af85d5d (ETH,
trend-following long-bias). Documento di sincronizzazione con caveat
aperti (varianza seed, dipendenza qwen-2.5-72b, Cerbero SPOF) e roadmap
suddivisa in completamento Phase 3, estensioni metodologiche, hardening
tecnico e documentazione.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 13:28:48 +00:00
Adriano Dal Pastro 03f723f7fc refactor(dashboard): switch a NiceGUI, rimuovi legacy Streamlit
NiceGUI è la dashboard ufficiale (port 8080, dark/neon palette, 3 pagine:
/, /convergence, /genomes). La porta è ora parametrica via env
SWARM_DASHBOARD_PORT, letta in ui.run() — Docker la usa anche per
healthcheck e label Traefik.

docker-compose.yml: entrypoint del servizio dashboard cambiato da
streamlit a python -m multi_swarm.dashboard.nicegui_app. Default porta
8080 ovunque (.env, .env.example, compose, healthcheck).

Rimossi i file legacy della vecchia GUI Streamlit:
- src/multi_swarm/dashboard/streamlit_app.py
- src/multi_swarm/dashboard/aquarium.py (helper canvas HTML5)
- src/multi_swarm/dashboard/pages/{01_overview,02_ga_convergence,
  03_genomes,04_aquarium}.py
- tests/integration/test_streamlit_smoke.py

pyproject.toml: rimossa la dep streamlit; uv.lock rigenerato (10 deps
transitive eliminate: pydeck, watchdog, jsonschema, pillow, ecc.).
README aggiornato (architettura, comando dashboard, sezione Dashboard
ora descrive NiceGUI con riferimento al deploy Docker via Traefik).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:15:11 +00:00
Adriano Dal Pastro 8e5efde219 feat(docker): deploy su VPS via traefik con cerbero-mcp interno
Dockerfile multi-stage (python:3.13-slim + uv) e docker-compose con due
servizi che condividono l'immagine:

- multi-swarm-paper: runner long-running scripts/run_paper_trading.py
- multi-swarm-dashboard: Streamlit su https://swarm.${DOMAIN_NAME}

Cerbero raggiunto via rete docker interna (http://cerbero-mcp:9000)
saltando il giro pubblico traefik+TLS. Persistenza via bind mount su
data/, series/, state/ (runs.db con WAL), strategies/ in read-only.

.env.example aggiornato con DOMAIN_NAME, SWARM_DASHBOARD_PORT (porta
interna parametrizzabile) e i PAPER_* per override del command.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 10:21:10 +00:00
Adriano 45f273f591 feat(phase-3): paper-trading runner BTC+ETH
Modulo paper_trading per forward-test virtuale Phase 3:
- Portfolio multi-asset equal-weight sleeve, fees bp su round-trip
- PaperExecutor compila strategia JSON e applica segnale a bar close
- PaperRepository persiste runs/ticks/trades/equity in runs.db
- CLI scripts/run_paper_trading.py: loop polling Cerbero, exec su nuovo bar

Strategie deployate:
- BTC fb63e851 (Sharpe OOS +0.50, mean rev RSI+ATR+hour gate)
- ETH facd6af85d5d (Sharpe OOS +0.19, trend vol regime + SMA50/200)

Capitale virtuale $1000 (sleeve $500 ciascuno), 2 settimane smoke.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 23:34:15 +02:00
Adriano 9d1ef8adcf chore(deps): aggiungi yfinance per test cross-asset non-crypto
Phase 2.7 portabilità: tentativo backtest top genome BTC/ETH su asset
tradFi via yfinance per stress-test universale del setup.
Esito documentato in memoria: yfinance 1h limitato a 730 giorni,
incompatibile con hour-gated strategy su 5+ anni.

Aggiunto .claude/ a .gitignore (scheduled_tasks.lock runtime artifact).
2026-05-13 23:27:53 +02:00
Adriano 67ae6ff74e feat(hypothesis): pattern guidance — forma curve + ripetibilità nel system prompt
Aggiunta sezione 'PATTERN GUIDANCE' nel SYSTEM_TEMPLATE che guida il LLM a
generare strategie basate non solo su threshold di indicatori isolati, ma
anche su:

- Forme di curva (trend asc/desc, compressione/espansione vol, mean reversion strutturale)
- Ripetibilità dell'andamento (crossover ricorrenti, pattern intraday/weekly, doppio top, range breakout)

La grammar JSON resta invariata (no nuove primitive); il prompt insegna al
LLM a comporre i nodi esistenti per approssimare pattern di chart analysis
classica. Obiettivo: spostare la generazione dalla soglia statica RSI<30
verso pattern shape-aware che si replicano nei dati storici.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:49:35 +02:00
Adriano 1a1dfb7a73 feat(fitness): multi-objective combined = alpha*IS + (1-alpha)*OOS opt-in
Aggiunti due meccanismi per selection multi-objective:

1) Helper compute_combined_fitness(fit_train, fit_oos, alpha):
   formula = alpha*IS + (1-alpha)*OOS, fallback a IS se OOS è None/NaN.

2) RunConfig.eval_oos_during_loop (default False) + fitness_combined_alpha
   (default 0.5). Quando True E wfa_train_split attivo, ogni genome con
   fitness IS > 0 viene rivalutato su test_ohlcv DURANTE il loop GA e la
   fitness usata per tournament_select/elite_select è quella combinata.
   2x costo backtest engine (richiede 2 evaluation per genome).

3) CLI flags --eval-oos-during-loop e --fitness-combined-alpha.

Motivazione: il run phase2-7-max7y-v2-wfa-001 ha mostrato che il top by
fitness_IS (4e1be9fa, ratio OOS 0.31) NON è il top per performance OOS reale
(634111992702, ratio 1.42, ret_OOS +105% / 2.2y). Selezionare durante GA
con combined fitness orienta l'evoluzione verso strategie OOS-robust by
design invece di filtrarle a posteriori.

Backward compat: default eval_oos_during_loop=False → comportamento
invariato per run senza il flag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:47:53 +02:00
Adriano 3fcad79f8d fix(llm): timeout esplicito 60s sul client OpenAI (no più hang infinito)
Run phase2-6-flat-wfa-001 è andato in hang per 4h+ a gen 3/10 su una
chiamata OpenRouter (process stuck in do_poll syscall, 0% CPU). Il SDK
OpenAI ha default timeout 600s ma evidentemente il TLS/socket handshake
può bloccarsi senza interrompere; senza timeout esplicito i retry tenacity
non scattano mai e il run resta pending.

Fix: OpenAI(timeout=60.0). Se una chiamata supera 60s, raise
APITimeoutError (già in _RETRYABLE_EXCEPTIONS) e tenacity ritenta fino a 5
volte con backoff esponenziale fino a 30s. Worst case totale: ~5×60s =
5min per call (vs 4h+ hang precedente).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 22:15:31 +02:00
Adriano 242724ba05 feat(phase-2.6): Walk-Forward Validation + min-trades filter parametrico
Due fondamenta scientifiche per filtrare overfit e lucky-shot:

1) undertrading_threshold parametrico (era hardcoded 10):
   - AdversarialAgent.__init__(undertrading_threshold=10)
   - CLI flag --undertrading-threshold
   - Aggiunto a hard_kill_findings v2 default
     {"no_trades", "degenerate", "undertrading"}: ora un genome con 1 trade
     fortunato (es. genome 80be6bcc-1trade-fit-0.21 di fitness-v2-combo) viene
     killato anche sotto fitness v2 soft-kill.
   - Test parametric: undertrading_threshold=25 → 15 trade triggerano HIGH.

2) Walk-Forward Validation (WFA):
   - RunConfig.wfa_train_split (None=off, 0<x<1=on) + wfa_top_k=5
   - run_phase1: split ohlcv in train/test; GA usa solo train; a fine GA
     i top_k genomi (by fitness in-sample, fitness>0) vengono rivalutati
     sul test_ohlcv via falsification+adversarial+compute_fitness.
   - Schema migration: evaluations + fitness_oos, sharpe_oos, return_oos,
     max_dd_oos, n_trades_oos (ALTER TABLE con try/except per DB pre-2.6).
   - Repository.update_evaluation_oos helper per popolare colonne OOS.
   - CLI flags --wfa-train-split, --wfa-top-k.
   - Test integration: train_split=0.7 → fitness_oos popolato per top_k.

Motivazione: la fase 2.5 ha generato 17 run con fitness fino a 0.36 + DSR
positivo, ma OOS test su 7 anni mostra che flat-ablation top crolla -37%
mentre fitness-v2 top regge (+143%). WFA in-run permette ora di vedere
direttamente il degradation train→test senza eseguire backtest separati,
rendendo possibile filtrare overfit early durante l'ottimizzazione.

Tests (+2 → 193 totale):
- test_undertrading_threshold_parametric
- test_e2e_wfa_populates_fitness_oos

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 17:31:22 +02:00
Adriano 4c184bb5f7 feat(scripts): backtest_strategy.py — esegue una strategia standalone su range esteso
Script utility per validare OOS strategie discovered durante run Phase 2.5.
Carica un JSON strategia (formato Hypothesis output), fetcha OHLCV via
Cerbero, esegue BacktestEngine + FalsificationReport + AdversarialReport,
stampa metriche annualizzate (CAGR, Sharpe, max DD, Calmar).

Esempio:
    uv run python scripts/backtest_strategy.py /tmp/strategy.json \
        --start 2018-09-01 --end 2026-01-01 --label my-strategy

Validato sui top 2 genomi Phase 2.5 (flat-ablation e fitness-v2-combo):
flat-ablation top overfit su 7y (-37%), fitness-v2 top regge (+143% in 7y,
CAGR +12.8%). Conferma che strategie con time gate temporal feature
generalizzano meglio di strategie con SMA crossover hard-tied al regime
del training period.

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