Files
PythagorasGoal/Old/scripts/analysis/shape_ml_validate.py
T
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

179 lines
7.6 KiB
Python

"""Validazione DURA del solo edge sopravvissuto alla ricerca shape: ML walk-forward
(LogisticRegression) sulle feature di FORMA. Tutto il resto della famiglia shape e' rumore.
Candidato: BTC logit W24H12 th0.58 (FULL +219% / OOS +42% / Sharpe 2.72 / 8-9 anni+,
regge fee 0.20% RT). Prima di promuoverlo a strategia serve (metodologia obbligatoria):
1. ROBUSTEZZA MULTI-ASSET: stessa config su BTC/ETH/LTC/SOL/ADA/XRP 1h.
2. WALK-FORWARD ROLLING (train fisso 2y) oltre all'expanding -> niente "memoria infinita".
3. STRESS leva 2x + slippage doppio (fee 0.20% RT) -> regge in condizioni realistiche?
4. ROBUSTEZZA SU GRIGLIA (th, W, H) -> plateau, non picco.
5. CORRELAZIONE col MASTER + integrazione -> e' un diversificatore (free-lunch)?
Tutto netto-fee, OOS = ultimo 30%. Conta il PnL netto, non l'accuracy (lezione squeeze).
Run: uv run python scripts/analysis/shape_ml_validate.py
"""
from __future__ import annotations
import sys
import time
import warnings
from pathlib import Path
import numpy as np
import pandas as pd
PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))
warnings.filterwarnings("ignore")
from scripts.analysis.explore_lab import get_df, evaluate, robust, FEE_RT, LEV, POS, OOS_FRAC
from scripts.analysis.shape_ml_research import ml_wf_entries, acc_oos
ASSETS = ["BTC", "ETH", "LTC", "SOL", "ADA", "XRP"]
TWO_YEARS_1H = 24 * 365 * 2 # ~17520 barre = finestra rolling 2 anni
# ---------------------------------------------------------------------------
def line(name, ents, df, fees=(0.0, 0.001, 0.002)):
"""Riga evaluate + accuracy OOS, ritorna (res, robusto?)."""
res = evaluate(name, ents, df)
ac = acc_oos(ents, df)
rb = (res["full"]["ret"] > 0 and res["oos"]["ret"] > 0
and res["sweep"][0.002] > 0 and res["sweep_oos"][0.002] > 0)
print(f" ^ accOOS={ac:4.1f}% {'[ROBUST fee0.2%]' if rb else ''}")
return res, rb
# ---------------------------------------------------------------------------
def sec_multi_asset(W=24, H=12, th=0.58):
print("\n[1] MULTI-ASSET — logit W%dH%d th%.2f, walk-forward EXPANDING (1h):" % (W, H, th))
ok = []
dfs = {}
for a in ASSETS:
df = get_df(a, "1h"); dfs[a] = df
ents = ml_wf_entries(df, W=W, H=H, model="logit", thresh=th)
_, rb = line(f"{a} exp", ents, df)
if rb:
ok.append(a)
print(f" -> EXPANDING robusti (fee0.2%): {ok if ok else 'NESSUNO'}")
return dfs, ok
def sec_rolling(dfs, W=24, H=12, th=0.58, tw=TWO_YEARS_1H):
print("\n[2] WALK-FORWARD ROLLING — train fisso ~2 anni (%d barre), stessa config:" % tw)
ok = []
for a in ASSETS:
ents = ml_wf_entries(dfs[a], W=W, H=H, model="logit", thresh=th, train_window=tw)
_, rb = line(f"{a} roll2y", ents, dfs[a])
if rb:
ok.append(a)
print(f" -> ROLLING robusti (fee0.2%): {ok if ok else 'NESSUNO'}")
return ok
def sec_stress(dfs, W=24, H=12, th=0.58):
print("\n[3] STRESS — leva 2x + slippage doppio (fee 0.20% RT) su BTC/ETH:")
print(" (la config nominale e' leva 3x fee 0.10%; qui peggioro entrambe)")
from scripts.analysis.explore_lab import simulate
for a in ["BTC", "ETH"]:
ents = ml_wf_entries(dfs[a], W=W, H=H, model="logit", thresh=th)
df = dfs[a]
split = int(len(df) * (1 - OOS_FRAC))
base = simulate(ents, df, fee_rt=0.001, lev=3.0)
stress_f = simulate(ents, df, fee_rt=0.002, lev=2.0)
stress_o = simulate(ents, df, fee_rt=0.002, lev=2.0, split=split)
print(f" {a}: base(3x,0.1%) FULL={base['ret']:+.0f}% Shrp={base['sharpe']:.2f} | "
f"STRESS(2x,0.2%) FULL={stress_f['ret']:+.0f}% OOS={stress_o['ret']:+.0f}% "
f"DD={stress_f['dd']:.0f}% Shrp={stress_f['sharpe']:.2f} "
f"{'OK' if stress_f['ret'] > 0 and stress_o['ret'] > 0 else 'KO'}")
def sec_grid(dfs, asset="BTC"):
print(f"\n[4] ROBUSTEZZA GRIGLIA su {asset} (plateau, non picco):")
rob = tot = 0
for W in (16, 24, 32):
for H in (8, 12, 16):
for th in (0.56, 0.58, 0.60):
ents = ml_wf_entries(dfs[asset], W=W, H=H, model="logit", thresh=th)
_, rb = line(f"{asset} W{W}H{H}th{th}", ents, dfs[asset])
tot += 1; rob += rb
print(f" -> {asset}: {rob}/{tot} celle robuste a fee 0.2% (plateau se alta frazione)")
# ---------------------------------------------------------------------------
def shape_daily_equity(asset, IDX, W=24, H=12, th=0.58):
"""Equity giornaliera dello sleeve shape-ML (time-exit a H, non-overlap, pos 0.15,
leva 3x, fee 0.10% RT), normalizzata sull'indice comune dei portafogli."""
from src.data.downloader import load_data
df = get_df(asset, "1h")
c = df["close"].values
ts = pd.to_datetime(df["timestamp"], unit="ms", utc=True)
ents = ml_wf_entries(df, W=W, H=H, model="logit", thresh=th)
n = len(c); eq = np.full(n, 1000.0); cap = 1000.0; last_exit = -1
fee = FEE_RT * LEV
for e in sorted(ents, key=lambda x: x["i"]):
i, d, mb = e["i"], e["d"], e["max_bars"]
if i <= last_exit or i + mb >= n:
continue
j = i + mb
ret = (c[j] - c[i]) / c[i] * d * LEV - fee
cap = max(cap + cap * POS * ret, 10.0)
eq[j:] = cap; last_exit = j
s = pd.Series(eq, index=ts).resample("1D").last().reindex(IDX).ffill().bfill()
return s / s.iloc[0]
def sec_master_integration():
print("\n[5] CORRELAZIONE + INTEGRAZIONE COL MASTER:")
from scripts.analysis.combine_portfolio import (
build_all_sleeves, port_returns, metrics, IDX, SPLIT,
)
sleeves = build_all_sleeves()
# sleeve shape: BTC + ETH (i due con piu' storia/edge)
shape = {}
for a in ("BTC", "ETH"):
shape[f"SH_{a}"] = shape_daily_equity(a, IDX)
dr_master = port_returns(sleeves) # MASTER equal-weight attuale
dr_shape = port_returns(shape)
corr = float(dr_master.corr(dr_shape))
print(f" correlazione daily MASTER vs sleeve-shape: {corr:+.3f}")
# correlazione media shape vs ogni sleeve esistente
cs = {k: float(port_returns({k: v}).corr(dr_shape)) for k, v in sleeves.items()}
print(" corr shape vs singole sleeve: " + ", ".join(f"{k}={v:+.2f}" for k, v in cs.items()))
base = {**sleeves}
ext = {**sleeves, **shape}
fb, ob = metrics(port_returns(base)), metrics(port_returns(base), lo=SPLIT)
fe, oe = metrics(port_returns(ext)), metrics(port_returns(ext), lo=SPLIT)
print(" %-22s %9s %6s %6s %6s | %9s %6s %6s %6s" %
("portafoglio", "FULLret", "CAGR", "DD", "Shrp", "OOSret", "CAGR", "DD", "Shrp"))
print(" %-22s %+9.0f %6.0f %6.1f %6.2f | %+9.0f %6.0f %6.1f %6.2f" %
("MASTER (9 sleeve)", fb["ret"], fb["cagr"], fb["dd"], fb["sharpe"],
ob["ret"], ob["cagr"], ob["dd"], ob["sharpe"]))
print(" %-22s %+9.0f %6.0f %6.1f %6.2f | %+9.0f %6.0f %6.1f %6.2f" %
("MASTER + shape", fe["ret"], fe["cagr"], fe["dd"], fe["sharpe"],
oe["ret"], oe["cagr"], oe["dd"], oe["sharpe"]))
better = oe["sharpe"] > ob["sharpe"] and oe["dd"] <= ob["dd"] + 1
print(f" -> aggiungere shape MIGLIORA il MASTER OOS (Sharpe up, DD ~stabile)? "
f"{'SI' if better else 'NO'}")
def run():
t0 = time.time()
print("=" * 100)
print(" VALIDAZIONE DURA — shape-ML (LogisticRegression walk-forward sulle feature di forma)")
print("=" * 100)
dfs, _ = sec_multi_asset()
sec_rolling(dfs)
sec_stress(dfs)
sec_grid(dfs, "BTC")
sec_master_integration()
print(f"\n tempo totale: {time.time() - t0:.0f}s")
print("=" * 100)
if __name__ == "__main__":
run()