"""Source-level sizing guards in the PINK algo runner (pink_direct). notional = capital × fraction × leverage is self-limiting (no division); the only non-finite ingress is a corrupt raw input feeding size = notional / price. So: - ENTER: a non-finite capital or a price below the industry-smallest-price floor is an untrustworthy signal -> suppress the OPEN (never trade on bad math). - EXIT: size the close from the kernel's authoritative slot accounting, so a malformed policy size can neither strand a position nor overshoot it. """ from __future__ import annotations import asyncio from dataclasses import replace from datetime import datetime, timezone from prod.clean_arch.dita_v2 import ( ExecutionKernel, InMemoryControlPlane, KernelCommandType, KernelControlSnapshot, KernelMode, KernelVerbosity, MemoryKernelJournal, MockVenueAdapter, MockVenueScenario, TradeSide, ) from prod.clean_arch.dita_v2.contracts import KernelIntent from prod.clean_arch.dita import DecisionAction, DecisionConfig, DecisionEngine, IntentEngine from prod.clean_arch.runtime.pink_direct import PinkDirectRuntime, _MIN_SANE_PRICE from prod.clean_arch.ports.data_feed import DataFeedPort, MarketSnapshot class _StubFeed(DataFeedPort): async def connect(self): return True async def disconnect(self): pass async def get_latest_snapshot(self, symbol): return None async def subscribe_snapshots(self, callback): pass async def get_acb_update(self): return None def get_latency_ms(self): return 0.0 def health_check(self): return True def _runtime(capital: float): kernel = ExecutionKernel( control_plane=InMemoryControlPlane( KernelControlSnapshot(mode=KernelMode.DEBUG, verbosity=KernelVerbosity.TRACE) ), venue=MockVenueAdapter(MockVenueScenario(emit_fill_on_submit=True, partial_fill_ratio=1.0)), journal=MemoryKernelJournal(), ) kernel.account.snapshot.capital = capital kernel.account.snapshot.peak_capital = capital if capital == capital else 25000.0 kernel.account.snapshot.equity = capital cfg = DecisionConfig() # capital_fraction=0.20, allow_short=True, max_leverage=5 runtime = PinkDirectRuntime( data_feed=_StubFeed(), kernel=kernel, decision_engine=DecisionEngine(cfg), intent_engine=IntentEngine(cfg), persistence=None, market_state_runtime=None, ) return runtime, kernel def _enter_snap(price: float) -> MarketSnapshot: return MarketSnapshot( timestamp=datetime.now(timezone.utc), symbol="BTCUSDT", price=price, bid=price * 0.999, ask=price * 1.001, eigenvalues=[1.0], velocity_divergence=-0.05, irp_alignment=0.5, scan_number=1, source="test", ) def test_enter_suppressed_on_nonfinite_capital(): runtime, kernel = _runtime(float("inf")) decision = asyncio.run(runtime.step(_enter_snap(100.0))) assert decision.action == DecisionAction.ENTER # policy decided to enter assert kernel.slot(0).is_free(), "ENTER must be suppressed on non-finite capital" def test_enter_suppressed_on_subfloor_price(): runtime, kernel = _runtime(25_000.0) decision = asyncio.run(runtime.step(_enter_snap(_MIN_SANE_PRICE / 100.0))) assert kernel.slot(0).is_free(), "ENTER must be suppressed on a sub-floor price" def test_enter_proceeds_on_sane_inputs(): runtime, kernel = _runtime(25_000.0) decision = asyncio.run(runtime.step(_enter_snap(100.0))) assert decision.action == DecisionAction.ENTER assert not kernel.slot(0).is_free(), "sane ENTER must open a position" def test_exit_sizes_from_kernel_slot_accounting(): runtime, kernel = _runtime(25_000.0) asyncio.run(runtime.step(_enter_snap(100.0))) # open a position slot_size = float(kernel.slot(0).size) assert slot_size > 0.0 base = KernelIntent( timestamp=datetime.now(timezone.utc), intent_id="x", trade_id=kernel.slot(0).trade_id, slot_id=0, asset="BTCUSDT", side=TradeSide.SHORT, action=KernelCommandType.EXIT, reference_price=100.0, target_size=999.0, leverage=1.0, exit_leg_ratios=(1.0,), reason="X", ) # Oversized policy size -> capped to the real remaining size. assert abs(runtime._exit_intent_from_slot(base).target_size - slot_size) < 1e-9 # Non-finite policy size -> full remaining size (never strands). assert abs(runtime._exit_intent_from_slot(replace(base, target_size=float("inf"))).target_size - slot_size) < 1e-9 # Valid partial -> respected. assert abs(runtime._exit_intent_from_slot(replace(base, target_size=slot_size * 0.5)).target_size - slot_size * 0.5) < 1e-9