14522262e6
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>
82 lines
3.9 KiB
Python
82 lines
3.9 KiB
Python
"""Smoke ESECUZIONE REALE a 2 gambe (PairsExecutionClient) su Deribit testnet.
|
|
|
|
Apre e chiude una posizione pair micro (ETH/BTC lineari USDC) come farebbe il
|
|
PairsWorker, esercitando: open_pair (2 market simultanei long A/short B), verifica
|
|
per-gamba, close_pair (2 reduce-only), riconciliazione PnL/fee a 2 gambe.
|
|
Verifica finale: conto flat su ENTRAMBI gli strumenti.
|
|
|
|
Costo testnet = €0. Non tocca lo stato di produzione (data_dir temporanea).
|
|
|
|
uv run python scripts/analysis/live_pairs_smoke.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from src.live.cerbero_client import CerberoClient
|
|
from src.live.execution import ExecutionClient, PairsExecutionClient
|
|
from src.live.pairs_worker import PairsWorker
|
|
|
|
|
|
def main() -> None:
|
|
client = CerberoClient()
|
|
acct = client.get_account_summary(currency="USDC")
|
|
print(f"Account testnet equity={acct.get('equity')} USDC testnet={acct.get('testnet')}")
|
|
if not acct.get("testnet"):
|
|
raise SystemExit("ABORT: non testnet")
|
|
|
|
pex = PairsExecutionClient(leg=ExecutionClient(client=client))
|
|
inst = {"ETH": "ETH_USDC-PERPETUAL", "BTC": "BTC_USDC-PERPETUAL"}
|
|
pex.ensure_specs(*inst.values())
|
|
print(f"strumenti: {inst}")
|
|
|
|
# GUARDIA: questo conto e' condiviso col runner di produzione (fade reali su
|
|
# BTC/ETH_USDC). Se ci sono posizioni aperte, ABORT: lo smoke userebbe lo stesso
|
|
# strumento e la verifica "conto flat" sarebbe falsata (e un eventuale
|
|
# close_position flatterebbe le quote del runner). Mai eseguire close_position qui.
|
|
for i in inst.values():
|
|
sz = pex.leg._position_size(i)
|
|
if sz != 0:
|
|
raise SystemExit(f"ABORT: posizione di produzione aperta su {i} (size={sz}). "
|
|
f"Eseguire lo smoke solo a conto flat.")
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
# capitale piccolo -> notional micro per gamba (capital*pos*lev)
|
|
w = PairsWorker("ETH", "BTC", "1h", capital=60.0, position_size=0.15, leverage=2.0,
|
|
data_dir=Path(tmp), executor=pex, exec_instruments=inst)
|
|
print(f"execution_enabled={w.execution_enabled} notional/gamba atteso=${60*0.15*2:.0f}")
|
|
|
|
# prezzi sim plausibili (il ramo sim del worker li usa per il suo ledger;
|
|
# il reale usa i fill veri). Niente zeri -> niente divisione per zero.
|
|
pa = pex.leg._mark_price(inst["ETH"]) or 1668.0
|
|
pb = pex.leg._mark_price(inst["BTC"]) or 63000.0
|
|
print("\n[A] OPEN long ratio (long ETH / short BTC)")
|
|
w._open(1, pa, pb, -2.5)
|
|
print(f" real_in_position={w.real_in_position} dir={w.real_dir}")
|
|
print(f" gamba A {w.real_side_a} {w.real_amount_a} @ {w.real_entry_a} (notional ${w.real_notional_a:.2f})")
|
|
print(f" gamba B {w.real_side_b} {w.real_amount_b} @ {w.real_entry_b} (notional ${w.real_notional_b:.2f})")
|
|
print(f" entry_fee ${w.real_entry_fee:.5f}")
|
|
assert w.real_in_position, "open pair non verificato"
|
|
assert w.real_side_a == "buy" and w.real_side_b == "sell"
|
|
|
|
print("\n[B] CLOSE (richiude entrambe le gambe reduce-only)")
|
|
cap0 = w.real_capital
|
|
pa2 = pex.leg._mark_price(inst["ETH"]) or pa
|
|
pb2 = pex.leg._mark_price(inst["BTC"]) or pb
|
|
w._close(pa2, pb2, 0.3, "mean_revert")
|
|
print(f" real_capital {cap0:.4f} -> {w.real_capital:.4f} (Δ {w.real_capital-cap0:+.4f}) trades={w.real_trades}")
|
|
assert not w.real_in_position, "close pair non azzera la posizione"
|
|
|
|
# verifica conto flat su entrambi gli strumenti
|
|
pa = pex.leg._position_size(inst["ETH"])
|
|
pb = pex.leg._position_size(inst["BTC"])
|
|
print(f"\n posizione netta ETH={pa} BTC={pb}")
|
|
print("✓ catena pairs OK — open 2 gambe verificate, close 2 gambe, fee reali, conto flat"
|
|
if pa == 0 and pb == 0 else
|
|
f"⚠ residuo sul book (ETH={pa} BTC={pb}) — verificare manualmente")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|