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