Commit Graph

66 Commits

Author SHA1 Message Date
Adriano Dal Pastro 26e977d338 feat(monitor): dashboard PAPER del portafoglio attivo (TP01+XS01) + paper forward loop
src/live/dashboard.py: web UI stdlib (:8787) che mostra metriche (FULL/HOLD Sharpe, DD, CAGR),
per-sleeve, posizioni correnti, equity (backtest + paper forward), ultimo dato. Solo MONITOR,
esecuzione REALE disabilitata. scripts/live/paper_portfolio.py: forward-only del portafoglio
(StrategyPortfolio su active_sleeves), stato persistente in data/paper_portfolio (gitignored).

Dockerfile + docker-compose.yml minimali (solo servizio dashboard; runner/esecuzione restano in
Old/). Container pythagoras-dashboard ricostruito col codice nuovo (il vecchio mostrava dati
pre-reset). Mount data/ read-only. .dockerignore esclude Old/data/.venv/.git/.env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 08:57:55 +00:00
Adriano Dal Pastro 14522262e6 chore(reset): v2.0.0 — storico certificato Deribit mainnet, ripartenza pulita
Reset del progetto su fondamenta verificate dopo la scoperta che l'intera
libreria "validata OOS" era artefatto di feed contaminato (print fantasma del
feed Cerbero TESTNET + storico Binance/USDT).

- Storico ricostruito da Deribit MAINNET (ccxt pubblico, tokenless) e
  CERTIFICATO (certify_feed.py): BTC/ETH puliti su TUTTA la storia
  (mediana 2-6 bps vs Coinbase USD), integrita' OHLC + coerenza resample
  (maxΔ 0.00) + cross-venue OK. Alt esclusi (illiquidi/divergenti: LTC/DOGE
  50-82% barre flat; XRP/BNB non certificabili).
- Verdetto sul feed pulito: FADE / PAIRS / XS01 / TSM01 morti (ogni
  portafoglio Sharpe -2.3..-3.0, DD ~40%); solo SH01 e frammenti HONEST
  con segnale residuo, da ri-validare in isolamento.
- Cleanup "restart pulito": strategie, stack live (src/live, src/portfolio,
  runner/executor, yml, docker), ~100 script ricerca/gate, waste/games/
  portfolios, dati non certificati + cache e 60+ diari -> archiviati in Old/
  (preservati, non cancellati). Diario consolidato in un unico documento.
- Skeleton ricerca tenuto: Strategy ABC + indicatori + src/fractal +
  src/backtest/engine + load_data; tool dati certificati (rebuild_history,
  certify_feed, audit_feed, multi_source_check).
- Universo dati ATTIVO: solo BTC/ETH (5m/15m/1h); guardrail fisico
  (load_data su alt -> FileNotFoundError). Esecuzione DISABILITATA, conto flat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 15:20:59 +00:00
Adriano Dal Pastro 264b9200ea feat(live): Stage 2 — GridWorker (Price Ladder) come PAPER sleeve nel runner
Wire del Price Ladder come sleeve PAPER (sim-only, fuori dal pool €500, NESSUN ordine reale):
- runner: kind="grid" -> GridWorker in build_worker_for; _spec_assets_tf grid; tick branch
  (w.tick(res[asset])); meccanismo PAPER_EXTRA (sleeve paper letti da overrides.paper_extra,
  NON da _defs.py -> NON entrano nel backtest canonico/regression-lock: PORT06 resta 19 sleeve).
  Parsing difensivo (un errore non crasha il runner mainnet). Loop dati estesi a paper_extra.
- GridWorker: bootstrap storia FULL (start fisso, come SH01) + mappatura capitale forward dal
  deploy (capital = initial*eq[-1]/base_norm) -> niente salti da finestra mobile; base_norm
  persistito (resume). grid_mtm robusto al df live (timestamp senza datetime; param df).
- portfolios.yml: GRID_BTC in paper_extra (regime range1.5, rd0.20/ru0.06, L6, sl0.10/tp0.03,
  position_size 0.15 PINNATO). Gira in data/portfolio_paper_stats/GRID_BTC/.
Validazione (validate_grid_worker.py): [A] logica n_trades==backtest, [B] forward-tracking
esatto, [C] resume esatto. Dry-test integrazione runner: import OK, build OK, tick OK, pos 0.15.
SICUREZZA: kind=grid mai eseguito reale (runner avvia ordini solo per single/ml); €500 intatti.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 16:18:53 +00:00
Adriano Dal Pastro b3d4ab7150 feat(live): GridWorker (Price Ladder) SIM/PAPER + validazione replay==backtest — shadow stage 1
Stage 1 dello shadow per il Price Ladder (config finale: BTC 1h range1.5 rd0.20 ru0.06 L6
sl0.10 tp0.03). GridWorker (src/live/grid_worker.py) gira sul feed LIVE e contabilizza
l'equity mark-to-market col motore CANONICO grid_mtm (parita' col backtest per costruzione),
SENZA piazzare ordini reali (sim/paper). Stato persistente + resume. grid_mtm esteso con
param df=None (retro-compatibile: il feed live passa il df; None = _load come prima, gate
invariato — BTC ladder 10.8/5.9, PORT06 base 8.18 identici). Validazione
validate_grid_worker.py: [A] full-tick == grid_mtm esatto, [B] replay incrementale converge
esatto, [C] resume entro la persistenza (4 dec) -> VALIDAZIONE OK.

NB SICUREZZA: nessuna modifica a runner/portfolios.yml/_defs -> il sistema mainnet (€500
reali) e' INTATTO; il worker e' inerte finche' non wirato. L'esecuzione REALE (griglia di
LIMIT resting su Deribit, fill parziali/episodi) e' lo stage 2-3, dietro testnet +
autorizzazione esplicita. Il runner avvia ordini reali solo per kind in (single,ml);
kind=grid resta sim per costruzione.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 14:58:11 +00:00
Adriano Dal Pastro c8b956ab56 fix(dashboard): PnL totale dal ledger, non init hardcoded 2000
La KPI "PnL totale" sottraeva un capitale iniziale fisso di 2000 (retaggio
testnet) -> sul micro-test mainnet da 500 mostrava -1499 (-74.95%) invece di
+0.95 (+0.19%). Nuovo helper _ledger_pnl(): legge pnl_total dall'ultima riga
di equity.jsonl (il ledger lo scrive come equity-initial_capital) e ne deriva
l'iniziale -> la dashboard combacia col ledger per costruzione, qualunque sia
il capitale (500 mainnet / 2000 testnet), niente piu' valori fissi da
aggiornare a mano. Fallback: primo punto equity, poi l'equity stessa.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 09:48:33 +00:00
Adriano Dal Pastro b576ee66ac feat(worker): guard TP-invertito — sopprime l'entry quando il TP e' gia' sfondato (wick-print)
Un wick transitorio fa calcolare un tp dal lato sbagliato dell'entry (donchian: segnale
su barra wickata, entry al prezzo recuperato oltre il proprio tp) -> l'exit intrabar
scatta a bars_held=0 in perdita (16-06: 8 giri MR02_BTC 15m, sim -17.9 / reale -2.3).
TP_PHANTOM non lo prende (niente resting oracle, prezzo oltre il livello). Gate
zero-parametri in StrategyWorker._open_position, solo path live. Test + diario + CLAUDE.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 14:16:13 +00:00
Adriano Dal Pastro faf08b3988 docs(spec): piano micro-test mainnet + token Cerbero env-configurabile
Piano operativo per validare l'edge su mainnet con poco denaro reale (il gate per
scalare). Fasi: smoke -> fade-only €1000 2-4 sett -> verdetto ledger-vs-backtest ->
espansione. Sizing motivato (fades €1000 = rumore arrotondamento 2.6% BTC; pairs
esclusi: 30% a quella taglia). Token ora da env CERBERO_TOKEN (default testnet
invariato) -> switch mainnet = solo .env, niente codice. is_mainnet() helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 22:36:26 +00:00
Adriano Dal Pastro 3ac8a46e6a feat(dashboard): trade attivi con data/ora ingresso + tempo in posizione
Nuove colonne 'Ingresso (UTC)' (entry_time) e 'In posizione' (durata dall'ingresso,
formattata m/h/g) con flag stantio. Sostituisce la colonna Eta (staleness) col
tempo di holding effettivo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 22:24:22 +00:00
Adriano Dal Pastro 7ee5b1767f feat(dashboard): solo dati REALI nei trade attivi + valore mercato reale (anche pairs) + attivi sotto il grafico
- entry/mark/unrealized SEMPRE reali (entry di esecuzione vs mark USDC live); il
  feed sim/decisione (testnet inverse dislocato) non e' piu' mostrato come prezzo
- pairs: valore di mercato reale di ENTRAMBE le gambe + PnL non realizzato reale a
  2 gambe (prima 'pairs (z)' senza valore)
- tabella attivi spostata subito sotto il grafico equity

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 22:21:22 +00:00
Adriano Dal Pastro d5a83075f8 fix(dashboard): unrealized usa entry REALE (non sim) per coerenza col mark reale
Le posizioni eseguite mostravano l'entry SIM (feed decisione testnet inverse,
dislocato ~1.3% dal lineare USDC) confrontato col mark REALE -> unrealized gonfiato
(SH01_ETH -1.36% invece di ~-0.25%) e due trade ETH con lo stesso entry sim 1661.95.
Ora entry = real_entry_price/real_entry_a se eseguito; unrealized vs mark reale su
base coerente. Indicatore '⚠sim' quando il feed di decisione diverge dal reale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 22:13:48 +00:00
Adriano Dal Pastro 183209dbd4 feat(dashboard): grafico equity per famiglia + tabella strategie raggruppata per famiglia
- nuovo grafico multi-linea 'Equity per famiglia' (PnL cumulato realizzato di ogni
  famiglia su asse-tempo comune, colori per famiglia, legenda col totale)
- tabella strategie reali raggruppata per famiglia con intestazioni colorate +
  PnL di famiglia; attive prima delle ritirate dentro ogni gruppo
- backend: fam_curves (step-wise cumulato per famiglia dai CLOSE reali), tag fam
  sui trade chiusi

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:48:56 +00:00
Adriano Dal Pastro e311d00fe4 fix(dashboard): tooltip equity allineato al mouse (responsive canvas)
Forzare l'altezza del canvas via CSS !important con maintainAspectRatio default
sfalsava la risoluzione interna vs quella mostrata -> hit-test tooltip offset dal
mouse. Fix canonico: canvas in contenitore .chartbox ad altezza fissa + chart
responsive:true/maintainAspectRatio:false + interaction index su tutti e 3 i grafici
(equity, modal, paper).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:35:15 +00:00
Adriano Dal Pastro f6287fcd36 feat(dashboard): area PAPER distinta con equity separata
I 4 multi-asset (TR01/ROT02/TSM01/XS01, solo statistica fuori dal pool reale) ora
in una zona dedicata con la PROPRIA equity (capitale nozionale + PnL cumulato del
book paper) e tabella separata. La tabella/fam_pnl/closed dell'area principale
diventano SOLO reali. Curva paper Chart.js (ocra), cliccabile -> stesso modal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:25:17 +00:00
Adriano Dal Pastro b6b465878a feat(dashboard): scheda per strategia (modal: curva PnL reale vs sim + trade + link grafici) + versione sistema/strategia + equity restyling
- click su una strategia -> modal con descrizione, versione di creazione/modifica,
  curva PnL CUMULATO reale vs sim (mostra il leakage), trade, e link alla scheda
  dettagliata strategie_attive.html (servita, docs/report montato ro)
- versione di sistema (APP_VERSION) nell'header; per ogni strategia la versione/
  origine documentata (mappa VERSIONS da CLAUDE.md)
- equity restyling: gradiente verde/rosso secondo segno, tooltip con EUR e delta,
  valore+delta in testata, assi in EUR, piu' alto. /api/strategy con guard
  path-traversal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:20:33 +00:00
Adriano Dal Pastro 22af19c7f9 feat(dashboard): badge strategie RITIRATE (staleness) + descrizioni per strategia
Le fade 1h sostituite dallo swap 15m sono marcate RITIRATA→15m (rilevate per
status.json stantio >30min, ordinate in fondo, riga barrata). Descrizioni concise
per ogni strategia (da strategie_attive.html) come tooltip + sezione legenda.
Fix rilevazione paper: per directory (portfolio_paper_stats), non per chiave
'weights' (TR01/TSM01/XS01 non ce l'hanno) -> ora i 4 multi-asset sono paper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:12:42 +00:00
Adriano Dal Pastro 31f08ddf32 feat(dashboard): frontend web PORT06 — stato live, PnL totale/per-strategia, grafici, trade
Server stdlib http.server (zero dipendenze nuove) che legge data/: KPI equity/PnL/DD,
grafico equity (Chart.js CDN + fallback), PnL per-strategia (barre, realizzato reale),
trade attivi in TEMPO REALE (mark Cerbero best-effort, PnL non realizzato, barre, eta
stantio) e chiusi (ultimi 50). Servizio docker-compose 'dashboard' porta 8787, stessa
immagine, monta data/, restart unless-stopped + healthcheck. Nessuna auth -> rete interna.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 19:46:47 +00:00
Adriano Dal Pastro 643ff7f943 feat(live): INIT_LINEAGE — eredita' capitale al cambio timeframe + sweep migliorie serale
Worker nuovo (no status.json) eredita capital/real_capital dal gemello piu'
recente stessa strategia+asset (mai la posizione): niente piu' seed manuale
al prossimo swap. 3 test nuovi, suite 129 passed.
Ricerca: gate 10m ADD bocciato (OOS Sh 10.86->10.76, watchlist chiusa);
XSEC breadth 8->14 Deribit BOCCIATO (gambe flat 91-99% corrompono il ranking)
ma promettente su dati HL reali (-6%->+9% stessa finestra) -> sblocco = routing
dati Hyperliquid quando la storia sara' sufficiente.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 21:18:30 +00:00
Adriano Dal Pastro 612f2bfced feat(live): reconcile resting + orphan single-leg + circuit-breaker venue-lock + FEED_BOOK_GAP
Codice della tornata v1.1.27/28 (gia' in produzione, mai committato):
- reconcile_account: estensione ordini RESTING (FILLED_UNBOOKED/MISSING/STALE,
  caso MR02_BTC: TP fillato di notte scoperto ore dopo) + expected_resting in books
- strategy_worker: orphan_legs su REAL_CLOSE_PARTIAL anche single-leg, persistito
- execution: circuit-breaker su venue-lock admin (stop ordini dopo errori ripetuti)
- runner/hourly_report: alert FEED_BOOK_GAP + timestamp closed trades
- cerbero_client: get_open_orders (merge all + trigger_all)
Test: 12 nuovi, suite completa 126 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 20:29:02 +00:00
Adriano Dal Pastro 82c05f6f81 fix(exec): code-review serale — guard anti-posizione-nuda sul netting + verità per-frazione
7 finder paralleli sul diff della giornata (8adf388..HEAD), fix dei confermati:

CRITICI (money-path):
- close_amount: GUARD stato-stantio sul fallback netting — il residuo
  non-reduce-only e' consentito solo fino al gap (conto reale - libri degli
  altri worker - orfani) nella direzione della chiusura (src/live/books.py =
  fonte unica, usata anche dal reconciler). Senza guard, un close su stato
  stantio (DSL scattato in outage, flatten manuale) APRIVA una posizione nuda
  a taglia piena bookata come 'chiusura verificata'. Fail-safe se il gap non
  e' calcolabile. Check polvere PRIMA di _quantize_step (che clampa al lotto
  minimo: un residuo 1e-17 diventava un ordine nudo da un lotto).
- _real_close: market_amt = filled_amount anche a merged verified=False (i
  contratti chiusi dal reduce-only non si buttano se il leg netting fallisce);
  REAL_CLOSE_PARTIAL non piu' gateato su verified (era soppresso proprio nel
  caso parziale reale).
- pairs: verita' per-FRAZIONE di gamba (gross proporzionale al fillato, orfano
  = solo il residuo — prima falsava reconciler e real_capital della parte gia'
  chiusa); REAL_OPEN_PAIR booka filled_amount; docstring applied corretta.
- open_pair unwind: chiude il FILLATO, non il richiesto (senza il cap silenzioso
  del reduce-only avrebbe mangiato quota altrui).
- place_tp_limit: quantize CONSERVATIVO (sell=floor/buy=ceil) — il rounding al
  tick piu' vicino poteva mettere il resting oltre il TP sim -> tocco genuino
  classificato phantom sistematicamente.

ROBUSTEZZA/OSSERVABILITA':
- runner: WORKER_ERROR_STREAK a 5 e poi ogni 50 poll + recovery RIPRESO +
  flag real_in_position nell'alert (prima: one-shot a n==5, poi silenzio).
- _tp_phantom: TTL 120s sul verdetto (era ~50 HTTP/h per worker a barra
  fantasma); merge notes con entrambi gli order_id (audit-trail).
- reset_flatten: _quantize_step Decimal (round float produceva amount che
  Deribit rifiuta); hourly_report: book XS01 con gambe SHORT visibili (abs).
- validate_xsec_worker: POS/LEV importati (non hardcoded); xs01_tranche:
  regression-lock ESEGUITO vs xsec_sim; reconcile su src/live/books;
  drift_monitor: rolling vettoriale + exit code 1 su warn.

Test: +4 guard/dust, fixture filled_amount -> 114 passed.
Deferiti (TODO): resting esposti al netting, lifecycle orphan_legs, finestra
trade-history TP_PHANTOM, validazione feed a monte, dedup minori.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 21:36:30 +00:00
Adriano Dal Pastro 844a9d0e22 feat(exec): netting delle chiusure market — il residuo reduce-only cappato/respinto va in market puro
close_amount ora: (1) tenta il market reduce-only (sicurezza storica: un bug di
stato filla 0 invece di aprire posizioni); (2) il residuo cappato/respinto dal
netting di conto (worker in direzioni opposte sullo stesso strumento) viene
rieseguito in MARKET PURO con label '|net' — muove il conto esattamente del
delta del libro = netta contro le quote opposte. Niente piu' gambe pairs orfane
ne' close cappati per costruzione (close_pair passa da close_amount).

- _merge_close_fills: il chiamante riceve UN Fill (prezzo medio pesato sui fill,
  fee sommate, filled_amount totale, verified se copre il richiesto, notes
  'netting' quando il fallback scatta)
- worker single-leg + pairs: evento NET_CLOSE (log jsonl + Telegram) a ogni
  fallback — osservabilita' della frequenza dei conflitti di netting
- sicurezza persa sul residuo coperta dal reconciler orario (ACCOUNT_DRIFT);
  orphan_legs/REAL_CLOSE_PARTIAL restano come ultima difesa
- 4 test nuovi (full r-o senza fallback, cappato, respinto, doppio fail) -> 110 passed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:54:43 +00:00
Adriano Dal Pastro 429fa01c97 fix(exec): verità contabile sul netting — filled_amount, gambe orfane, tick isolato
Da audit live (3 indagini parallele, diario 2026-06-11-system-audit.md): il modello
quote-per-worker reduce-only si rompe con direzioni opposte sullo stesso strumento
(pairs long ETH vs fade short ETH) — close cappati bookati pieni, 3 gambe pairs mai
eseguite col PnL sim nel ledger reale, conto short 0.027 ETH oltre i libri
(riallineato a mano + DSL orfano cancellato).

- Fill.filled_amount (order.filled_amount): TUTTI i ledger usano il fillato reale
- REAL_CLOSE_PARTIAL (log+alert) su close cappato; residuo orfano dichiarato
- pairs: PnL solo per gambe verificate; gamba respinta -> orphan_legs persistito
  + alert PAIR_LEG_ORPHAN; applied solo con entrambe le gambe (else sim_fallback)
- REAL_DIVERGENCE anche su jsonl (prima solo Telegram)
- runner: tick isolato per-worker + WORKER_ERROR_STREAK a 5 fail consecutivi

Strutturale APERTO (decisione utente, opzioni nel diario): position-manager
centrale / sotto-conti per famiglia / status-quo monitorato.

Test: +2 (partial-close, orphan-leg), fixture filled_amount -> 106 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:05:42 +00:00
Adriano Dal Pastro 12625b3315 feat(exec): gate TP_PHANTOM — il tocco TP va confermato dal book reale, non dal feed
Il feed testnet stampa wick che 'toccano' il TP intrabar senza che il prezzo
abbia mai scambiato al livello: il sim bookava +4% fantasma a bars_held=0 e
_real_close chiudeva A MERCATO una posizione col resting TP a zero fill
(-fee/spread a giro, 14 giri l'11-06). Ora StrategyWorker._tp_phantom sopprime
l'exit take_profit quando: tocco sim + resting LIMIT zero-fill + prezzo corrente
che non ha raggiunto il livello (il limit sul book reale e' l'oracolo del tocco).
Zero parametri (verita' d'esecuzione, non filtro di strategia); SL close-confirm
e max_bars restano attivi nello stesso tick; fill parziale/prezzo oltre il
livello/worker non eseguito/errore rete -> comportamento storico. Log TP_PHANTOM
dedup per barra + alert Telegram una tantum. 5 test nuovi (104 passed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 19:32:24 +00:00
Adriano Dal Pastro 9d15506b05 feat(stability): sweep stabilità — fix TR01 mean(rets), XS01 phase-tranching K=3, z-stop pairs bocciato
Audit anti-overfit su tutte le 19 sleeve (diario 2026-06-11-stability-sweep.md):

- FIX BasketTrendWorker: mean(rets) sui soli asset in posizione sovrappesava N/k
  a paniere parziale (1 long = 0.45 del capitale invece di 0.09) -> replay -44%
  vs ref +42%. Ora sum(rets)/N (convenzione canonica 1/N): replay +32% vs +42%
  (residuo = convenzione dichiarata). Solo statistica PAPER.
- XS01 PHASE-TRANCHING (gate xs01_tranche_gate: plateau K=2 E K=3 promossi,
  PORT06 OOS Sh 10.07->10.15 DD 1.48->1.38, FULL pari): la fase del roll e'
  timing-luck (Sharpe daily 1.52-2.33, DD 13.8-33% sulle 12 fasi). Worker con
  param tranches (default 1), 3 sub-book sfasati hold/3 su capitale comune,
  migrazione status legacy, last_bar_ts solo-avanti; runner forward del param;
  _defs tranches=3; hourly_report aggrega i sub-book; validatore esteso e
  PASSATO (K=1 == xsec_sim esatto, K=3 == unione fasi esatto).
- Disaster-cap z sui pairs: pre-registrato e BOCCIATO su tutti i criteri (coda
  OOS peggiora 4/6 coppie, Sharpe -10..-49%, plateau solo del danno; 5a conferma
  stop-su-MR). Record pairs_zstop_research.py; pairs restano senza stop.
- Audit drift: regression-lock trendmax OK (parita' 1.00000, plateau 2.5/3.0/3.5
  confermato), correlazioni cross-famiglia ~0 invariate; PORT06 rolling al
  19-28mo pct (normale) ma FADE 120g al 2o percentile storico -> monitor in TODO
  (nessun ritocco parametri).
- TODO: forming-bar ROT02/TSM01 era gia' fixato (v1.1.10), item chiuso.

Test: pytest 99 passed; validate_honest_workers OK; validate_xsec_worker OK.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:29:14 +00:00
Adriano Dal Pastro e25d5db6ad feat(xsec): dispersion-gate XS01 live (disp_min=0.0313) — Sharpe 3.46, PORT06 OOS 10.07->10.37; FC01 funding-carry scartata
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:42:12 +00:00
Adriano Dal Pastro 61fcc29c5b fix(xsec): cast numpy->Python in _save/_close_book — int64 rompeva json.dumps e bloccava il runner in error-streak
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:23:52 +00:00
Adriano Dal Pastro cc39c36c08 feat(live): REAL-TRUTH ledger — capital aggiornato dal PnL dei fill reali, sim ridotto a diagnostica
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 12:23:52 +00:00
Adriano Dal Pastro a85289d7c7 feat(xsec): XS01 reversione cross-sectional (8 asset) -> PORT06 PAPER
Famiglia NUOVA trovata in sessione (dopo aver scartato trend/breakout/seasonal/
opzioni/funding come rumore): ogni 12h long i perdenti relativi / short i vincenti
su 8 asset, market-neutral. Scorrelata (~0) da pairs e fade -> diversificatore.

- engine canonico scripts/strategies/XS01_cross_sectional.py (no look-ahead, plateau
  OOS Sharpe 2-3.9, 5/5 anni+, edge concentrato 2025, cost-sensitive ~0.35% RT).
- src/live/xsec_worker.py CrossSectionalWorker: validate_xsec_worker == backtest ESATTO
  (4993/1427 trade). Mirror della cadenza engine (entry-to-entry = hold+1).
- gate PORT06: +XS01 -> OOS Sharpe 9.66->10.07, FULL DD 3.68->3.46 (OOS DD +0.17pp,
  risk-contrib 2.2%). xsec_port06_gate.py.
- wiring: _defs XSEC in PORT06 (19 sleeve, family XSEC), build_everything, runner
  kind=xsec, asset_days da supported (fix fetch alt anche per paper sleeves), paper.
- 8 gambe -> niente exec reale -> gira PAPER. Regression-lock 18->19, FULL 7.20->7.34,
  OOS 9.66->10.07. 93 test verdi. Diario 2026-06-09-xs01-cross-sectional.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 21:38:05 +00:00
Adriano Dal Pastro d25d897fd1 feat(pairs): attiva ETH/BTC 15m flat-skip in PORT06 (BLEND, mezza size)
Origine: gioco "Blind Traders" (100 agenti ciechi su BTC/ETH anonimizzati) ->
vincitore = spread ETH/BTC reversion a 15m. Testato sul serio col gate PORT06:
non duplicato (corr 1h vs 15m = 0.37), robusto (16/16 celle Sharpe>1), edge NON
artefatto delle candele flat ETH 15m (filtrandole resta l'83% dello Sharpe).

Percorso live costruito e validato:
- pairs_research.pairs_sim_flat: engine generalizzato con exit LIVE-REALIZABLE
  (arma exit_ready, esce alla 1a barra pulita); regression-lock a pairs_sim.
- PairsWorker: flat_skip + exit_ready + rilevamento flat da OHLC (1h byte-exact).
- runner: fetch diretto dei timeframe sub-orari + override position_size per-sleeve.
- validate_worker_pairs: replay worker == backtest a 15m (8452 vs 8453 trade).
- _defs/build_everything: sleeve PR_ETHBTC_15M (mezza size, pos 0.10) -> PORT06
  FULL 6.43->7.20, OOS 8.58->9.66, DD giu'. Rischio bilanciato col 1h.
- smoke live: Cerbero serve candele 15m fresche; worker ticca.

Diari docs/diary/2026-06-09-*. Caveat slippage: mezza size = blend-tilt prudente.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 11:48:15 +00:00
Adriano Dal Pastro c655604131 feat(live): executor a 2 gambe per i pairs (PairsExecutionClient, shadow) — pronto, spento
PairsExecutionClient (compone ExecutionClient): open_pair (2 market long A/short B,
verifica per-gamba, LEG-RISK unwind se una sola filla), close_pair (2 reduce-only via
close_amount, MAI close_position), register_contract (fetch spec USDC). Spec LTC/ADA/SOL
aggiunti. PairsWorker: ledger reale shadow a 2 gambe resume-safe (_real_open_pair/
_real_close_pair, PnL per gamba dir A=+d/B=-d, doppio arrotondamento riportato). Runner:
pairs_executor gated su execution.pairs_enabled (false di default).

Validazione: test 92/92 (open/close, leg-risk unwind, resume) + smoke testnet
end-to-end (open 2 gambe verificate, close reduce-only, PnL reale -0.039 vs sim -0.036,
conto flat). Smoke ora aborta se ci sono posizioni di produzione + usa solo close_amount.

NB incidente testnet documentato (diario): pulizia manuale con close_position ha flattato
le quote shadow dei fade sul conto condiviso -> auto-riconciliazione al prossimo close.
Lezione: mai close_position su strumenti condivisi.

pairs_enabled resta FALSE: accendere con finestra a conto flat + osservazione.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 10:19:56 +00:00
Adriano Dal Pastro f509f51543 fix(live): ROT02/TSM01 scartano la barra 1d in formazione (forming-bar in _panel)
Code-review follow-up: i worker daily valutavano momentum/regime e bookavano il
return sulla candela 1d PARZIALE al primo poll dopo mezzanotte UTC, poi last_bar_ts
bloccava la rivalutazione a giorno chiuso (stessa classe del bug gia' fixato su
fade/TR01/Pairs). Fix in _panel (un punto solo -> ROT02 e TSM01 lo ereditano) via
src.live.bars.last_bar_is_forming. Replay honest invariato (dati storici: nessuna
barra in formazione). Test: 88/88 + parity drop forming daily bar.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 10:00:16 +00:00
Adriano Dal Pastro f5173fba06 fix(live): 4 hardening da code-review — REAL_DIVERGENCE, outage su feed vuoto, bars.py condiviso, DSL cancel retry
Review multi-agente 7-angoli su 8c4e1cd..HEAD + check trades live:

1. Alert Telegram REAL_DIVERGENCE quando |slippage sim/reale| >= 100bps a
   open/close. Causa scatenante: spike print testnet 10:37 (candela 10:00
   H=65618, O/C ~62400) -> 3 fade BTC short su close fantasma 65266.5, reale
   fillato a 62395 (-440bps), sim +2.26 mai esistiti — passato in silenzio.
2. FEED_OUTAGE anche su feed degradato SENZA eccezione (HTTP 200 + candles
   vuote: i worker saltavano il tick in silenzio, streak a 0). Helper unico
   _outage_tick; chiavi payload uniformate (minuti su start e RIPRESO).
3. src/live/bars.py: detection forming-bar unificata (bar_ms_of /
   last_bar_is_forming / last_settled_idx) — era copiata in 4 punti
   (strategy_worker, basket, pairs, _check_stale_feed hardcoded 1h).
   E' l'invariante di sicurezza EXIT-16: ora una sola implementazione testata.
4. DSL cancel hardening in _real_close: retry su errore transitorio + alert
   REAL_DSL_CANCEL_FAIL se lo stop resta forse orfano sul book (prima l'id
   veniva dimenticato in silenzio); order_not_found = probabile trigger in
   outage -> solo log (il close a valle esce gia' verified=False).

Refutato il finding top dei finder ("stop_market senza trigger"): cerbero-mcp
traduce price->trigger_price+mark, e in produzione 2 DSL armati + 1 ciclo
completo pulito (MR07_BTC).

Test: 83/83 (9 nuovi: bars helper + DSL/divergence con executor finto).
Smoke testnet 4 scenari verdi, conto flat, zero falsi allarmi.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 14:59:58 +00:00
Adriano Dal Pastro 62e272255b feat(live): disaster-bracket on-book sui fade reali + alert FEED_OUTAGE + osservabilita' multi-asset
Punti 5-6 dell'improvement-sweep 2026-06-06 (protezione capitale + osservabilita'):

Punto 5 — disaster bracket:
- ExecutionClient.place_disaster_sl: STOP_MARKET reduce-only a ~-30% dall'ingresso
  (trigger mark price), piazzato a ogni REAL_OPEN (MR01/MR02/MR07/DIP01) e
  cancellato in _real_close. Assicurazione outage: il poll-loop in except lascia
  le posizioni reali senza valutazione exit (ETH gap max storico 33%/1h). In
  operativita' normale non scatta mai -> 0 costo Sharpe. real_dsl_order_id
  persistito (resume-safe). Config overrides.execution.disaster_sl_pct (0.30).
- NB: set_stop_loss di cerbero-mcp e' un private/edit Deribit (solo ordini APERTI)
  -> non usabile su market fillati; il bracket e' un trigger order autonomo via
  place_order(type=stop_market). Cancel di un trigger order risponde 'untriggered'
  (= successo, verificato testnet: re-cancel -> order_not_found).
- Runner: alert Telegram FEED_OUTAGE dopo 5 poll falliti consecutivi (elenco
  posizioni reali aperte) + notifica RIPRESO con durata.

Punto 6 — osservabilita':
- in_position nei _save() di TR01/ROT02/TSM01; hourly_report: sezione MULTI-ASSET
  (book | ultimo flip | freschezza status) — prima i 3 worker erano invisibili
  (collect() filtra su event/in_position che non emettevano); esclusi dalla
  tabella IN CORSO (assume entry/bars single-leg).
- live_shadow_smoke esteso: scenari C/D SHORT (TP-resting BUY mai esercitato
  prima) + disaster bracket in tutti gli scenari.

Verifiche: 72/72 test; smoke testnet 4 scenari verdi (DSL piazzato/cancellato due
lati, zero ordini orfani sul book, conto flat); multi_asset_section renderizza sui
dati live. Diario docs/diary/2026-06-07-sweep-fixes.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 09:36:11 +00:00
Adriano Dal Pastro 3909646028 fix(live): parita' worker multi-asset — TR01 fee x leva, forming-bar su TR01/Pairs, WARN panel corto
Punti 2-4 dell'improvement-sweep 2026-06-06 (fix di parita', nessun cambio di strategia):

- TR01 (basket_trend_worker): fee per flip = POS * LEV * fee_rt/2 come il reference
  honest_improve2._tr_basket_daily:150 (mancava il fattore leva -> fee sotto-caricate 2x,
  bias ottimistico che gonfiava total_capital al ribilancio).
- TR01: crossover EMA e booking del return valutati SOLO su barre 4h COMPLETE
  (la riga -1 e' la candela in corso finche' non e' trascorsa la sua durata) — lezione
  EXIT-16; evidenza live: flip SOL 0->1->0 in 59min nella stessa finestra 4h.
- PairsWorker: entry ED exit valutati sul close di barra COMPLETA, come il backtest
  pairs_research (close settled). Stesso pattern bar_ms di strategy_worker.tick.
- TSM01/ROT02: il silent return su panel inner-join troncato sotto il lookback ora
  emette WARN log + Telegram PANEL_SHORT (helper _warn_panel_short condiviso), gated
  su "era gia' operativo" (no falsi positivi al cold-start), una notifica per episodio.

Test: 72/72 verdi (7 nuovi: forming-bar TR01/pairs + controllo positivo, fee con leva,
PANEL_SHORT warn/dedup/cold-start). Replay parity: validate_worker_pairs ESATTO
(ETH/BTC e BTC/LTC == backtest); validate_honest_workers invariato (TR01 -44% vs ref
+42% IDENTICO pre/post fix: e' la divergenza di convenzione capitale-unico vs
media-equity gia' documentata, da rivisitare a parte).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:23:19 +00:00
Adriano Dal Pastro 2da3457ca7 fix(live): EXIT-16 confirm-SL valutato sul close di barra COMPLETATA + alert STALE_FEED
Il worker valutava il confirm sul prezzo della candela IN FORMAZIONE ad ogni poll,
reintroducendo la wick-sensitivity che EXIT-16 elimina (audit crash ETH 2026-06-05:
2 stop su 3 erano wick-stop che il backtest validato non avrebbe preso in quel
momento). Ora il confirm usa SOLO il close dell'ultima barra completata (riga -1 =
candela in corso finche' now < ts[-1]+bar_ms), buf dall'ATR della stessa barra,
fill al prezzo corrente (~ stress lag_close_exit OK in exit-lab), TP intrabar
invariato. Concausa feed-gap: non mitigabile lato exit (fill reali ~ sim);
entry-guard post-flat TESTATA e BOCCIATA (skippare i segnali dopo barre flat
peggiora tutti gli sleeve ETH: la candela-gap e' l'overshoot che la fade fada).
Aggiunto alert Telegram STALE_FEED (>=2 barre 1h flat -> notifica + gap % al
risveglio, dedup per episodio, solo osservabilita').

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 18:32:14 +00:00
Adriano Dal Pastro a2579d21bc feat(fade): EXIT-16 close-confirm SL — stop solo se il CLOSE sfonda sl∓0.5·ATR14 (immune ai wick)
Param sl_confirm_atr (None = comportamento storico) in FadeStrategy.backtest,
MR01.backtest e StrategyWorker.tick; attivo live a 0.5 sulle 6 fade in _defs.py.
TP intrabar al livello e max_bars invariati; in modalita' confirm il TP ha
priorita' nel bar. Ricerca exit-lab (34 agenti, 3 lenti avversariali + tail
audit): gli stop intrabar da wick sono falsi negativi per le fade. PORT06
canonico: FULL Sharpe 6.47->7.84 DD 4.10->2.60, OOS 8.82->10.06 DD 1.30->1.15.
NB path grezzo non filtrato: ret esplode ma DD per-sleeve sale — la riduzione
DD vive nel config live (trend_max+hurst) + diversificazione, come misurato.
5 test nuovi (59 verdi).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:25:17 +00:00
Adriano Dal Pastro abd396fa54 feat(live): TP reale = LIMIT reduce-only al livello (fix +235bps slippage exit)
All'apertura reale il worker piazza un limit reduce-only al TP della strategia
(quota del SOLO worker, prezzo quantizzato al tick); alla chiusura sim cancella
il resting, riconcilia i fill (anche parziali) via get_trade_history per
order_id e chiude a market solo il residuo. real_tp_order_id persistito
(resume-safe). SL resta market-on-poll (deliberato: trigger Deribit = nuovo
order_id al trigger, fill non verificabile; e il rimbalzo sul SL lavora a
favore). Smoke testnet 2 scenari OK (resting+cancel / fill immediato).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:24:07 +00:00
Adriano Dal Pastro 74670dae05 fix(live): quantizzazione amount senza artefatti float (Decimal) — 72*0.001=0.07200000000000001 causava 'Invalid params' su Deribit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 16:10:28 +00:00
Adriano Dal Pastro 092e809946 docs(live): leva per-strumento NON impostabile su Deribit (set_leverage=400, verificato nei log Cerbero) — l'esposizione la decide la size
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 17:52:55 +00:00
Adriano Dal Pastro 719509fb2f feat(live): alert Telegram esecuzione reale + doc shadow-execution in CLAUDE.md
- telegram_notifier: eventi REAL_EXEC_LIVE (primo ordine reale verificato per worker)
  e REAL_OPEN_FAIL (apertura reale non verificata)
- StrategyWorker: notifica una-tantum al primo REAL_OPEN verificato + ogni FAIL;
  flag real_first_notified persistito
- CLAUDE.md: documentato lo shadow-execution (ExecutionClient, lineari USDC,
  verifica sul trade, fee reali, config, alert, smoke)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:20:08 +00:00
Adriano Dal Pastro cb1b6ea46a feat(live): esecuzione REALE su Deribit testnet (shadow) per i 6 fade sui lineari USDC
- ExecutionClient: notional->amount (lineare USDC + inverse), open/close_amount
  reduce-only, verifica sul trade (order_id), fee reali lette dai trades[]
- CerberoClient: place_order market + reduce_only, get_trade_history
- StrategyWorker: shadow (REAL_OPEN/REAL_CLOSE accanto al sim), ledger reale
  parallelo persistito, confronto slippage/fee sim-vs-reale
- runner+portfolios.yml: config execution (6 fade MR01/MR02/MR07 x BTC/ETH su
  BTC_USDC/ETH_USDC-PERPETUAL), capitale 2000
- smoke: live_exec_smoke (layer) + live_shadow_smoke (catena worker), provati su testnet

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:11:26 +00:00
Adriano Dal Pastro b5de241ebc revert(live): rimuovi fallback mainnet — il paper deve usare il venue di esecuzione (testnet)
Il fallback a Deribit mainnet per i dati introduceva una DIVERGENZA paper<->esecuzione: il paper
simulava su prezzi mainnet ma gli ordini (place_order via Cerbero) andrebbero su TESTNET, i cui
prezzi/liquidità divergono ~9%. Un paper trader deve usare la STESSA fonte/venue dove gli ordini
verrebbero eseguiti, altrimenti non predice il comportamento reale. Durante un outage testnet il
runner si mette in pausa (corretto: senza il venue non si eseguirebbe comunque). Rimosso
get_historical_mainnet e il wiring nel runner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 19:50:47 +00:00
Adriano Dal Pastro 8e72d7ad02 feat(live): fallback OHLCV a Deribit MAINNET quando Cerbero/testnet e' giu'
Deribit testnet (test.deribit.com) va giu' periodicamente (502) e Cerbero lo rilancia ->
il runner si bloccava senza dati. Aggiunto CerberoClient.get_historical_mainnet (Deribit MAINNET
public, NO-AUTH, paginato sotto il cap ~5000 candele/chiamata) e fallback nel runner: try Cerbero
-> on fail/empty usa mainnet. Prezzi REALI (meglio del testnet farlocco per il paper). Verificato
durante l'outage: tutti gli 8 strumenti (BTC/ETH + alt _USDC) coperti su mainnet. Log una-tantum
all'attivazione/disattivazione del fallback.

Caveat: testnet e mainnet hanno prezzi diversi (~9%) -> al primo switch le posizioni aperte su
prezzi testnet vanno resettate (transizione pulita).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 16:58:14 +00:00
Adriano Dal Pastro 4770a8368f feat(deploy): tag di versione nei msg Telegram, +1 ad ogni deploy
File VERSION (semver, cotto nell'immagine) letto da src/version.py. Compare nelle notifiche trade
(telegram_notifier) e nel report orario -> sai quale codice ha generato quale msg.
scripts/bump_version.py incrementa la patch; scripts/deploy.sh = bump+commit+rebuild (versione
aumenta ad OGNI deploy). v1.0.0 = primo release versionato (include hurst loss-guard).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 14:34:18 +00:00
Adriano Dal Pastro ab4f706057 fix(live): win netto-fee + filtro TP edge-minimo sulle fade
Due correzioni emerse da close live con win=True ma pnl<0.

1) Metrica win lorda -> netta. _close_position contava is_win=trade_return>0
   (lordo), gonfiando l'accuracy: un take-profit colpito con mossa < fee RT
   risultava "win" pur perdendo. 51 close live: 39 win (76,5%) -> 13 falsi win
   -> accuracy netta reale 52,9%. Fix: is_win = net > 0. Capitale/PnL erano
   già corretti (netti). Contatori persistiti riconciliati a parte (MR01/DIP01
   BTC 7->1).

2) Filtro edge-minimo min_tp_frac. I 13 falsi win erano tutti MR01/DIP01 BTC in
   regime piatto: TP (la media) entro il costo round-trip -> perdenti garantiti.
   Aggiunto param min_tp_frac (default 0.0=off) a tutte e 4 le fade (MR01 banda,
   MR02 midpoint, MR07 ATR, DIP01): salta i segnali col TP entro la soglia.
   Non si "allarga" il TP (rischierebbe di perdere di piu'): si evita la trade.
   Cablato live a 0.0015 (1,5x fee) in _defs.py.

Validazione backtest BTC+ETH 1h: neutro su tutte le fade (0-1 trade rimossi,
pnl invariato o +leggero su DIP01). I micro-scalp sotto-fee non esistono nello
storico -> artefatto del regime attuale. Filtro puro-upside.

Test: test_win_net_of_fees.py, test_min_tp_frac.py (monotonia + gap > soglia +
default-off invariato). Suite: 50 passed.

NB deploy: il sorgente e' COPY nell'immagine, non montato -> serve
`docker compose up -d --build`, non un semplice restart (vale anche per il fix
SH01 horizon-exit, andato live solo con questo rebuild). Volume ./data persiste,
14 worker in RESUME puliti.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 11:07:30 +00:00
Adriano Dal Pastro 53e0965c4b fix(live): exit a orizzonte per strategie senza TP/SL (SH01)
Lo StrategyWorker onorava max_bars (orizzonte del Signal) solo nel ramo
`if self.tp and self.sl`. SH01 (shape-ML, H=12) non porta TP/SL, quindi
cadeva sul fallback legacy hold_bars=3 e chiudeva a 3 barre invece delle
12 validate: l'edge (asimmetria sull'orizzonte, non frequenza) non aveva
tempo di realizzarsi -> accuratezza live falsata (33%), tutti exit
"hold_limit" a bars_held=3.

Aggiunto un ramo `elif self.max_bars` che esce a "time_limit" quando
bars_held>=max_bars, prima del fallback hold_bars. Tocca solo le
strategie horizon-only (SH01); le fade con tp+sl+max_bars sono invariate.

Test: tests/portfolio/test_horizon_exit.py (resta in posizione a 3 barre
con max_bars=12; esce a 12 con reason time_limit). Suite: 43 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 09:05:53 +00:00
Adriano 49039ac286 fix(live): StrategyWorker esce intrabar su TP/SL (high/low, al livello) come il backtest
Chiude il gap live-vs-backtest delle fade/DIP01: prima il worker controllava solo il
close, ora controlla high/low della barra ed esce AL LIVELLO tp/sl (SL prioritario),
identico alla semantica intrabar del backtest. +4 test. Pairs/rotation/tsmom invariati.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 18:00:12 +02:00
Adriano 1e60835612 feat(live): TsmomWorker (TSM01) consenso TSMOM multi-orizzonte risk-gated 2026-05-29 17:42:44 +02:00
Adriano a40315563e feat(live): RotationWorker (ROT02) dual-momentum top-k risk-gated 2026-05-29 17:41:13 +02:00
Adriano e7e8041dae feat(live): BasketTrendWorker (TR01) EMA-cross long/flat multi-asset
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:39:11 +02:00
Adriano ce601c4507 feat(live): DIP01 dip-buy come Strategy single-asset (worker via StrategyWorker)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:36:32 +02:00