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>
This commit is contained in:
Adriano Dal Pastro
2026-06-19 15:16:03 +00:00
parent 8401a280b9
commit 14522262e6
383 changed files with 1971 additions and 779 deletions
@@ -0,0 +1,169 @@
"""GATE PORT06 — ETH/BTC pairs a 15m (origine: gioco "Blind Traders", vincitore #43).
Domanda onesta sollevata dal gioco: la coppia ETH/BTC (gia' deployata in PR01 a 1h,
config UNIV n=50 z_in=2.0 z_exit=0.75 max_bars=72) MIGLIORA se girata a 15m con la
config trovata dal gioco (n=66 z_in=1.67 z_exit=1.0 max_bars=35), oppure e' solo una
variante piu' veloce, correlata, dello STESSO spread?
Metodo (engine di PRODUZIONE pairs_sim, NON il motore-giocattolo del gioco):
[1] PARITA': pairs_sim ETH/BTC 1h UNIV (pos0.15 lev3) == sleeve canonico PR_ETHBTC.
[2] CORRELAZIONE 1h vs 15m (rendimenti giornalieri): se ~1 e' ridondante.
[3] STANDALONE 1h vs 15m (+ griglia robustezza n x z_in su 15m, + stress fee 2x).
[4] GATE PORT06: baseline(1h) vs SWAP(15m) vs BLEND(0.5*1h+0.5*15m) per la sleeve
ETH/BTC; promosso se vs baseline l'OOS Sharpe non peggiora E il DD scende
(PORT06 e famiglia), come gli altri gate del progetto.
uv run python scripts/analysis/pairs15m_port06_gate.py
"""
from __future__ import annotations
import sys
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))
from scripts.analysis.combine_portfolio import port_returns, metrics, SPLIT, OOS_DATE, IDX
from scripts.analysis.pairs_research import pairs_sim, OOS_FRAC
from scripts.analysis.report_families import daily_from
from scripts.portfolios._defs import PORTFOLIOS
from src.portfolio import weighting as W
POS, LEV = 0.15, 3.0 # config CANONICA (== build_everything)
UNIV_1H = dict(tf="1h", n=50, z_in=2.0, z_exit=0.75, max_bars=72)
GAME_15M = dict(tf="15m", n=66, z_in=1.674, z_exit=1.0, max_bars=35) # vincitore gioco
def eth_btc_daily(cfg):
r = pairs_sim("ETH", "BTC", **{**cfg, "pos": POS, "lev": LEV})
return daily_from(r["eq_ts"], r["eq_v"]), r
def std_metrics(cfg, fee_rt=0.001):
f = pairs_sim("ETH", "BTC", **{**cfg, "pos": POS, "lev": LEV, "fee_rt": fee_rt})
o = pairs_sim("ETH", "BTC", **{**cfg, "pos": POS, "lev": LEV, "fee_rt": fee_rt,
"split_frac": 1 - OOS_FRAC})
yrs = f["yearly"]; pos_y = sum(1 for v in yrs.values() if v > 0)
return f, o, pos_y, len(yrs)
def port_metrics(members, p):
ids = p.sleeve_ids
dr = pd.DataFrame({i: members[i].pct_change().fillna(0.0) for i in ids})
w = W.weight_vector(p.weighting, ids, dr, weights=p.weights,
caps=p.caps, clusters=p.clusters, lookback=p.vol_lookback)
drp = port_returns({i: members[i] for i in ids}, w)
return metrics(drp), metrics(drp, lo=SPLIT)
def fam_metrics(eqs):
dr = port_returns(eqs)
return metrics(dr), metrics(dr, lo=SPLIT)
def blend(e1, e2, w1=0.5):
"""Sleeve combinata: media pesata dei rendimenti giornalieri (ribilancio 1D)."""
r1 = e1.reindex(IDX).ffill().bfill().pct_change().fillna(0.0)
r2 = e2.reindex(IDX).ffill().bfill().pct_change().fillna(0.0)
rb = w1 * r1 + (1 - w1) * r2
eq = (1 + rb).cumprod()
return eq / eq.iloc[0]
def main():
p = PORTFOLIOS["PORT06"]
pair_ids = [s.sid for s in p.sleeves if s.sid.startswith("PR_")]
print("=" * 100)
print(" GATE PORT06 — ETH/BTC pairs 15m (vincitore gioco) vs 1h deployato")
print(f" pos={POS} lev={LEV} (canonico) | OOS da {OOS_DATE} | coppie PORT06: {pair_ids}")
print("=" * 100)
from src.portfolio.sleeves import all_sleeve_equities
eq_base = dict(all_sleeve_equities())
# [1] PARITA'
print("\n[1] PARITA' pairs_sim ETH/BTC 1h UNIV (pos0.15 lev3) == sleeve canonico PR_ETHBTC:")
e1h, r1h = eth_btc_daily(UNIV_1H)
base = eq_base["PR_ETHBTC"]
corr = base.pct_change().fillna(0).corr(e1h.pct_change().fillna(0))
rb = (base.iloc[-1] / base.iloc[0] - 1) * 100
rr = (e1h.iloc[-1] / e1h.iloc[0] - 1) * 100
par_ok = corr > 0.999 and abs(rr - rb) <= max(1.0, abs(rb) * 0.01)
print(f" corr={corr:.5f} ret canon {rb:+.0f}% vs replay {rr:+.0f}% "
f"{'OK' if par_ok else '<-- MISMATCH (STOP)'}")
if not par_ok:
return
# [2] CORRELAZIONE 1h vs 15m
e15, r15 = eth_btc_daily(GAME_15M)
c = e1h.pct_change().fillna(0).corr(e15.pct_change().fillna(0))
print(f"\n[2] CORRELAZIONE rendimenti giornalieri ETH/BTC 1h vs 15m: {c:.3f}")
print(f" {'(quasi-duplicato se >0.8; diversificatore se <0.5)':<60s}")
# [3] STANDALONE 1h vs 15m
print("\n[3] STANDALONE ETH/BTC (netto fee 0.20% RT/coppia, leva 3x):")
print(f" {'cfg':<10s}{'trd':>6s}{'win%':>6s}{'FULL%':>9s}{'OOS%':>9s}{'CAGR%':>7s}"
f"{'DD%':>6s}{'oDD%':>7s}{'Shrp':>6s}{'anni+':>7s}{'fee2x FULL%':>12s}")
for tag, cfg in [("1h UNIV", UNIV_1H), ("15m gioco", GAME_15M)]:
f, o, py, ny = std_metrics(cfg)
f2, _, _, _ = std_metrics(cfg, fee_rt=0.002)
print(f" {tag:<10s}{f['trades']:>6d}{f['win']:>6.1f}{f['ret']:>+9.0f}{o['ret']:>+9.0f}"
f"{f['cagr']:>7.0f}{f['dd']:>6.0f}{o['dd']:>7.0f}{f['sharpe']:>6.2f}"
f"{f'{py}/{ny}':>7s}{f2['ret']:>+12.0f}")
# robustezza: plateau n x z_in su 15m (Sharpe>1?)
print("\n Robustezza 15m (Sharpe full, griglia n x z_in, z_exit=1.0 max_bars=35):")
ns = [40, 50, 66, 80]; zs = [1.5, 1.7, 2.0, 2.5]
cells = 0; tot = 0
hdr = " n\\z_in " + "".join(f"{z:>7.1f}" for z in zs)
print(hdr)
for n in ns:
row = f" {n:>6d} "
for z in zs:
s = pairs_sim("ETH", "BTC", tf="15m", n=n, z_in=z, z_exit=1.0,
max_bars=35, pos=POS, lev=LEV)["sharpe"]
tot += 1; cells += s > 1
row += f"{s:>7.2f}"
print(row)
print(f" -> {cells}/{tot} celle Sharpe>1 (plateau se ~tutte; picco se poche)")
# [4] GATE PORT06
print("\n[4] GATE PORT06 — sleeve ETH/BTC: baseline(1h) vs SWAP(15m) vs BLEND(50/50):")
variants = {
"baseline 1h": e1h,
"SWAP 15m": e15,
"BLEND 1h+15m": blend(e1h, e15, 0.5),
}
print(f" {'variante':<14s} | {'FULL Sh':>8s}{'FULL DD%':>9s}{'CAGR':>6s}"
f" | {'OOS Sh':>7s}{'OOS DD%':>8s} | {'famSh':>6s}{'famDD%':>7s}")
print(" " + "-" * 78)
res = {}
for tag, eth in variants.items():
members = dict(eq_base)
members["PR_ETHBTC"] = eth
f, o = port_metrics(members, p)
fam_eqs = {sid: (eth if sid == "PR_ETHBTC" else eq_base[sid]) for sid in pair_ids}
ff, _ = fam_metrics(fam_eqs)
res[tag] = (f, o, ff)
print(f" {tag:<14s} | {f['sharpe']:>8.2f}{f['dd']:>9.2f}{f['cagr']:>5.0f}%"
f" | {o['sharpe']:>7.2f}{o['dd']:>8.2f} | {ff['sharpe']:>6.2f}{ff['dd']:>7.1f}")
# VERDETTO
fb, ob, _ = res["baseline 1h"]
print("\n" + "=" * 100)
print(" VERDETTO vs baseline 1h: promosso se OOS Sharpe non peggiora E DD scende (PORT06 e famiglia)")
print("=" * 100)
for tag in ("SWAP 15m", "BLEND 1h+15m"):
f, o, ff = res[tag]
ok = (o["sharpe"] >= ob["sharpe"] - 0.02 and o["dd"] <= ob["dd"] + 1e-9
and f["sharpe"] >= fb["sharpe"] - 0.02)
print(f" {tag:<14s}: OOS Sh {ob['sharpe']:.2f}->{o['sharpe']:.2f} "
f"DD {ob['dd']:.2f}->{o['dd']:.2f} | FULL Sh {fb['sharpe']:.2f}->{f['sharpe']:.2f} "
f"DD {fb['dd']:.2f}->{f['dd']:.2f} => {'PROMOSSO' if ok else 'bocciato'}")
if __name__ == "__main__":
main()