From b5de241ebc0bebcc753ee222300eee04259f9d10 Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Tue, 2 Jun 2026 19:50:47 +0000 Subject: [PATCH] =?UTF-8?q?revert(live):=20rimuovi=20fallback=20mainnet=20?= =?UTF-8?q?=E2=80=94=20il=20paper=20deve=20usare=20il=20venue=20di=20esecu?= =?UTF-8?q?zione=20(testnet)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Il fallback a Deribit mainnet per i dati introduceva una DIVERGENZA paper<->esecuzione: il paper simulava su prezzi mainnet ma gli ordini (place_order via Cerbero) andrebbero su TESTNET, i cui prezzi/liquidità divergono ~9%. Un paper trader deve usare la STESSA fonte/venue dove gli ordini verrebbero eseguiti, altrimenti non predice il comportamento reale. Durante un outage testnet il runner si mette in pausa (corretto: senza il venue non si eseguirebbe comunque). Rimosso get_historical_mainnet e il wiring nel runner. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/live/cerbero_client.py | 34 ---------------------------------- src/portfolio/runner.py | 25 ++++++------------------- 2 files changed, 6 insertions(+), 53 deletions(-) diff --git a/src/live/cerbero_client.py b/src/live/cerbero_client.py index a3f16db..e3749b7 100644 --- a/src/live/cerbero_client.py +++ b/src/live/cerbero_client.py @@ -59,40 +59,6 @@ class CerberoClient: }) return data.get("candles", []) - def get_historical_mainnet(self, instrument: str, start_ms: int, end_ms: int, - resolution: str = "60") -> list[dict]: - """FALLBACK: OHLCV da Deribit MAINNET public (www.deribit.com, NO-AUTH) quando Cerbero - (testnet) è giù — es. 502 da test.deribit.com. Prezzi REALI (meglio del testnet per il - paper). Stesso shape di get_historical_v2: [{timestamp(ms),open,high,low,close,volume}]. - Pagina all'indietro (cap Deribit ~5000 candele/chiamata).""" - base = "https://www.deribit.com/api/v2/public/get_tradingview_chart_data" - span = 4900 * int(resolution) * 60 * 1000 # ~4900 candele/chiamata (< cap 5000) - out: list[dict] = [] - cur = end_ms - while cur > start_ms: - s = max(start_ms, cur - span) - try: - resp = requests.get(base, params={"instrument_name": instrument, "resolution": resolution, - "start_timestamp": s, "end_timestamp": cur}, timeout=TIMEOUT) - resp.raise_for_status() - r = resp.json().get("result", {}) - except Exception: - break - if r.get("status") != "ok" or not r.get("ticks"): - break - t = r["ticks"] - out += [{"timestamp": t[i], "open": r["open"][i], "high": r["high"][i], - "low": r["low"][i], "close": r["close"][i], "volume": r["volume"][i]} - for i in range(len(t))] - oldest = min(t) - if oldest >= cur: - break - cur = oldest - 1 - seen, ded = set(), [] - for x in sorted(out, key=lambda d: d["timestamp"]): - if x["timestamp"] not in seen: - seen.add(x["timestamp"]); ded.append(x) - return ded def get_instruments(self, currency: str, kind: str = "future", exchange: str = "deribit", limit: int = 100) -> list[dict]: diff --git a/src/portfolio/runner.py b/src/portfolio/runner.py index 0992c9b..6236c22 100644 --- a/src/portfolio/runner.py +++ b/src/portfolio/runner.py @@ -39,9 +39,6 @@ _LOOKBACK_DAYS = {"1h": 90, "4h": 220, "1d": 440} # margine ampio per il walk-forward. Difensivo: non dipende dal fetch 440g di TSM01/ROT02. _ML_LOOKBACK_DAYS = 365 -# stato del fallback dati: True quando Cerbero (testnet) è giù e usiamo Deribit MAINNET public -_MAINNET_FALLBACK = {"on": False} - def build_worker_for(spec: SleeveSpec, alloc_capital: float, leverage: float, data_dir: Path = DATA_DIR, position_size: float = 0.15): @@ -182,25 +179,15 @@ def run(config_path: str = "portfolios.yml"): # fetch 1h per asset al lookback massimo richiesto raw1h: dict[str, pd.DataFrame] = {} end = datetime.now(timezone.utc) + # SOLO testnet (via Cerbero): il paper DEVE usare lo stesso venue dove gli ordini + # verrebbero eseguiti (testnet). Mai sostituire con dati mainnet -> divergerebbe dal + # comportamento reale (prezzi/liquidità testnet != mainnet). Durante un outage testnet + # il runner si mette in pausa (corretto: senza il venue non si potrebbe eseguire). for asset, days in asset_days.items(): inst = inst_map.get(asset, f"{asset}-PERPETUAL") start = end - timedelta(days=days) - candles = None - try: - candles = client.get_historical_v2(inst, start.strftime("%Y-%m-%d"), - end.strftime("%Y-%m-%d"), "1h") - except Exception: - candles = None - if not candles: - # FALLBACK: Cerbero (testnet) giù -> OHLCV reale da Deribit MAINNET public - candles = client.get_historical_mainnet( - inst, int(start.timestamp() * 1000), int(end.timestamp() * 1000), "60") - if candles and not _MAINNET_FALLBACK["on"]: - _MAINNET_FALLBACK["on"] = True - print("[runner] FALLBACK attivo: OHLCV da Deribit MAINNET (Cerbero/testnet non disponibile)") - elif _MAINNET_FALLBACK["on"]: - _MAINNET_FALLBACK["on"] = False - print("[runner] Cerbero tornato disponibile: fallback mainnet disattivato") + candles = client.get_historical_v2(inst, start.strftime("%Y-%m-%d"), + end.strftime("%Y-%m-%d"), "1h") if candles: df = pd.DataFrame(candles) df["timestamp"] = df["timestamp"].astype("int64")