revert(live): rimuovi fallback mainnet — il paper deve usare il venue di esecuzione (testnet)
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) <noreply@anthropic.com>
This commit is contained in:
@@ -59,40 +59,6 @@ class CerberoClient:
|
|||||||
})
|
})
|
||||||
return data.get("candles", [])
|
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",
|
def get_instruments(self, currency: str, kind: str = "future",
|
||||||
exchange: str = "deribit", limit: int = 100) -> list[dict]:
|
exchange: str = "deribit", limit: int = 100) -> list[dict]:
|
||||||
|
|||||||
+6
-19
@@ -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.
|
# margine ampio per il walk-forward. Difensivo: non dipende dal fetch 440g di TSM01/ROT02.
|
||||||
_ML_LOOKBACK_DAYS = 365
|
_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,
|
def build_worker_for(spec: SleeveSpec, alloc_capital: float, leverage: float,
|
||||||
data_dir: Path = DATA_DIR, position_size: float = 0.15):
|
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
|
# fetch 1h per asset al lookback massimo richiesto
|
||||||
raw1h: dict[str, pd.DataFrame] = {}
|
raw1h: dict[str, pd.DataFrame] = {}
|
||||||
end = datetime.now(timezone.utc)
|
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():
|
for asset, days in asset_days.items():
|
||||||
inst = inst_map.get(asset, f"{asset}-PERPETUAL")
|
inst = inst_map.get(asset, f"{asset}-PERPETUAL")
|
||||||
start = end - timedelta(days=days)
|
start = end - timedelta(days=days)
|
||||||
candles = None
|
candles = client.get_historical_v2(inst, start.strftime("%Y-%m-%d"),
|
||||||
try:
|
end.strftime("%Y-%m-%d"), "1h")
|
||||||
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")
|
|
||||||
if candles:
|
if candles:
|
||||||
df = pd.DataFrame(candles)
|
df = pd.DataFrame(candles)
|
||||||
df["timestamp"] = df["timestamp"].astype("int64")
|
df["timestamp"] = df["timestamp"].astype("int64")
|
||||||
|
|||||||
Reference in New Issue
Block a user