Files
PythagorasGoal/Old/scripts/analysis/real_dip_pairs_check.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

138 lines
5.7 KiB
Python

"""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()