diff --git a/docs/diary/2026-06-12-fade15m-gate.md b/docs/diary/2026-06-12-fade15m-gate.md index 9287de3..c6d7872 100644 --- a/docs/diary/2026-06-12-fade15m-gate.md +++ b/docs/diary/2026-06-12-fade15m-gate.md @@ -51,3 +51,28 @@ il suo OOS DD peggiora 1.48→2.09). In subordine BLEND (miglior FULL DD 2.31%). position_size ridotto come il blend pairs (il gate ADD qui è già a peso pieno e migliora comunque, ma il caveat slippage 15m suggerisce prudenza). 5. MR02_BTC 15m è il più fee-sensitive (fee2x OOS 0.60): monitorare le fee reali. + +## Addendum — DEPLOY: SWAP SECCO (stessa giornata, scelta utente) + +L'utente ha scelto **SWAP** (la variante a CAGR più alto), consapevole dei due +costi discussi: OOS DD 1.48→2.09% e perdita della maturità operativa 1h (la +meccanica live — EXIT-16 confirm, TP_PHANTOM, TP resting — gira 4x più veloce +su un feed testnet con wick anomali; il gate misura l'edge, non la robustezza +operativa). Proposta alternativa staged (ADD temporaneo 1-2 settimane, poi +spegnere il 1h) declinata: "swap secco". + +Implementazione (deliberatamente minima, sid INVARIATI → pesi/alloc/epoche +intatti): +- `_defs.py`: FADE specs → `tf="15m"` (DIP01 resta 1h: non era nel gate). +- `combine_portfolio.py`: `FADE_TF="15m"` nel builder canonico → le due facce + (backtest/live) restano sulla STESSA definizione; il lock di parità + (`test_backtest_parity`) confronta le facce fra loro e resta verde. +- Runner: NESSUNA modifica (il fetch sub-orario BTC/ETH 15m esisteva già per il + blend pairs; `_spec_assets_tf`/`_series_for` sono generici). +- Worker: nuove dir `*__15m` (stato 1h preservato in `*__1h`, worker flat al + momento dello switch). Esecuzione reale invariata (match per nome MR01/02/07). +- max_bars=24 barre ora = 6h; EXIT-16 confirm sulla barra 15m completata. + +Monitor post-deploy: stop-rate e divergenza sim/reale dei fade 15m +nell'hourly report; fee reali su MR02_BTC; STALE_FEED (le barre flat 15m +sono più frequenti che a 1h). diff --git a/scripts/analysis/combine_portfolio.py b/scripts/analysis/combine_portfolio.py index c730ea0..9152d05 100644 --- a/scripts/analysis/combine_portfolio.py +++ b/scripts/analysis/combine_portfolio.py @@ -40,9 +40,17 @@ ANN = 365.0 # giorni/anno per annualizzare # ---------------- equity giornaliere ---------------- -def fade_daily_equity(asset: str, fn, params) -> pd.Series: - """Equity giornaliera di uno sleeve fade: trade 1h (filtro trend 3.0) -> equity -> daily.""" - df = load_data(asset, "1h") +# SWAP fade 1h -> 15m (2026-06-12, scelta utente). Gate fade15m_port06_gate.py: parametri +# 1h NON ri-tunati trasferiti a 15m, corr 15m-1h media 0.26, SWAP promosso (FULL CAGR +# 74->101% DD 3.46->2.47%, OOS Sh 10.07->10.86; OOS DD 1.48->2.09 accettato), edge ETH +# regge il flat-entry-skip. Il canonico segue il deployato per tenere la parita' delle +# due facce. Diario docs/diary/2026-06-12-fade15m-gate.md. +FADE_TF = "15m" + + +def fade_daily_equity(asset: str, fn, params, tf: str = FADE_TF) -> pd.Series: + """Equity giornaliera di uno sleeve fade: trade (filtro trend 3.0) -> equity -> daily.""" + df = load_data(asset, tf) ts = pd.to_datetime(df["timestamp"], unit="ms", utc=True) trades = build_trades(fn(df, **params), df, trend_max=3.0) n = len(df); eq = np.full(n, INIT, dtype=float); cap = INIT @@ -55,7 +63,7 @@ def fade_daily_equity(asset: str, fn, params) -> pd.Series: def build_all_sleeves() -> dict[str, pd.Series]: sleeves: dict[str, pd.Series] = {} - # --- FADE: 8 sleeve --- + # --- FADE: 6 sleeve (15m dal 2026-06-12, vedi FADE_TF) --- for asset in ["BTC", "ETH"]: for nm, (fn, params) in strats_for(asset).items(): sleeves[f"{nm}_{asset}"] = fade_daily_equity(asset, fn, params) diff --git a/scripts/portfolios/_defs.py b/scripts/portfolios/_defs.py index 24af874..6606a3c 100644 --- a/scripts/portfolios/_defs.py +++ b/scripts/portfolios/_defs.py @@ -61,8 +61,18 @@ def _fade_params(c: str, a: str) -> dict: return p -FADE = [SleeveSpec(kind="single", name=c, sid=f"{c}_{a}", asset=a, cluster=f"{a}-rev", - params=_fade_params(c, a)) +# SWAP timeframe 1h -> 15m (2026-06-12, scelta utente "swap secco"). Gate +# fade15m_port06_gate.py: parametri 1h trasferiti a 15m NON ri-tunati (pre-registrati, +# anti-overfit), corr daily 15m-1h media 0.26 (NON e' lo stesso edge piu' veloce), +# SWAP promosso — FULL CAGR 74->101% DD 3.46->2.47%, OOS Sh 10.07->10.86 (OOS DD +# 1.48->2.09 accettato); l'edge ETH sopravvive al flat-entry-skip (non e' stale-print +# come pairs-alt). Stessi sid -> pesi/alloc invariati; il worker cambia cadenza +# (max_bars=24 barre = 6h; EXIT-16 confirm sulla barra 15m completata). Il backtest +# canonico segue (combine_portfolio.FADE_TF). MR02_BTC e' il piu' fee-sensitive +# (fee2x OOS Sh 0.60): monitorare le fee reali nel report orario. +# Diario docs/diary/2026-06-12-fade15m-gate.md. +FADE = [SleeveSpec(kind="single", name=c, sid=f"{c}_{a}", asset=a, tf="15m", + cluster=f"{a}-rev", params=_fade_params(c, a)) for a in ("BTC", "ETH") for c in ("MR01", "MR02", "MR07")] HONEST = [ # DIP01: single-asset 1h -> StrategyWorker (Strategy DIP01_dip_buy). TR01/ROT02: multi-asset. diff --git a/tests/portfolio/test_backtest_parity_cap.py b/tests/portfolio/test_backtest_parity_cap.py index d66f311..d280d37 100644 --- a/tests/portfolio/test_backtest_parity_cap.py +++ b/tests/portfolio/test_backtest_parity_cap.py @@ -12,6 +12,9 @@ def test_port06_cap_backtest_numbers_locked(): # flat-skip, mezza size) -> FULL 6.47->7.20, OOS 8.82->9.66, DD 4.1%->3.7%. # Aggiornato 2026-06-09 (2): + XS01 (reversione cross-sectional 8 asset, PAPER) -> # FULL 7.20->7.34, OOS 9.66->10.07, FULL DD 3.68->3.46 (OOS DD +0.17pp). - assert r.full["sharpe"] == pytest.approx(7.34, abs=0.15) - assert r.oos["sharpe"] == pytest.approx(10.07, abs=0.25) - assert r.full["dd"] == pytest.approx(3.46, abs=0.5) + # Aggiornato 2026-06-12: SWAP fade 1h->15m (combine_portfolio.FADE_TF, scelta utente, + # gate fade15m_port06_gate.py) -> FULL 7.34->8.13 DD 3.46->2.47, OOS 10.07->10.86. + # Nuovo baseline atteso, non una regressione. + assert r.full["sharpe"] == pytest.approx(8.13, abs=0.15) + assert r.oos["sharpe"] == pytest.approx(10.86, abs=0.25) + assert r.full["dd"] == pytest.approx(2.47, abs=0.5)