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:
@@ -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()
|
||||
Reference in New Issue
Block a user