docs: aggiorna strategie_attive.html + CLAUDE/TODO a v1.1.20 (XS01, real-truth, 19 sleeve)

- make_strategy_doc: nuova famiglia XSEC — card XS01 (meccanismo, dispersion-gate
  disp_min=0.0313, gate PORT06 OOS 10.07->10.37) con grafico book+gate e tabella
  per anno (engine canonico ungated); pesi aggiornati a 19 sleeve (5.69/5.26/2.94%);
  header con real-truth ledger e 4 book paper; bullet metodologia real-truth;
  ripuliti i riferimenti 'oggi' (EXIT-16 su DIP01, fix punto-10 SH01)
- strategie_attive.html rigenerato: v1.1.20, backtest canonico FULL Sharpe 7.34 /
  DD 3.46% — OOS Sharpe 10.07 / DD 1.48% (19 sleeve, XS01 incluso)
- CLAUDE.md: sezione XS01 (famiglia XSEC, gate, dispersion-gate live-only, FC01
  scartata), copertura reale 15/19, varianti gioco options/session/grid in struttura
- TODO.md: stato esecuzione aggiornato (6 pairs, XS01 paper, real-truth)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-11 10:00:48 +00:00
parent 8d69a0cef5
commit ba5ec7bd6b
4 changed files with 155 additions and 46 deletions
+25 -6
View File
@@ -61,7 +61,11 @@ scripts/analysis/ → ricerca/validazione OOS fee-aware (strategy_research,
option_overlay_lab.py (overlay opzioni prezzato; mr02eth_port06_gate.py = gate swap-sleeve); option_overlay_lab.py (overlay opzioni prezzato; mr02eth_port06_gate.py = gate swap-sleeve);
pairs15m_*.py (gate/flatcheck/smoke ETH/BTC 15m -> sleeve PR_ETHBTC_15M) pairs15m_*.py (gate/flatcheck/smoke ETH/BTC 15m -> sleeve PR_ETHBTC_15M)
scripts/games/ → gioco "Blind Traders": 100 agenti ciechi su BTC/ETH anonimi (engine.py, scripts/games/ → gioco "Blind Traders": 100 agenti ciechi su BTC/ETH anonimi (engine.py,
arena.py epoche+cull, agent_brief.py digest, run_game.py). Origine del BLEND 15m arena.py epoche+cull, agent_brief.py digest, run_game.py). Origine del BLEND 15m.
Varianti: options_* (strutture in opzioni, BS+skew+DVOL; opt_calibrate da
cerbero-bite), session_* (pattern orari), grid_* (griglie da STRATEGIA_GRIGLIA.md;
gate scripts/analysis/grid_game_gate.py). arena: GAME_NO_LIVE=1 vieta le
strategie gia' deployate (pairs, fade zscore/breakout/momentum)
scripts/bump_version.py, scripts/deploy.sh → versionamento e deploy (bump+commit+rebuild) scripts/bump_version.py, scripts/deploy.sh → versionamento e deploy (bump+commit+rebuild)
VERSION → versione semver (cotta nell'immagine, +1 ad ogni deploy) VERSION → versione semver (cotta nell'immagine, +1 ad ogni deploy)
strategies.yml → config multi-strategy paper trader strategies.yml → config multi-strategy paper trader
@@ -386,8 +390,23 @@ queste fade, ma va confermato col paper trader live prima di rischiare capitale
## Portafogli ## Portafogli
- Un `Portfolio` è un oggetto di prima classe (`src/portfolio/`) con definizione (sleeve + schema pesi) e due facce sulla **STESSA** definizione: `.backtest()` (riusa il builder unico di `sleeves.py` → parità esatta con `report_families`) e live (`PortfolioRunner`: capitale pool condiviso, sizing per peso, ribilancio giornaliero, ledger aggregato in `data/portfolios/{code}/`). - Un `Portfolio` è un oggetto di prima classe (`src/portfolio/`) con definizione (sleeve + schema pesi) e due facce sulla **STESSA** definizione: `.backtest()` (riusa il builder unico di `sleeves.py` → parità esatta con `report_families`) e live (`PortfolioRunner`: capitale pool condiviso, sizing per peso, ribilancio giornaliero, ledger aggregato in `data/portfolios/{code}/`).
- **Schemi peso:** `equal` (default), `cap` (tetto per famiglia, es. pairs 33% — config raccomandata), `inverse_vol`, `cluster_rp` (equal fra cluster naturali poi inverse-vol intra-cluster), `manual`. Definiti in `weighting.py`; la chiave cap è la famiglia (PAIRS/FADE/HONEST/SHAPE/TSM). - **Schemi peso:** `equal` (default), `cap` (tetto per famiglia, es. pairs 33% — config raccomandata), `inverse_vol`, `cluster_rp` (equal fra cluster naturali poi inverse-vol intra-cluster), `manual`. Definiti in `weighting.py`; la chiave cap è la famiglia (PAIRS/FADE/HONEST/SHAPE/TSM/XSEC).
- **Default `portfolios.yml`:** PORT06 (master+shape), `weighting=cap pairs 0.33 + shape 0.0588`, leva 2x, ribilancio 1D. Backtest PORT06 canonico (dati al 2026-05-28, pre-cap-shape): FULL Sharpe 6.47 DD 4.10% / OOS Sharpe 8.82 DD 1.30%; **con EXIT-16 close-confirm (config live attuale): FULL 7.84 / 2.60%, OOS 10.06 / 1.15%** (i vecchi 6.07/8.19 erano pre-loss-guard/pre-refresh dati). Col cap SHAPE (2026-06-05): FULL 6.43 / 3.96%, OOS 8.58 / 1.36% — assicurazione sulla coda SH01, vedi sotto. **Col BLEND ETH/BTC 15m (2026-06-09, v1.1.16, vedi sotto): FULL 7.20 / 3.68%, OOS 9.66 / 1.31% — 18 sleeve.** - **Default `portfolios.yml`:** PORT06 (master+shape), `weighting=cap pairs 0.33 + shape 0.0588`, leva 2x, ribilancio 1D. Backtest PORT06 canonico (dati al 2026-05-28, pre-cap-shape): FULL Sharpe 6.47 DD 4.10% / OOS Sharpe 8.82 DD 1.30%; **con EXIT-16 close-confirm (config live attuale): FULL 7.84 / 2.60%, OOS 10.06 / 1.15%** (i vecchi 6.07/8.19 erano pre-loss-guard/pre-refresh dati). Col cap SHAPE (2026-06-05): FULL 6.43 / 3.96%, OOS 8.58 / 1.36% — assicurazione sulla coda SH01, vedi sotto. Col BLEND ETH/BTC 15m (2026-06-09, v1.1.16, vedi sotto): FULL 7.20 / 3.68%, OOS 9.66 / 1.31% — 18 sleeve. **Con XS01 (2026-06-09, vedi sotto): OOS Sharpe 10.07, FULL DD 3.46 — 19 sleeve** (pool live real-only 15; i 4 book multi-asset TR01/ROT02/TSM01/XS01 girano in statistica).
- **XS01 — Cross-Sectional Reversion (ATTIVO LIVE 2026-06-09; dispersion-gate v1.1.20, 2026-06-10).**
Famiglia nuova XSEC, distinta da pairs (pairwise) e fade (single-asset): ogni `hold=12` ore
classifica 8 crypto (UNIVERSE8) per rendimento a `lb=48` ore e va long i perdenti relativi /
short i vincenti (peso ∝ (ret media cross-section)), market-neutral gross 1, fee 0.20%
RT/book (turnover 2). Scorrelato ~0 da pairs e fade. FULL Sharpe ~3.3, plateau lb 12-72 ×
hold 6-24; cost-sensitive (muore a ~0.35% RT/book). Gate PORT06: OOS Sharpe 9.66→10.07,
FULL DD 3.68→3.46. **Dispersion-gate** (`disp_min=0.0313` = p50 TRAIN): entra solo se la
std cross-section del momentum ≥ soglia — diagnostica monotona TRAIN+OOS, plateau p30-p70,
standalone Sharpe 2.50→3.46 (regge fee 2x), PORT06 OOS 10.07→10.37 a DD pari. Come
trend/hurst sulle fade, il gate agisce SOLO sul path live (backtest canonico non filtrato
→ il live farà meglio del backtest). 8 gambe → PAPER (niente esecuzione reale a €2k).
Worker `XsecWorker` validato (`validate_xsec_worker`: replay == backtest esatto). Strategia
`scripts/strategies/XS01_cross_sectional.py`, gate `scripts/analysis/xsec_port06_gate.py` /
`xs01_dispersion_gate.py`. NB scartata nella stessa tornata: FC01 funding-carry (nessun
edge su 6.5 anni). Diari `docs/diary/2026-06-09/10-*`.
- **BLEND ETH/BTC 15m flat-skip (ATTIVO LIVE v1.1.16, 2026-06-09).** Sleeve `PR_ETHBTC_15M` accanto al 1h: pairs ETH/BTC a **15m** (n=66, z_in=1.674, z_exit=1.0, max_bars=35) a **mezza size** (`params.position_size=0.10`). **Origine: gioco "Blind Traders"** (100 agenti ciechi su BTC/ETH anonimizzati → riscoprono la mean-reversion, vincitore = spread ETH/BTC 15m; `scripts/games/`). Gate PORT06 sul serio: **non duplicato (corr 1h↔15m = 0.37)**, robusto (16/16 celle Sharpe>1), e l'edge **NON è artefatto delle candele flat ETH 15m** (16% storico; filtrandole resta l'83% dello Sharpe). Engine `pairs_research.pairs_sim_flat` con uscita **LIVE-REALIZABLE** (`flat_skip`: niente entry/exit su barre O=H=L=C, esce alla 1a barra pulita), **regression-lock** a `pairs_sim` con flat_skip=False. **Worker validato** (`validate_worker_pairs` a 15m: replay == backtest, 8452 vs 8453 trade; 1h byte-exact). Runner: fetch sub-orario diretto da Cerbero + `pos_for_spec` override **per-sleeve** (params.position_size > famiglia > globale). Mezza size perché a peso pieno il 15m pesava il 25.8% del rischio PORT06 (→ 11.5%, bilanciato col 1h) — blend-tilt prudente sul **caveat slippage** (a slippage realistico il vantaggio di Sharpe regge, quello di DD si assottiglia: il vero banco di prova è il ledger reale shadow). Diari `docs/diary/2026-06-09-pairs15m-*.md`, gate `scripts/analysis/pairs15m_port06_gate.py` / `pairs15m_gate_final.py` / `pairs15m_flatcheck.py`, smoke `pairs15m_live_smoke.py`. - **BLEND ETH/BTC 15m flat-skip (ATTIVO LIVE v1.1.16, 2026-06-09).** Sleeve `PR_ETHBTC_15M` accanto al 1h: pairs ETH/BTC a **15m** (n=66, z_in=1.674, z_exit=1.0, max_bars=35) a **mezza size** (`params.position_size=0.10`). **Origine: gioco "Blind Traders"** (100 agenti ciechi su BTC/ETH anonimizzati → riscoprono la mean-reversion, vincitore = spread ETH/BTC 15m; `scripts/games/`). Gate PORT06 sul serio: **non duplicato (corr 1h↔15m = 0.37)**, robusto (16/16 celle Sharpe>1), e l'edge **NON è artefatto delle candele flat ETH 15m** (16% storico; filtrandole resta l'83% dello Sharpe). Engine `pairs_research.pairs_sim_flat` con uscita **LIVE-REALIZABLE** (`flat_skip`: niente entry/exit su barre O=H=L=C, esce alla 1a barra pulita), **regression-lock** a `pairs_sim` con flat_skip=False. **Worker validato** (`validate_worker_pairs` a 15m: replay == backtest, 8452 vs 8453 trade; 1h byte-exact). Runner: fetch sub-orario diretto da Cerbero + `pos_for_spec` override **per-sleeve** (params.position_size > famiglia > globale). Mezza size perché a peso pieno il 15m pesava il 25.8% del rischio PORT06 (→ 11.5%, bilanciato col 1h) — blend-tilt prudente sul **caveat slippage** (a slippage realistico il vantaggio di Sharpe regge, quello di DD si assottiglia: il vero banco di prova è il ledger reale shadow). Diari `docs/diary/2026-06-09-pairs15m-*.md`, gate `scripts/analysis/pairs15m_port06_gate.py` / `pairs15m_gate_final.py` / `pairs15m_flatcheck.py`, smoke `pairs15m_live_smoke.py`.
- **SH01 SENZA STOP-LOSS — by design, CONFERMATO da ricerca (2026-06-05).** Dopo il crash ETH (15.6% su un trade SH01 live), ricerca multi-agente con harness dedicato `scripts/analysis/sh01_exit_lab.py` (cache segnali walk-forward, engine con **fill gap-aware** `worse(livello, open)`, parity esatta con explore_lab, protocollo train≤2023-11-01/OOS): **11 famiglie di stop testate (ATR intrabar/close-confirm, %, chandelier, breakeven, giveback, loser-timestop, disaster-cap close+intrabar, swing, vol-regime), 0 sopravvissute** al gate (ETH migliorato senza degradare BTC, train E oos, plateau). Pattern: ogni stop stretto abbastanza da toccare la coda ETH rompe BTC; ogni stop largo non arriva alla coda; nei crash il fill è al gap, non al livello (lo stop "protettivo" PEGGIORA la coda OOS). Mitigazione adottata: **cap famiglia SHAPE a 0.0588 in PORT06** (≈ dimezzata; costo OOS Sharpe 0.24, FULL DD 0.14pp) — la prossima coda impatta il conto per metà. NON impostare mai `sl`/`sl_confirm_atr` su SH_BTC/SH_ETH. Direzione futura: liquidity-gate sull'entry (skip dopo feed flat). Diario `docs/diary/2026-06-05-sh01-sl-research.md`. - **SH01 SENZA STOP-LOSS — by design, CONFERMATO da ricerca (2026-06-05).** Dopo il crash ETH (15.6% su un trade SH01 live), ricerca multi-agente con harness dedicato `scripts/analysis/sh01_exit_lab.py` (cache segnali walk-forward, engine con **fill gap-aware** `worse(livello, open)`, parity esatta con explore_lab, protocollo train≤2023-11-01/OOS): **11 famiglie di stop testate (ATR intrabar/close-confirm, %, chandelier, breakeven, giveback, loser-timestop, disaster-cap close+intrabar, swing, vol-regime), 0 sopravvissute** al gate (ETH migliorato senza degradare BTC, train E oos, plateau). Pattern: ogni stop stretto abbastanza da toccare la coda ETH rompe BTC; ogni stop largo non arriva alla coda; nei crash il fill è al gap, non al livello (lo stop "protettivo" PEGGIORA la coda OOS). Mitigazione adottata: **cap famiglia SHAPE a 0.0588 in PORT06** (≈ dimezzata; costo OOS Sharpe 0.24, FULL DD 0.14pp) — la prossima coda impatta il conto per metà. NON impostare mai `sl`/`sl_confirm_atr` su SH_BTC/SH_ETH. Direzione futura: liquidity-gate sull'entry (skip dopo feed flat). Diario `docs/diary/2026-06-05-sh01-sl-research.md`.
- **Data layer Cerbero v2:** `get_historical_v2` unificato + `get_instruments` (naming robusto) + `get_ticker_batch`. Trading su Deribit. - **Data layer Cerbero v2:** `get_historical_v2` unificato + `get_instruments` (naming robusto) + `get_ticker_batch`. Trading su Deribit.
@@ -411,9 +430,9 @@ queste fade, ma va confermato col paper trader live prima di rischiare capitale
single-leg con exit a orizzonte H=12 — niente TP/SL, `_place_real_tp` no-op e `_real_close` chiude single-leg con exit a orizzonte H=12 — niente TP/SL, `_place_real_tp` no-op e `_real_close` chiude
tutto market reduce-only, disaster-bracket on-book come unica protezione di coda (v1.1.13). Motivo: tutto market reduce-only, disaster-bracket on-book come unica protezione di coda (v1.1.13). Motivo:
SH01 è il diversificatore più decorrelato (senza i 5 sleeve PAPER il DD del portafoglio sale SH01 è il diversificatore più decorrelato (senza i 5 sleeve PAPER il DD del portafoglio sale
3.96→5.35%). Copertura reale ora ~83% (fade+DIP+**6 pairs incl. ETH/BTC 15m**+SH01); restano 3.96→5.35%). Copertura reale ora 15 sleeve su 19 (fade+DIP+**6 pairs incl. ETH/BTC 15m**+SH01);
simulati TR01/ROT02/TSM01 (book multi-asset, bloccati dal capitale: rumore arrotondamento 20-30% restano simulati TR01/ROT02/TSM01/XS01 (book multi-asset, bloccati dal capitale: rumore
a €2k, serve ~€20k). Diari `docs/diary/2026-06-08-pairs-executor.md`. arrotondamento 20-30% a €2k, serve ~€20k). Diari `docs/diary/2026-06-08-pairs-executor.md`.
- **ESECUZIONE REALE — shadow (v1.0.3, 2026-06-03).** I **6 fade** (MR01/MR02/MR07 × BTC/ETH) eseguono ordini **REALI su Deribit testnet** accanto al fill simulato (*shadow*: sim + reale in parallelo, il sim resta la verità che guida le decisioni). `src/live/execution.py` `ExecutionClient`: `open` (market) + `close_amount` (market **reduce-only della SOLA quota del worker** — i 3 fade BTC condividono lo strumento e le posizioni si nettano per conto, quindi NON si usa `close_position` che flatterebbe le quote altrui); **verifica l'esecuzione sul TRADE** (order_id in `get_trade_history`, non sulla size netta aggregata); **fee REALI lette dai `trades[]`**. Strumenti = **lineari USDC** (`BTC_USDC`/`ETH_USDC-PERPETUAL`, amount nel base-coin, step 0.0001/0.001): scelti perché il **payoff lineare == matematica del backtest** (l'inverse `*-PERPETUAL` introdurrebbe una base 1/prezzo) e fee/PnL sono in USDC. Lo `StrategyWorker` tiene un **ledger reale parallelo** (`real_capital`, persistito) e logga `REAL_OPEN`/`REAL_CLOSE` col confronto **slippage** (prezzo sim vs eseguito) e **fee** (assunta 0.10% vs reale). Config: `portfolios.yml``overrides.execution {enabled, sleeves:[MR01,MR02,MR07,DIP01], instruments:{BTC:BTC_USDC-PERPETUAL, ETH:ETH_USDC-PERPETUAL}}` (**DIP01 aggiunto il 2026-06-04**: stesso wiring single-leg, TP resting incluso); pairs/rotation/tsmom/shape restano **simulati** (pairs richiede un executor a 2 gambe con gestione leg-risk; shape non ha TP). **Fee reali misurate = 0.05%/lato = 0.10% RT** (== assunto del backtest, su ETH; BTC inverse era ~0.094%). **Alert Telegram:** `REAL_EXEC_LIVE` (primo ordine reale verificato per worker) + `REAL_OPEN_FAIL`. Smoke (testnet, €0): `scripts/analysis/live_exec_smoke.py` (layer: ordine→verifica→fee) e `live_shadow_smoke.py` (catena worker open/close). **Capitale live portato a 2000** (notional fade ~$35) per ridurre il rumore di arrotondamento su BTC (step lineare ~$6.7). NB: ledger reale ≠ ledger sim — i worker già in posizione sim a un restart non hanno quota reale corrispondente; lo shadow reale parte pulito dalla prossima apertura. - **ESECUZIONE REALE — shadow (v1.0.3, 2026-06-03).** I **6 fade** (MR01/MR02/MR07 × BTC/ETH) eseguono ordini **REALI su Deribit testnet** accanto al fill simulato (*shadow*: sim + reale in parallelo, il sim resta la verità che guida le decisioni). `src/live/execution.py` `ExecutionClient`: `open` (market) + `close_amount` (market **reduce-only della SOLA quota del worker** — i 3 fade BTC condividono lo strumento e le posizioni si nettano per conto, quindi NON si usa `close_position` che flatterebbe le quote altrui); **verifica l'esecuzione sul TRADE** (order_id in `get_trade_history`, non sulla size netta aggregata); **fee REALI lette dai `trades[]`**. Strumenti = **lineari USDC** (`BTC_USDC`/`ETH_USDC-PERPETUAL`, amount nel base-coin, step 0.0001/0.001): scelti perché il **payoff lineare == matematica del backtest** (l'inverse `*-PERPETUAL` introdurrebbe una base 1/prezzo) e fee/PnL sono in USDC. Lo `StrategyWorker` tiene un **ledger reale parallelo** (`real_capital`, persistito) e logga `REAL_OPEN`/`REAL_CLOSE` col confronto **slippage** (prezzo sim vs eseguito) e **fee** (assunta 0.10% vs reale). Config: `portfolios.yml``overrides.execution {enabled, sleeves:[MR01,MR02,MR07,DIP01], instruments:{BTC:BTC_USDC-PERPETUAL, ETH:ETH_USDC-PERPETUAL}}` (**DIP01 aggiunto il 2026-06-04**: stesso wiring single-leg, TP resting incluso); pairs/rotation/tsmom/shape restano **simulati** (pairs richiede un executor a 2 gambe con gestione leg-risk; shape non ha TP). **Fee reali misurate = 0.05%/lato = 0.10% RT** (== assunto del backtest, su ETH; BTC inverse era ~0.094%). **Alert Telegram:** `REAL_EXEC_LIVE` (primo ordine reale verificato per worker) + `REAL_OPEN_FAIL`. Smoke (testnet, €0): `scripts/analysis/live_exec_smoke.py` (layer: ordine→verifica→fee) e `live_shadow_smoke.py` (catena worker open/close). **Capitale live portato a 2000** (notional fade ~$35) per ridurre il rumore di arrotondamento su BTC (step lineare ~$6.7). NB: ledger reale ≠ ledger sim — i worker già in posizione sim a un restart non hanno quota reale corrispondente; lo shadow reale parte pulito dalla prossima apertura.
- **Disaster-bracket on-book + alert outage (v1.1.4, 2026-06-07).** A ogni `REAL_OPEN` dei fade - **Disaster-bracket on-book + alert outage (v1.1.4, 2026-06-07).** A ogni `REAL_OPEN` dei fade
eseguiti il worker piazza uno **STOP_MARKET reduce-only a ~30%** dall'ingresso (trigger sul mark, eseguiti il worker piazza uno **STOP_MARKET reduce-only a ~30%** dall'ingresso (trigger sul mark,
+10 -8
View File
@@ -1,17 +1,18 @@
# TODO — prossimi passi # TODO — prossimi passi
> Raccolta dei follow-up aperti. Aggiornato 2026-06-08 (pairs reali ATTIVI v1.1.12; > Raccolta dei follow-up aperti. Aggiornato 2026-06-11 (XS01 dispersion-gate live v1.1.20;
> roadmap improvement-sweep 10/10 completata). > real-truth ledger attivo; reset portafoglio 2026-06-10).
## Stato esecuzione per sleeve (REALE vs SIMULATO) ## Stato esecuzione per sleeve (REALE vs SIMULATO)
**REALE (shadow su Deribit testnet) — il "vero" risultato monetario:** **REALE (shadow su Deribit testnet, REAL-TRUTH: il ledger segue i fill reali) — 15 sleeve:**
- 6 fade (MR01/MR02/MR07 × BTC/ETH) + DIP01_BTC → single-leg, v1.0.3+ - 6 fade (MR01/MR02/MR07 × BTC/ETH) + DIP01_BTC → single-leg, v1.0.3+
- 5 pairs PR01 (ETH/BTC, LTC/ETH, ADA/ETH, BTC/LTC, ETH/SOL) → 2 gambe, v1.1.12 (2026-06-08) - 6 pairs PR01 (ETH/BTC, LTC/ETH, ADA/ETH, BTC/LTC, ETH/SOL + ETH/BTC 15m) → 2 gambe,
v1.1.12 (2026-06-08); il 15m dal v1.1.16 (2026-06-09)
- SH01 × BTC/ETH → single-leg, exit a orizzonte (no TP/SL), v1.1.13 (2026-06-08) - SH01 × BTC/ETH → single-leg, exit a orizzonte (no TP/SL), v1.1.13 (2026-06-08)
**SIMULATO (paper, NON esegue reale) — categoria distinta:** **SIMULATO (paper, NON esegue reale) — 4 book multi-asset, fuori dal capitale-pool:**
- TR01 / ROT02 / TSM01 → book multi-asset, bloccati dal CAPITALE (rumore arrotondamento) - TR01 / ROT02 / TSM01 / XS01 → bloccati dal CAPITALE (rumore arrotondamento)
## Esecuzione reale — pezzi mancanti ## Esecuzione reale — pezzi mancanti
@@ -20,7 +21,7 @@
(_place_real_tp no-op senza TP, _real_close chiude tutto market reduce-only a orizzonte). (_place_real_tp no-op senza TP, _real_close chiude tutto market reduce-only a orizzonte).
Bastava accettare kind 'ml' in _exec_for + SH01 in execution.sleeves. Disaster-bracket Bastava accettare kind 'ml' in _exec_for + SH01 in execution.sleeves. Disaster-bracket
on-book = unica protezione di coda. Test SH01 open/close reale OK. on-book = unica protezione di coda. Test SH01 open/close reale OK.
- [ ] **Multi-asset in reale** (SIMULATO: TR01/ROT02/TSM01) — **SBLOCCATO DA CAPITALE ≥ ~€20k**. - [ ] **Multi-asset in reale** (SIMULATO: TR01/ROT02/TSM01/XS01) — **SBLOCCATO DA CAPITALE ≥ ~€20k**.
Strumenti USDC tutti esistenti (BNB/DOGE/XRP inclusi), ma a €2k il rumore di arrotondamento Strumenti USDC tutti esistenti (BNB/DOGE/XRP inclusi), ma a €2k il rumore di arrotondamento
per-asset è 20-30% (DOGE/XRP/SOL step grandi in $, esposizione frammentata su 5-8 asset) → per-asset è 20-30% (DOGE/XRP/SOL step grandi in $, esposizione frammentata su 5-8 asset) →
l'esecuzione reale misurerebbe il rumore dei lotti, non la strategia. Serve un l'esecuzione reale misurerebbe il rumore dei lotti, non la strategia. Serve un
@@ -33,7 +34,8 @@
- [ ] **Valutare aumento capitale a €5.000-10.000** per togliere il rumore di arrotondamento. - [ ] **Valutare aumento capitale a €5.000-10.000** per togliere il rumore di arrotondamento.
A €2.000 il rumore BTC per trade è ~2.4% (morde); soglie: ~€4.800 (<1%), ~€9.500 (<0.5%, A €2.000 il rumore BTC per trade è ~2.4% (morde); soglie: ~€4.800 (<1%), ~€9.500 (<0.5%,
"punto dolce"), ~€19.000 (trascurabile). Le commissioni invece sono % e neutre al capitale. "punto dolce"), ~€19.000 (trascurabile). Le commissioni invece sono % e neutre al capitale.
Riguarda solo i 7 single-leg che eseguono reale; pairs/SH01 sono simulati. Col real-truth ledger il rumore di arrotondamento entra DIRETTAMENTE nell'equity → più
capitale = ledger più fedele alla strategia. Riguarda i 15 sleeve che eseguono reale.
## Follow-up dal code-review (bassa priorità, non urgenti) ## Follow-up dal code-review (bassa priorità, non urgenti)
File diff suppressed because one or more lines are too long
+86 -15
View File
@@ -379,13 +379,43 @@ def chart_sh01():
return b64(fig) return b64(fig)
def chart_xs01():
"""Book corrente (long perdenti/short vincenti) + dispersione cross-section col gate."""
from scripts.strategies.XS01_cross_sectional import aligned_panel, UNIVERSE, LB
M = aligned_panel()
logC = np.log(M.values)
ts = pd.to_datetime(M.index, unit="ms", utc=True)
dm = logC[-1] - logC[-1 - LB]
dm = dm - dm.mean()
w = -dm / np.sum(np.abs(dm))
fig, (ax, ax2) = plt.subplots(1, 2, figsize=(8.6, 3.4), width_ratios=[1, 1.5])
ax.bar(UNIVERSE, w * 100, color=[C_TP if x > 0 else C_SL for x in w])
ax.set_ylabel("peso book %")
ax.tick_params(axis="x", rotation=60)
ax.set_title("book: long i perdenti relativi,\nshort i vincenti (mom 48h demeaned)",
loc="left", fontweight="bold", fontsize=9)
D = logC[LB:] - logC[:-LB]
disp = pd.Series(D.std(axis=1), index=ts[LB:]).iloc[-24 * 180:]
ax2.plot(disp.index, disp.values, color="#333", lw=0.7)
ax2.axhline(0.0313, color=C_SL, ls="--", lw=1.2)
on = disp.values >= 0.0313
ax2.fill_between(disp.index, 0, disp.values.max(), where=on, alpha=0.10, color=C_TP)
ax2.annotate("disp_min 0.0313 (p50 TRAIN)\nentry solo sopra soglia",
(disp.index[-1], 0.0313), xytext=(-150, 10),
textcoords="offset points", color=C_SL, fontsize=8)
ax2.set_title("dispersion-gate: std cross-section del momentum",
loc="left", fontweight="bold", fontsize=9)
fig.tight_layout()
return b64(fig)
def chart_weights(): def chart_weights():
p = PORTFOLIOS["PORT06"] p = PORTFOLIOS["PORT06"]
ids = p.sleeve_ids ids = p.sleeve_ids
w = W.weight_vector("cap", ids, None, caps=p.caps) w = W.weight_vector("cap", ids, None, caps=p.caps)
fam = {i: W.family_of(i) for i in ids} fam = {i: W.family_of(i) for i in ids}
colors = {"FADE": "#1f6fd6", "HONEST": "#e08c1a", "PAIRS": "#9467bd", colors = {"FADE": "#1f6fd6", "HONEST": "#e08c1a", "PAIRS": "#9467bd",
"TSM": "#5ab4ac", "SHAPE": "#d64545"} "TSM": "#5ab4ac", "SHAPE": "#d64545", "XSEC": "#8c564b"}
order = sorted(ids, key=lambda i: (fam[i], i)) order = sorted(ids, key=lambda i: (fam[i], i))
fig, ax = plt.subplots(figsize=(8.6, 2.9)) fig, ax = plt.subplots(figsize=(8.6, 2.9))
ax.bar(order, [w[i] * 100 for i in order], color=[colors[fam[i]] for i in order]) ax.bar(order, [w[i] * 100 for i in order], color=[colors[fam[i]] for i in order])
@@ -547,6 +577,25 @@ def stats_multi():
yearly_table({"TSM01 (universo 8)": equity_yearly(tsm)}, note)) yearly_table({"TSM01 (universo 8)": equity_yearly(tsm)}, note))
def stats_xs01():
"""XS01 per-anno dall'engine canonico (UNGATED, come il backtest di portafoglio)."""
from scripts.strategies.XS01_cross_sectional import xsec_sim
r = xsec_sim()
s = pd.Series(r["eq_v"], index=pd.to_datetime(r["eq_ts"], utc=True))
years = {}
for y in sorted(r["yearly"]):
g = s[s.index.year == y]
dd = float(((g.cummax() - g) / g.cummax()).max() * 100) if len(g) else 0.0
years[int(y)] = {"n": r["yearly_n"].get(y, 0), "pnl": r["yearly"][y], "dd": dd}
pk = s.cummax()
note = ("PnL = Σ rendimenti netti per trade del book (%, gross 1, fee 0.20% RT/book = "
"turnover 2×0.10%); DD dall'equity compounding (pos 0.15, leva 3x convenzione "
"test). Engine canonico SENZA dispersion-gate (il gate agisce solo sul path "
"live, come trend/hurst sulle fade → il live farà meglio del backtest).")
return yearly_table({"XS01 (universo 8)": (years, float(((pk - s) / pk).max() * 100))},
note)
def stats_sh01(): def stats_sh01():
"""SH01 per-anno dal walk-forward EXPANDING (il regime validato e ora live).""" """SH01 per-anno dal walk-forward EXPANDING (il regime validato e ora live)."""
from scripts.analysis.shape_ml_research import ml_wf_entries from scripts.analysis.shape_ml_research import ml_wf_entries
@@ -580,8 +629,8 @@ box-shadow:0 1px 3px rgba(0,0,0,.05)}
.badge{display:inline-block;font-size:11px;font-weight:700;padding:2px 9px;border-radius:10px; .badge{display:inline-block;font-size:11px;font-weight:700;padding:2px 9px;border-radius:10px;
margin-right:6px;color:#fff} margin-right:6px;color:#fff}
.b-fade{background:#1f6fd6}.b-honest{background:#e08c1a}.b-pairs{background:#9467bd} .b-fade{background:#1f6fd6}.b-honest{background:#e08c1a}.b-pairs{background:#9467bd}
.b-tsm{background:#5ab4ac}.b-shape{background:#d64545}.b-real{background:#2e9e6b} .b-tsm{background:#5ab4ac}.b-shape{background:#d64545}.b-xsec{background:#8c564b}
.b-sim{background:#8a8f98} .b-real{background:#2e9e6b}.b-sim{background:#8a8f98}
img{max-width:100%;border:1px solid #eee;border-radius:6px;margin-top:10px} img{max-width:100%;border:1px solid #eee;border-radius:6px;margin-top:10px}
table{border-collapse:collapse;width:100%;font-size:13px;margin-top:8px} table{border-collapse:collapse;width:100%;font-size:13px;margin-top:8px}
td,th{border:1px solid #e3e5e8;padding:5px 9px;text-align:left} td,th{border:1px solid #e3e5e8;padding:5px 9px;text-align:left}
@@ -609,6 +658,7 @@ def main():
st_dip = stats_dip() st_dip = stats_dip()
t_pairs = stats_pairs() t_pairs = stats_pairs()
t_tr, t_rot, t_tsm = stats_multi() t_tr, t_rot, t_tsm = stats_multi()
t_xs = stats_xs01()
print(" SH01 walk-forward expanding (il piu' lento)...") print(" SH01 walk-forward expanding (il piu' lento)...")
st_sh = stats_sh01() st_sh = stats_sh01()
@@ -631,6 +681,7 @@ def main():
g_pr = chart_pr01() g_pr = chart_pr01()
g_tsm = chart_tsm01(panel) g_tsm = chart_tsm01(panel)
g_sh = chart_sh01() g_sh = chart_sh01()
g_xs = chart_xs01()
# metriche canoniche del default per l'intestazione (sempre aggiornate) # metriche canoniche del default per l'intestazione (sempre aggiornate)
pr = PORTFOLIOS["PORT06"].backtest() pr = PORTFOLIOS["PORT06"].backtest()
@@ -665,7 +716,7 @@ estremo in un'ora), fada il movimento. Exit in multipli di ATR. È la fade più
sono falsi negativi</b> — l'overshoot che buca lo stop e rientra è esattamente il movimento che sono falsi negativi</b> — l'overshoot che buca lo stop e rientra è esattamente il movimento che
la fade sta comprando. Con EXIT-16 lo SL intrabar è disattivato: si esce solo se il <b>close</b> la fade sta comprando. Con EXIT-16 lo SL intrabar è disattivato: si esce solo se il <b>close</b>
della barra completata sfonda il livello di 0.5·ATR. Il TP intrabar resta. Impatto sul della barra completata sfonda il livello di 0.5·ATR. Il TP intrabar resta. Impatto sul
portafoglio: OOS Sharpe 8.82→10.06. Esteso oggi anche a DIP01 (grid 36/36).</p>""", g_e16) portafoglio: OOS Sharpe 8.82→10.06. Esteso anche a DIP01 (2026-06-07, grid 36/36).</p>""", g_e16)
c_dip = card("DIP01 — Dip Buy (BTC)", B("honest", "HONEST") + real, """ c_dip = card("DIP01 — Dip Buy (BTC)", B("honest", "HONEST") + real, """
<p>Compra il <b>dip</b>: quando lo z-score del prezzo incrocia sotto 2.5 (sell-off rapido), <p>Compra il <b>dip</b>: quando lo z-score del prezzo incrocia sotto 2.5 (sell-off rapido),
@@ -713,24 +764,41 @@ l'edge): la coda si gestisce dimezzando il peso della famiglia (cap 5.88%).</p>
<p class='sub'>Esecuzione reale single-leg su Deribit testnet: niente TP/SL, chiusura a orizzonte <p class='sub'>Esecuzione reale single-leg su Deribit testnet: niente TP/SL, chiusura a orizzonte
H=12 (market reduce-only), disaster-bracket on-book come unica protezione di coda — è il H=12 (market reduce-only), disaster-bracket on-book come unica protezione di coda — è il
diversificatore più decorrelato del portafoglio.</p> diversificatore più decorrelato del portafoglio.</p>
<p class='sub'>Fix di oggi (punto-10): il training live usa la storia COMPLETA dal parquet <p class='sub'>Fix punto-10 (2026-06-07): il training live usa la storia COMPLETA dal parquet
locale (il regime corto a 365g non era robusto: trade-rate 22% vs 10% validato).</p>""", g_sh, yearly_table(st_sh)) locale (il regime corto a 365g non era robusto: trade-rate 22% vs 10% validato).</p>""", g_sh, yearly_table(st_sh))
c_xs = card("XS01 — Cross-Sectional Reversion (8 asset)", B("xsec", "XSEC") + sim, """
<p><b>Famiglia nuova (2026-06-09)</b>: ogni 12 ore classifica 8 crypto (BTC, ETH, LTC, ADA,
SOL, BNB, XRP, DOGE) per rendimento a 48 ore e va <b>long i perdenti relativi / short i
vincenti</b> (peso ∝ (ret media cross-section)), market-neutral gross 1. Cattura il
<i>fattore</i> reversione cross-sezionale — distinto dai pairs (pairwise) e dai fade
(single-asset): correlazione ~0 con entrambi. Gate PORT06: OOS Sharpe 9.66→10.07,
FULL DD 3.68→3.46. Plateau robusto (lb 12-72 × hold 6-24 tutte OOS+).</p>
<p class='sub'><b>Dispersion-gate (2026-06-10, v1.1.20)</b>: entra solo se la dispersione
cross-section del momentum ≥ 0.0313 (mediana TRAIN) — la reversione paga quando c'è
dispersione da far rientrare. Diagnostica monotona TRAIN e OOS, plateau p30-p70,
standalone Sharpe 2.50→3.46 (regge fee 2x), PORT06 OOS 10.07→<b>10.37</b> a DD pari.
Solo path live (backtest canonico non filtrato → il live farà meglio del backtest).</p>
<p class='sub'>8 gambe → niente esecuzione reale: gira PAPER come i book multi-asset
(il rumore di arrotondamento a €2k dominerebbe). Worker validato (replay == backtest esatto).</p>""",
g_xs, t_xs)
html = f"""<!doctype html><html lang="it"><head><meta charset="utf-8"> html = f"""<!doctype html><html lang="it"><head><meta charset="utf-8">
<title>PythagorasGoal — Strategie attive PORT06</title><style>{CSS}</style></head> <title>PythagorasGoal — Strategie attive PORT06</title><style>{CSS}</style></head>
<body><div class="wrap"> <body><div class="wrap">
<h1>PythagorasGoal — Strategie attive</h1> <h1>PythagorasGoal — Strategie attive</h1>
<p class="sub">Portafoglio live <b>PORT06</b> — definizione {n_def} sleeve; <b>pool live real-only 15 sleeve</b> <p class="sub">Portafoglio live <b>PORT06</b> — definizione {n_def} sleeve; <b>pool live real-only 15 sleeve</b>
(i 3 book multi-asset girano in statistica, fuori dal capitale-pool). Capitale pool €2.000, leva 2x · (i 4 book multi-asset TR01/ROT02/TSM01/XS01 girano in statistica, fuori dal capitale-pool).
Capitale pool €2.000, leva 2x, <b>real-truth ledger</b> ·
v{ver} · generato {now} · backtest canonico: {hdr}</p> v{ver} · generato {now} · backtest canonico: {hdr}</p>
<div class="card"> <div class="card">
<p>Tre famiglie principali quasi <b>scorrelate</b> fra loro (fade↔honest ~0.05, pairs ~0.02-0.09, <p>Famiglie quasi <b>scorrelate</b> fra loro (fade↔honest ~0.05, pairs ~0.02-0.09,
shape ~0.08): la diversificazione è la leva anti-drawdown. Pesi equal con tetti per famiglia, shape ~0.08, xsec ~0): la diversificazione è la leva anti-drawdown. Pesi equal con tetti
ribilancio giornaliero su capitale pool condiviso. Fee Deribit 0.10% round-trip incluse ovunque; per famiglia, ribilancio giornaliero su capitale pool condiviso. Fee Deribit 0.10% round-trip
ogni meccanismo live è passato da un gate out-of-sample a livello di portafoglio.</p> incluse ovunque; ogni meccanismo live è passato da un gate out-of-sample a livello di portafoglio.</p>
<img src="data:image/png;base64,{g_w}"></div> <img src="data:image/png;base64,{g_w}"></div>
<h2>FADE — mean-reversion intraday 1h <span class="sub">(6 sleeve × 6.47%)</span></h2> <h2>FADE — mean-reversion intraday 1h <span class="sub">(6 sleeve × 5.69%)</span></h2>
<div class="note"><b>Tesi della famiglia:</b> sui perpetui crypto l'edge è la <i>reversione</i>: <div class="note"><b>Tesi della famiglia:</b> sui perpetui crypto l'edge è la <i>reversione</i>:
i movimenti estremi rientrano (i breakout falliscono — l'intera famiglia squeeze-breakout è stata i movimenti estremi rientrano (i breakout falliscono — l'intera famiglia squeeze-breakout è stata
scartata come artefatto di look-ahead). Le fade vendono l'eccesso e comprano il panico, con tre scartata come artefatto di look-ahead). Le fade vendono l'eccesso e comprano il panico, con tre
@@ -741,14 +809,16 @@ non si fada un crollo/parabolica), <b>EXIT-16</b> (stop solo sul close confermat
{c_mr02} {c_mr02}
{c_mr07} {c_mr07}
{c_e16} {c_e16}
<h2>HONEST — long-only multi-regime <span class="sub">(3 sleeve × 6.47%)</span></h2> <h2>HONEST — long-only multi-regime <span class="sub">(3 sleeve × 5.69%)</span></h2>
{c_dip} {c_dip}
{c_tr} {c_tr}
{c_rot} {c_rot}
<h2>PAIRS — spread reversion market-neutral <span class="sub">(6 sleeve: 5 coppie 1h + ETH/BTC 15m a mezza size, famiglia ≤33%)</span></h2> <h2>PAIRS — spread reversion market-neutral <span class="sub">(6 sleeve × 5.26%: 5 coppie 1h + ETH/BTC 15m a mezza size, famiglia ≤33%)</span></h2>
{c_pr} {c_pr}
<h2>TSM — trend-following multi-orizzonte <span class="sub">(1 sleeve × 6.47%)</span></h2> <h2>TSM — trend-following multi-orizzonte <span class="sub">(1 sleeve × 5.69%)</span></h2>
{c_tsm} {c_tsm}
<h2>XSEC — reversione cross-sectional <span class="sub">(1 sleeve × 5.69%)</span></h2>
{c_xs}
<h2>SHAPE — ML morfologico <span class="sub">(2 sleeve × 2.94%, famiglia ≤5.88%)</span></h2> <h2>SHAPE — ML morfologico <span class="sub">(2 sleeve × 2.94%, famiglia ≤5.88%)</span></h2>
{c_sh} {c_sh}
@@ -757,7 +827,8 @@ non si fada un crollo/parabolica), <b>EXIT-16</b> (stop solo sul close confermat
<li><b>Fee sempre incluse</b>: 0.10% round-trip taker Deribit (misurate reali = assunte). Molte operazioni = morte per fee: ogni strategia regge lo stress a fee doppie.</li> <li><b>Fee sempre incluse</b>: 0.10% round-trip taker Deribit (misurate reali = assunte). Molte operazioni = morte per fee: ogni strategia regge lo stress a fee doppie.</li>
<li><b>Niente look-ahead</b>: direzione e prezzo decisi solo con dati fino al close corrente; barre in formazione escluse (lezione EXIT-16). La famiglia squeeze (accuratezze 76-82%) è stata scartata proprio per questo artefatto.</li> <li><b>Niente look-ahead</b>: direzione e prezzo decisi solo con dati fino al close corrente; barre in formazione escluse (lezione EXIT-16). La famiglia squeeze (accuratezze 76-82%) è stata scartata proprio per questo artefatto.</li>
<li><b>Gate out-of-sample</b>: nessun meccanismo va in produzione senza migliorare (o non degradare) il portafoglio FULL e OOS — robusto individualmente ≠ migliora PORT06.</li> <li><b>Gate out-of-sample</b>: nessun meccanismo va in produzione senza migliorare (o non degradare) il portafoglio FULL e OOS — robusto individualmente ≠ migliora PORT06.</li>
<li><b>Esecuzione reale shadow (~83% del portafoglio)</b>: 15 sleeve eseguono ordini reali su Deribit testnet accanto al sim — i 6 fade + DIP01 (single-leg, TP limit al livello, disaster-stop 30% on-book), i 6 pairs incl. <b>ETH/BTC 15m flat-skip</b> (2 gambe, leg-risk unwind) e i 2 SH01 (single-leg, exit a orizzonte, niente TP/SL). Restano simulati solo i book multi-asset TR01/ROT02/TSM01 (bloccati dal capitale: serve ~€20k per il rumore di arrotondamento). Fee reali verificate dai trade; divergenze sim/reale ≥100bps alertate su Telegram.</li> <li><b>Esecuzione reale shadow (15 sleeve su 19)</b>: i 6 fade + DIP01 (single-leg, TP limit al livello, disaster-stop 30% on-book), i 6 pairs incl. <b>ETH/BTC 15m flat-skip</b> (2 gambe, leg-risk unwind) e i 2 SH01 (single-leg, exit a orizzonte, niente TP/SL) eseguono ordini reali su Deribit testnet. Restano simulati solo i book multi-asset TR01/ROT02/TSM01/XS01 (bloccati dal capitale: serve ~€20k per il rumore di arrotondamento). Fee reali verificate dai trade; divergenze sim/reale ≥100bps alertate su Telegram.</li>
<li><b>Real-truth ledger (2026-06-10)</b>: il capitale dei worker eseguiti si aggiorna col PnL dei <b>fill reali</b> (fee reali incluse), non col sim — equity, pesi e notional derivano dai soldi veri sul conto; il sim resta diagnostica nel log (fallback dichiarato solo se il trade reale non è mai esistito). Le decisioni di entry/exit restano guidate dal feed.</li>
</ul></div> </ul></div>
<p class="sub">Generato da <code>scripts/analysis/make_strategy_doc.py</code> — grafici da episodi reali sui dati parquet locali.</p> <p class="sub">Generato da <code>scripts/analysis/make_strategy_doc.py</code> — grafici da episodi reali sui dati parquet locali.</p>
</div></body></html>""" </div></body></html>"""