2 Commits

Author SHA1 Message Date
Adriano Dal Pastro 378ec7fb43 release: v1.1.30 2026-06-12 20:47:45 +00:00
Adriano Dal Pastro f78380596a feat(live): SWAP fade 1h -> 15m su PORT06 (scelta utente, gate fade15m_port06_gate)
FADE specs tf=15m (sid invariati -> pesi/alloc intatti; DIP01 resta 1h);
builder canonico allineato (combine_portfolio.FADE_TF) -> parita' delle due
facce; regression-lock aggiornato al nuovo baseline (FULL Sh 7.34->8.13
DD 3.46->2.47, OOS Sh 10.07->10.86 DD 1.48->2.09). Runner invariato (fetch
15m gia' esistente dal blend pairs). Suite 126 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 20:47:44 +00:00
5 changed files with 56 additions and 10 deletions
+1 -1
View File
@@ -1 +1 @@
1.1.29
1.1.30
+25
View File
@@ -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).
+12 -4
View File
@@ -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)
+12 -2
View File
@@ -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.
+6 -3
View File
@@ -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)