feat(live): fallback OHLCV a Deribit MAINNET quando Cerbero/testnet e' giu'
Deribit testnet (test.deribit.com) va giu' periodicamente (502) e Cerbero lo rilancia -> il runner si bloccava senza dati. Aggiunto CerberoClient.get_historical_mainnet (Deribit MAINNET public, NO-AUTH, paginato sotto il cap ~5000 candele/chiamata) e fallback nel runner: try Cerbero -> on fail/empty usa mainnet. Prezzi REALI (meglio del testnet farlocco per il paper). Verificato durante l'outage: tutti gli 8 strumenti (BTC/ETH + alt _USDC) coperti su mainnet. Log una-tantum all'attivazione/disattivazione del fallback. Caveat: testnet e mainnet hanno prezzi diversi (~9%) -> al primo switch le posizioni aperte su prezzi testnet vanno resettate (transizione pulita). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,41 @@ 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]:
|
||||
"""Enumera gli strumenti reali (v2). Usato per risolvere il naming senza hardcoding."""
|
||||
|
||||
Reference in New Issue
Block a user