docs: aggiorna CLAUDE.md + strategie_attive.html col BLEND ETH/BTC 15m
- CLAUDE.md: default PORT06 (FULL 7.20/OOS 9.66, 18 sleeve), paragrafo BLEND 15m flat-skip (origine gioco Blind Traders, gate, validazione, caveat slippage), copertura reale ~83% (6 pairs), scripts/games/ + pairs15m_* nella struttura. - make_strategy_doc.py: header dinamico dal backtest, colonna ETH/BTC·15m nella tabella pairs, card PR01 col blend, conteggi sleeve aggiornati -> rigenerato HTML. - pairs_sim_flat: ritorna yearly_n (parita' con pairs_sim, usato dal doc). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -58,7 +58,10 @@ scripts/analysis/ → ricerca/validazione OOS fee-aware (strategy_research,
|
||||
regime_fetcher.py + regime_lab.py (DVOL/funding/feature regime per la ricerca);
|
||||
exit_lab.py + exit_policies/ (harness ricerca exit: cache segnali, train/OOS);
|
||||
options_fetcher.py + options_chain.py (storico opzioni REALE da cerbero-bite);
|
||||
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)
|
||||
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
|
||||
scripts/bump_version.py, scripts/deploy.sh → versionamento e deploy (bump+commit+rebuild)
|
||||
VERSION → versione semver (cotta nell'immagine, +1 ad ogni deploy)
|
||||
strategies.yml → config multi-strategy paper trader
|
||||
@@ -384,7 +387,8 @@ queste fade, ma va confermato col paper trader live prima di rischiare capitale
|
||||
|
||||
- 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).
|
||||
- **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.
|
||||
- **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.**
|
||||
- **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`.
|
||||
- **Data layer Cerbero v2:** `get_historical_v2` unificato + `get_instruments` (naming robusto) + `get_ticker_batch`. Trading su Deribit.
|
||||
- **SCOPE LIVE (fase 2 completata):** il runner esegue TUTTI gli sleeve di PORT06. Worker: single `StrategyWorker` (fade MR01/02/07, DIP01, **e SH01**), `PairsWorker` (PR01 2 gambe), e i multi-asset dedicati `BasketTrendWorker` (TR01 4h), `RotationWorker` (ROT02 1d), `TsmomWorker` (TSM01 1d). Il runner fetcha 1h da Cerbero v2 e **resampla a 4h/1d** (lookback dimensionato sui daily: TSM01 usa 252g). Validazione: runner pool/ribilancio/ledger == backtest (`validate_portfolio_runner.py`, identico); worker multi-asset == reference (`validate_honest_workers.py`: TSM01 esatto, ROT02 +1303% canonico, TR01 stesso ordine — differenza di convenzione capitale-unico vs media-equity).
|
||||
@@ -407,9 +411,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
|
||||
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
|
||||
3.96→5.35%). Copertura reale ora ~81% (fade+DIP+pairs+SH01); restano simulati TR01/ROT02/TSM01
|
||||
(book multi-asset, bloccati dal capitale: rumore arrotondamento 20-30% a €2k, serve ~€20k).
|
||||
Diari `docs/diary/2026-06-08-pairs-executor.md`.
|
||||
3.96→5.35%). Copertura reale ora ~83% (fade+DIP+**6 pairs incl. ETH/BTC 15m**+SH01); restano
|
||||
simulati TR01/ROT02/TSM01 (book multi-asset, bloccati dal capitale: rumore 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.
|
||||
- **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,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -495,9 +495,14 @@ def stats_pairs():
|
||||
from scripts.analysis.pairs_research import pairs_sim
|
||||
from scripts.strategies.PR01_pairs_reversion import PAIRS as PAIRS_CFG
|
||||
cols, data = [], {}
|
||||
for a, b, p in PAIRS_CFG:
|
||||
r = pairs_sim(a, b, **p)
|
||||
tag = f"{a}/{b}"
|
||||
from scripts.analysis.pairs_research import pairs_sim_flat
|
||||
# le 5 coppie 1h universali + il BLEND ETH/BTC 15m flat-skip (mezza size = sleeve live)
|
||||
runs = [(f"{a}/{b}", lambda a=a, b=b, p=p: pairs_sim(a, b, **p)) for a, b, p in PAIRS_CFG]
|
||||
runs.append(("ETH/BTC·15m", lambda: pairs_sim_flat(
|
||||
"ETH", "BTC", tf="15m", n=66, z_in=1.674, z_exit=1.0, max_bars=35,
|
||||
flat_skip=True, pos=0.075)))
|
||||
for tag, fn in runs:
|
||||
r = fn()
|
||||
cols.append(tag)
|
||||
s = pd.Series(r["eq_v"], index=pd.to_datetime(r["eq_ts"], utc=True))
|
||||
ydd = {int(y): float(((g.cummax() - g) / g.cummax()).max() * 100)
|
||||
@@ -627,6 +632,12 @@ def main():
|
||||
g_tsm = chart_tsm01(panel)
|
||||
g_sh = chart_sh01()
|
||||
|
||||
# metriche canoniche del default per l'intestazione (sempre aggiornate)
|
||||
pr = PORTFOLIOS["PORT06"].backtest()
|
||||
n_def = len(PORTFOLIOS["PORT06"].sleeve_ids)
|
||||
hdr = (f"FULL Sharpe {pr.full['sharpe']:.2f} / DD {pr.full['dd']:.2f}% — "
|
||||
f"OOS Sharpe {pr.oos['sharpe']:.2f} / DD {pr.oos['dd']:.2f}%")
|
||||
|
||||
B = lambda f, t: f'<span class="badge b-{f}">{t}</span>'
|
||||
real = B("real", "ESECUZIONE REALE (testnet)")
|
||||
sim = B("sim", "SIMULATO")
|
||||
@@ -671,13 +682,19 @@ le fade per costruzione non prendono. Valuta solo barre 4h COMPLETE.</p>""", g_t
|
||||
(solo se positive), gross 0.45. Gate di regime: tutto cash se BTC<SMA100. Diversificare su 3
|
||||
asset invece di 2 ha quasi dimezzato il DD (40%→26%) alzando il ritorno.</p>""", g_rot, t_rot)
|
||||
|
||||
c_pr = card("PR01 — Pairs Reversion (ETH/BTC, LTC/ETH, ADA/ETH, BTC/LTC, ETH/SOL)",
|
||||
c_pr = card("PR01 — Pairs Reversion (ETH/BTC, LTC/ETH, ADA/ETH, BTC/LTC, ETH/SOL + ETH/BTC 15m)",
|
||||
B("pairs", "PAIRS") + real, """
|
||||
<p><b>Market-neutral</b>: quando il rapporto fra due asset si allontana troppo dalla sua media
|
||||
(|z| del log-ratio ≥ 2), compra la gamba debole e shorta la forte; chiude quando il rapporto
|
||||
rientra (|z| ≤ 0.75) o dopo 72 barre. Config <b>universale</b> per tutte le coppie (niente tuning
|
||||
per-coppia = anti-overfit). Correlazione col mercato ~0.05: rende anche quando il mercato è fermo.
|
||||
Fee su 2 gambe. Senza stop per design → position size ridotto a 0.20 (esposizione ≈ validato).</p>
|
||||
<p class='sub'><b>BLEND timeframe (nuovo, 2026-06-09)</b>: ETH/BTC gira anche a <b>15m</b> accanto al 1h
|
||||
(config n=66, |z|≥1.67, exit |z|≤1.0 o 35 barre). Origine: gioco "Blind Traders" (100 agenti ciechi
|
||||
su dati anonimi); testato col gate PORT06 — <b>decorrelato dal 1h (corr 0.37)</b>, robusto (16/16),
|
||||
e l'edge regge anche filtrando le candele flat ETH 15m (<b>flat-skip</b>: niente ingresso/uscita su
|
||||
barre stale O=H=L=C). Worker validato (replay == backtest). A <b>mezza size</b> (blend-tilt prudente
|
||||
sul caveat slippage): porta il PORT06 a FULL Sharpe ~7.2 / OOS ~9.7.</p>
|
||||
<p class='sub'>Esecuzione reale a 2 gambe su Deribit testnet (<code>PairsExecutionClient</code>):
|
||||
open/close long A / short B, leg-risk unwind, mai <code>close_position</code>.</p>""", g_pr, t_pairs)
|
||||
|
||||
@@ -703,9 +720,9 @@ locale (il regime corto a 365g non era robusto: trade-rate 22% vs 10% validato).
|
||||
<title>PythagorasGoal — Strategie attive PORT06</title><style>{CSS}</style></head>
|
||||
<body><div class="wrap">
|
||||
<h1>PythagorasGoal — Strategie attive</h1>
|
||||
<p class="sub">Portafoglio live <b>PORT06</b> — definizione 17 sleeve; <b>pool live real-only 14 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 ·
|
||||
v{ver} · generato {now} · backtest canonico: FULL Sharpe 6.61 / DD 3.58% — OOS Sharpe 8.77 / DD 1.34%</p>
|
||||
v{ver} · generato {now} · backtest canonico: {hdr}</p>
|
||||
<div class="card">
|
||||
<p>Tre famiglie principali 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,
|
||||
@@ -728,7 +745,7 @@ non si fada un crollo/parabolica), <b>EXIT-16</b> (stop solo sul close confermat
|
||||
{c_dip}
|
||||
{c_tr}
|
||||
{c_rot}
|
||||
<h2>PAIRS — spread reversion market-neutral <span class="sub">(5 coppie × 5.88%, famiglia ≤33%)</span></h2>
|
||||
<h2>PAIRS — spread reversion market-neutral <span class="sub">(6 sleeve: 5 coppie 1h + ETH/BTC 15m a mezza size, famiglia ≤33%)</span></h2>
|
||||
{c_pr}
|
||||
<h2>TSM — trend-following multi-orizzonte <span class="sub">(1 sleeve × 6.47%)</span></h2>
|
||||
{c_tsm}
|
||||
@@ -740,7 +757,7 @@ 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>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>Esecuzione reale shadow (~81% del portafoglio)</b>: 14 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 5 pairs (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 (~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>
|
||||
</ul></div>
|
||||
<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>"""
|
||||
|
||||
@@ -141,7 +141,7 @@ def pairs_sim_flat(a, b, tf="1h", n=50, z_in=2.0, z_exit=0.5, max_bars=72,
|
||||
split = int(N * split_frac)
|
||||
fee = 2 * fee_rt * lev
|
||||
cap = peak = 1000.0; dd = 0.0; last = -1
|
||||
trades = wins = 0; rets = []; yearly = {}
|
||||
trades = wins = 0; rets = []; yearly = {}; yearly_n = {}
|
||||
eq_ts, eq_v = [], []
|
||||
n_skip_entry = 0
|
||||
kmax = max_bars + (scan_buffer if flat_skip else 0)
|
||||
@@ -176,6 +176,7 @@ def pairs_sim_flat(a, b, tf="1h", n=50, z_in=2.0, z_exit=0.5, max_bars=72,
|
||||
trades += 1; wins += ret > 0; rets.append(ret * pos); last = j
|
||||
eq_ts.append(ts.iloc[j]); eq_v.append(cap)
|
||||
yearly[ts.iloc[i].year] = yearly.get(ts.iloc[i].year, 0.0) + ret * 100
|
||||
yearly_n[ts.iloc[i].year] = yearly_n.get(ts.iloc[i].year, 0) + 1
|
||||
yrs_span = (ts.iloc[-1] - ts.iloc[max(split, 0)]).days / 365.25 or 1
|
||||
sharpe = 0.0
|
||||
if len(rets) > 1 and np.std(rets) > 0:
|
||||
@@ -183,7 +184,7 @@ def pairs_sim_flat(a, b, tf="1h", n=50, z_in=2.0, z_exit=0.5, max_bars=72,
|
||||
ret_tot = (cap / 1000 - 1) * 100
|
||||
cagr = ((cap / 1000) ** (1 / yrs_span) - 1) * 100 if cap > 0 else -100
|
||||
return dict(trades=trades, win=wins / trades * 100 if trades else 0, ret=ret_tot,
|
||||
cagr=cagr, dd=dd * 100, sharpe=sharpe, yearly=yearly,
|
||||
cagr=cagr, dd=dd * 100, sharpe=sharpe, yearly=yearly, yearly_n=yearly_n,
|
||||
eq_ts=eq_ts, eq_v=eq_v, n_skip_entry=n_skip_entry)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user