"""TP01 LIVE EXECUTE — loop di esecuzione GATED su Deribit mainnet (USDC linear). Porta il conto reale al target di TP01 (causale, dati certificati): per ogni asset calcola il notional bersaglio = min(0.5 * frazione * equity, max_notional), e apre/riduce/chiude per raggiungerlo. DOPPIO GATE DI SICUREZZA (entrambi necessari per inviare ordini reali): 1. config/live.json -> "execution_enabled": true (master switch, default false) 2. flag CLI --execute Senza entrambi e' un DRY-RUN (stampa il piano, NON invia). Reconciliation dopo ogni ordine; log in data/live/executions.jsonl. TP01 oggi e' FLAT -> target 0 -> nessuna azione finche' il segnale non gira. uv run python scripts/live/live_execute.py # DRY-RUN (piano, nessun ordine) uv run python scripts/live/live_execute.py --execute # esegue SOLO se execution_enabled=true """ from __future__ import annotations import json import sys from pathlib import Path import pandas as pd PROJECT_ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(PROJECT_ROOT)) from src.live.deribit import INSTRUMENT from src.live.execution import DeribitTrader from src.live.shadow import ASSETS, WEIGHT, shadow_report CONFIG = PROJECT_ROOT / "config" / "live.json" LOG_DIR = PROJECT_ROOT / "data" / "live" LOG = LOG_DIR / "executions.jsonl" def load_config() -> dict: cfg = json.loads(CONFIG.read_text()) if CONFIG.exists() else {} cfg.setdefault("execution_enabled", False) cfg.setdefault("max_notional_per_asset_usd", 300.0) cfg.setdefault("min_order_usd", 5.0) cfg.setdefault("disaster_sl_pct", 0.30) return cfg def log_event(rec: dict): LOG_DIR.mkdir(parents=True, exist_ok=True) with open(LOG, "a") as f: f.write(json.dumps(rec) + "\n") def main(): cfg = load_config() want_execute = "--execute" in sys.argv[1:] enabled = bool(cfg["execution_enabled"]) do_execute = want_execute and enabled max_notional = float(cfg["max_notional_per_asset_usd"]) min_order = float(cfg["min_order_usd"]) sl_pct = float(cfg["disaster_sl_pct"]) r = shadow_report() # targets causali + conto/posizioni reali (online) equity = r["equity"] print("=" * 84) print(" TP01 LIVE EXECUTE — Deribit mainnet (USDC linear)") print("=" * 84) mode = ("ESECUZIONE REALE" if do_execute else ("ARMATO ma manca --execute" if enabled else "DRY-RUN (execution_enabled=false)")) print(f" modo : {mode}") print(f" gate : execution_enabled={enabled} | --execute={want_execute}") print(f" conto reale : ${r['real_equity']:,.2f}" if r["real_equity"] else f" conto: {r['eq_basis']}") print(f" sizing base : ${equity:,.2f} | cap/asset ${max_notional:.0f} | min ${min_order:.0f} | disaster-SL -{sl_pct*100:.0f}%") print(f" ultima barra : {r['last_data']}\n") if not r["online"]: print(" conto non leggibile (offline) -> stop, non eseguo a cieco.") return trader = DeribitTrader() if do_execute else None actions = [] for a in r["assets"]: asset = a["asset"]; frac = a["target"]; mark = a["mark"]; cur = a["position_usd"] tgt = min(WEIGHT * frac * equity, max_notional) if frac > 0 else 0.0 delta = tgt - cur if abs(delta) < min_order: act = "HOLD (a target)" elif tgt < 1.0 and cur > 1.0: act = f"CLOSE ${cur:,.0f}" elif delta > 0: act = f"BUY ${delta:,.0f}" else: act = f"REDUCE ${-delta:,.0f}" print(f" {asset:<3} target {frac:+.3f}x -> ${tgt:,.0f} | pos ${cur:,.0f} | delta ${delta:+,.0f} -> {act}") if do_execute: if not act.startswith("HOLD"): fills = trader.rebalance_to(INSTRUMENT[asset], tgt, mark, min_usd=min_order) newpos = trader.position_usd(INSTRUMENT[asset]) for f in fills: print(f" -> {f.side.upper()} {f.filled:.4f} @ ${f.price:,.1f} fee {f.fee_usdc:.5f} " f"({'OK' if f.verified else 'NON VERIFICATO: ' + f.notes})") log_event(dict(ts_utc=str(pd.Timestamp(r['last_data'])), asset=asset, action=act, side=f.side, filled=f.filled, price=f.price, fee=f.fee_usdc, verified=f.verified, notes=f.notes, pos_after=newpos)) print(f" reconcile: pos ${newpos:,.0f}") ds = trader.ensure_disaster_sl(INSTRUMENT[asset], sl_pct) # bracket: piazza se long, pulisce se flat print(f" disaster-SL: {ds.get('state')}" + (f" @ ${ds['stop']:,.1f}" if ds.get("stop") else "")) actions.append(act) print() if not do_execute: print(" => DRY-RUN: nessun ordine inviato." + ("" if enabled else " Per armare: config/live.json execution_enabled=true + --execute.")) elif all(x.startswith("HOLD") for x in actions): print(" => Nessuna azione: conto gia' al target di TP01 (oggi flat).") else: print(" => Esecuzione completata (vedi data/live/executions.jsonl).") if __name__ == "__main__": main()