"""Smoke della catena SHADOW dentro lo StrategyWorker (testnet, ordini reali minimi). Apre e chiude la quota di UN worker fade come farebbe il runner: _open_position (sim + REAL_OPEN reale su BTC_USDC) → _close_position (sim + REAL_CLOSE reduce-only) → controlla che real_capital sia aggiornato dal fill reale. Non tocca lo stato di produzione (data_dir temporanea). Costo testnet = €0. uv run python scripts/analysis/live_shadow_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 from src.live.strategy_loader import load_strategy from src.live.strategy_worker import StrategyWorker from src.strategies.base import Signal 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") ex = ExecutionClient(client=client) instrument = "BTC_USDC-PERPETUAL" price = ex._mark_price(instrument) print(f"{instrument} mark={price}") with tempfile.TemporaryDirectory() as tmp: w = StrategyWorker( strategy=load_strategy("MR01_bollinger_fade"), asset="BTC", tf="1h", capital=100.0, position_size=0.15, leverage=2.0, data_dir=Path(tmp), executor=ex, exec_instrument=instrument, ) print(f"execution_enabled={w.execution_enabled} notional atteso=${100*0.15*2:.0f}") # OPEN long (sim + reale) sig = Signal(idx=0, direction=1, entry_price=price, metadata={}) w._open_position(sig, price) print(f" real_in_position={w.real_in_position} side={w.real_side} " f"amount={w.real_amount} entry={w.real_entry_price} " f"entry_fee=${w.real_entry_fee_usd:.5f} notional=${w.real_entry_notional:.2f}") assert w.real_in_position, "OPEN reale non verificato" # CLOSE (sim + reale reduce-only) a un prezzo leggermente diverso exit_price = (w.entry_price or price) * 1.001 cap_before = w.real_capital w._close_position(exit_price, "smoke_close") print(f" real_capital {cap_before:.4f} -> {w.real_capital:.4f} " f"(Δ {w.real_capital - cap_before:+.4f}) real_trades={w.real_trades}") assert not w.real_in_position, "posizione reale non chiusa" # verifica finale: il conto e' flat sullo strumento (nessuna quota residua del worker) pos = ex._position_size(instrument) print(f" posizione netta {instrument}: {pos}") print("✓ catena shadow OK — ordine reale aperto, verificato, chiuso reduce-only, " "fee reali nel ledger reale") if __name__ == "__main__": main()