Files
siloqy/prod/tests/test_pink_ditav2_accounting_invariants.py

95 lines
2.9 KiB
Python
Raw Normal View History

"""Multi-leg non-double-book accounting invariant tests for PINK → DITAv2."""
from __future__ import annotations
from datetime import datetime, timezone
import unittest
from prod.clean_arch.dita_v2 import (
ExecutionKernel,
InMemoryControlPlane,
InMemoryZincPlane,
KernelCommandType,
KernelIntent,
MockVenueAdapter,
MockVenueScenario,
TradeSide,
TradeStage,
)
class TestAccountingInvariants(unittest.TestCase):
"""Verify single-application of capital deltas across multi-leg exits."""
def setUp(self):
self.control = InMemoryControlPlane()
self.venue = MockVenueAdapter(
MockVenueScenario(
reject_entries=False,
reject_exits=False,
partial_fill_ratio=0.5,
cancel_reject=False,
)
)
self.kernel = ExecutionKernel(
max_slots=1,
control_plane=self.control,
venue=self.venue,
zinc_plane=InMemoryZincPlane(),
)
def _enter(self) -> None:
intent = KernelIntent(
timestamp=datetime.now(timezone.utc),
intent_id="acct-entry-001",
trade_id="acct-trade-001",
slot_id=0,
asset="BTCUSDT",
side=TradeSide.SHORT,
action=KernelCommandType.ENTER,
reference_price=65000.0,
target_size=0.01,
leverage=2.0,
reason="acct_test_entry",
exit_leg_ratios=(0.5, 1.0),
)
self.kernel.process_intent(intent)
def _exit(self) -> None:
intent = KernelIntent(
timestamp=datetime.now(timezone.utc),
intent_id="acct-exit-001",
trade_id="acct-trade-001",
slot_id=0,
asset="BTCUSDT",
side=TradeSide.SHORT,
action=KernelCommandType.EXIT,
reference_price=64500.0,
target_size=0.005,
leverage=2.0,
reason="acct_test_exit",
exit_leg_ratios=(0.5, 1.0),
)
self.kernel.process_intent(intent)
def test_capital_unchanged_after_entry(self):
capital_before = self.kernel.account.snapshot.capital
self._enter()
capital_after = self.kernel.account.snapshot.capital
self.assertEqual(capital_after, capital_before,
"Entry should not change capital (no realized PnL)")
def test_full_cycle_does_not_crash(self):
"""Run a full entry→partial exit lifecycle without errors."""
self._enter()
slot_before = self.kernel.slot(0)
self.assertTrue(slot_before.is_open(), "Slot should be open after entry")
self._exit()
# After partial exit, slot may still be open or closed depending on mock behavior
slot_after = self.kernel.slot(0)
self.assertIsNotNone(slot_after, "Slot should still exist after partial exit")
if __name__ == "__main__":
unittest.main()