"""VERIFICA su dati REALI — DIP01 e i 6 pairs hanno edge su prezzi veri? Le 6 fade sono morte su mainnet/Binance (edge = artefatto-print testnet). Restano i candidati piu' probabili a sopravvivere: i pairs (market-neutral sul log-ratio -> i print di singolo asset si elidono in parte) e DIP01. Test: monkeypatch di load_data / get_df -> serie 100% Binance spot (provato ~ mainnet: disc <0.13%), STESSO engine canonico (pairs_sim / dip_market_gated). Cache in data/raw/_real_*.parquet (NON tocca i canonici). """ from __future__ import annotations import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(PROJECT_ROOT)) import numpy as np, pandas as pd, ccxt SYM = {"BTC": "BTC/USDT", "ETH": "ETH/USDT", "LTC": "LTC/USDT", "ADA": "ADA/USDT", "SOL": "SOL/USDT"} START, END = "2020-06-01", "2026-05-26" YEARS = [2021, 2022, 2023, 2024, 2025, 2026] _EX = None _CACHE: dict[tuple, pd.DataFrame] = {} def _ex(): global _EX if _EX is None: _EX = ccxt.binance({"enableRateLimit": True}) return _EX def fetch(asset, tf): key = (asset, tf) if key in _CACHE: return _CACHE[key] cache = PROJECT_ROOT / "data" / "raw" / f"_real_{asset.lower()}_{tf}.parquet" if cache.exists(): df = pd.read_parquet(cache); _CACHE[key] = df; return df tf_ms = {"15m": 15, "1h": 60}[tf] * 60 * 1000 start_ms = int(pd.Timestamp(START, tz="UTC").timestamp() * 1000) end_ms = int(pd.Timestamp(END, tz="UTC").timestamp() * 1000) rows, since = [], start_ms while since <= end_ms: r = _ex().fetch_ohlcv(SYM[asset], tf, since=since, limit=1000) if not r: break rows += r nxt = int(r[-1][0]) + tf_ms if nxt <= since: break since = nxt df = pd.DataFrame(rows, columns=["timestamp", "open", "high", "low", "close", "volume"]) df = df.drop_duplicates("timestamp").sort_values("timestamp").reset_index(drop=True) df = df[df["timestamp"] <= end_ms].reset_index(drop=True) df.to_parquet(cache, index=False); _CACHE[key] = df return df # ---- monkeypatch dei loader dei due engine canonici ---- def _patched_load_data(asset, tf="1h"): return fetch(asset, tf) def _patched_get_df(asset, tf="1h"): return fetch(asset, tf) def daily_from_eq(eq_ts, eq_v): idx = pd.date_range("2021-01-01", END, freq="1D", tz="UTC") s = pd.Series(eq_v, index=pd.to_datetime(eq_ts, utc=True)).resample("1D").last().reindex(idx).ffill().bfill() return s / s.iloc[0] def metrics_from_daily(s, split_date="2024-10-12"): r = s.pct_change().fillna(0.0) def m(rr): eq = (1 + rr).cumprod(); peak = eq.cummax() dd = float(((peak - eq) / peak).max() * 100) sh = float(rr.mean() / rr.std() * np.sqrt(365)) if rr.std() > 0 else 0.0 return (eq.iloc[-1] - 1) * 100, dd, sh sd = pd.Timestamp(split_date, tz="UTC") fF, ddF, shF = m(r) ro = r[r.index >= sd] fO, ddO, shO = m(ro) yr = {int(y): float(((1 + r[r.index.year == y]).prod() - 1) * 100) for y in YEARS} return yr, fF, ddF, shF, fO, ddO, shO def main(): print("Fetch Binance spot (1h: BTC/ETH/LTC/ADA/SOL ; 15m: BTC/ETH)...\n") for a in SYM: fetch(a, "1h") for a in ("BTC", "ETH"): fetch(a, "15m") import scripts.analysis.pairs_research as PR import scripts.analysis.honest_improve2 as HI PR.load_data = _patched_load_data HI.get_df = _patched_get_df from scripts.analysis.pairs_research import pairs_sim, pairs_sim_flat, OOS_FRAC from scripts.strategies.PR01_pairs_reversion import PAIRS # ---------- DIP01 ---------- print("=" * 96) print(" DIP01 (BTC 1h dip-buy) su Binance spot REALE | RET% per anno + FULL/OOS (leva 3x)") print("=" * 96) d = HI.dip_market_gated("BTC", market_n=0, return_equity=True) s = daily_from_eq(d["eq_ts"], d["eq_v"]) yr, fF, ddF, shF, fO, ddO, shO = metrics_from_daily(s) print(f" {'':<10s}" + "".join(f"{y:>9d}" for y in YEARS) + " | FULL% DD% Shrp | OOS% Shrp") print(f" {'DIP01_BTC':<10s}" + "".join(f"{yr[y]:>+9.0f}" for y in YEARS) + f" | {fF:>+7.0f}{ddF:>5.0f}{shF:>6.2f} | {fO:>+6.0f}{shO:>6.2f}") # ---------- PAIRS (5 univ + BLEND 15m) ---------- print("\n" + "=" * 96) print(" PAIRS PR01 su Binance spot REALE | fee 0.20% RT/coppia, leva 3x | (canonico CLAUDE.md fra parentesi)") print("=" * 96) print(f" {'coppia':<12s}{'trd':>6s}{'win%':>6s}{'CAGR%':>7s}{'DD%':>6s}{'Shrp':>6s}{'oDD%':>6s}{'anni+':>7s}") canon = {"ETH/BTC": 4.36, "LTC/ETH": 3.08, "ADA/ETH": 2.69, "BTC/LTC": 2.36, "ETH/SOL": 1.96} for a, b, p in PAIRS: f = pairs_sim(a, b, **p) o = pairs_sim(a, b, **p, split_frac=1 - OOS_FRAC) yrs = f["yearly"]; pos_y = sum(1 for v in yrs.values() if v > 0) name = f"{a}/{b}" print(f" {name:<12s}{f['trades']:>6d}{f['win']:>6.1f}{f['cagr']:>7.0f}{f['dd']:>6.0f}" f"{f['sharpe']:>6.2f}{o['dd']:>6.0f}{pos_y:>5d}/{len(yrs)} (canon Sh {canon.get(name,'?')})") # BLEND ETH/BTC 15m (mezza size, flat-skip) come nel portafoglio r15 = pairs_sim_flat("ETH", "BTC", tf="15m", n=66, z_in=1.674, z_exit=1.0, max_bars=35, flat_skip=True, pos=0.075) o15 = pairs_sim_flat("ETH", "BTC", tf="15m", n=66, z_in=1.674, z_exit=1.0, max_bars=35, flat_skip=True, pos=0.075, split_frac=1 - OOS_FRAC) yrs = r15["yearly"]; pos_y = sum(1 for v in yrs.values() if v > 0) print(f" {'ETH/BTC 15m':<12s}{r15['trades']:>6d}{r15['win']:>6.1f}{r15['cagr']:>7.0f}{r15['dd']:>6.0f}" f"{r15['sharpe']:>6.2f}{o15['dd']:>6.0f}{pos_y:>5d}/{len(yrs)} (BLEND mezza size)") if __name__ == "__main__": main()