First commit of the previously-untracked PINK-on-DITAv2 migration system (execution moves to the Rust kernel; policy stays on legacy DITA, so Alpha Engine algorithmic integrity is preserved). BLUE is untouched. Sprint 0 (safety snapshot + flaw-fix verification, MARKET single-leg scope): - Verified Rust FSM fixes (flaws 2,4,10,11,13) by source read of lib.rs. - Hardened 5 vacuous/guarded assertions in test_flaws.py so each flaw test genuinely exercises its fix. Most important: Flaw 5 now asserts capital moves by EXACTLY realized PnL (was entering/exiting at the same price). - Offline suites: 533 passed, 0 failed (35 flaws + 402 kernel/accounting/ bridge + 96 runtime/persistence/multi-exit/restart/seams). - GATE PASS: MARKET-path-critical flaws 1,2,5 confirmed fixed + green. - Added SPRINT0_FLAW_VERIFICATION.md report and _rust_kernel/.gitignore (excludes Rust target/ build artifacts). LIMIT/partial-fill remain explicitly out of scope (MARKET-only bring-up). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
381 lines
16 KiB
Python
381 lines
16 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
import os
|
|
import random
|
|
import threading
|
|
import time
|
|
import unittest
|
|
from uuid import uuid4
|
|
|
|
from prod.clean_arch.dita_v2 import (
|
|
ControlUpdate,
|
|
ExecutionKernel,
|
|
InMemoryControlPlane,
|
|
KernelCommandType,
|
|
KernelDiagnosticCode,
|
|
KernelControlSnapshot,
|
|
KernelIntent,
|
|
KernelMode,
|
|
KernelVerbosity,
|
|
MockVenueAdapter,
|
|
MockVenueScenario,
|
|
InMemoryZincPlane,
|
|
RealZincPlane,
|
|
RealZincControlPlane,
|
|
RealZincUnavailable,
|
|
TradeSide,
|
|
TradeSlot,
|
|
TradeStage,
|
|
VenueEvent,
|
|
VenueEventStatus,
|
|
KernelEventKind,
|
|
)
|
|
from prod.clean_arch.dita_v2.real_zinc_plane import SharedRegion
|
|
|
|
|
|
HAS_REAL_ZINC = SharedRegion is not None
|
|
|
|
|
|
def mk_intent_kwargs(
|
|
*,
|
|
slot_id: int,
|
|
trade_id: str,
|
|
action: KernelCommandType,
|
|
size: float = 1.0,
|
|
leverage: float = 2.0,
|
|
side: TradeSide = TradeSide.SHORT,
|
|
price: float = 100.0,
|
|
reason: str = "FUZZ",
|
|
) -> dict[str, object]:
|
|
return {
|
|
"timestamp": datetime.now(timezone.utc),
|
|
"intent_id": f"intent-{trade_id}-{action.value}-{slot_id}",
|
|
"trade_id": trade_id,
|
|
"slot_id": slot_id,
|
|
"asset": "BTCUSDT",
|
|
"side": side,
|
|
"action": action,
|
|
"reference_price": price,
|
|
"target_size": size,
|
|
"leverage": leverage,
|
|
"exit_leg_ratios": (0.5, 0.5) if action == KernelCommandType.EXIT else (1.0,),
|
|
"reason": reason,
|
|
}
|
|
|
|
|
|
@unittest.skipUnless(HAS_REAL_ZINC, "Real Zinc adapter is unavailable")
|
|
class TestDITAv2RealZinc(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.prefix = f"dita_v2_{os.getpid()}_{uuid4().hex}"
|
|
self.writer = RealZincPlane(prefix=self.prefix, slot_count=3, create=True)
|
|
self.reader = RealZincPlane(prefix=self.prefix, slot_count=3, create=False)
|
|
|
|
def tearDown(self) -> None:
|
|
self.writer.close()
|
|
self.reader.close()
|
|
|
|
def _slot_dicts(self, plane: RealZincPlane) -> list[dict[str, object]]:
|
|
return [slot.to_dict() for slot in plane.read_slots()]
|
|
|
|
def test_wait_notify_and_roundtrip(self) -> None:
|
|
waiter_started = threading.Event()
|
|
waiter_result: dict[str, bool] = {"ok": False}
|
|
|
|
def _waiter() -> None:
|
|
waiter_started.set()
|
|
waiter_result["ok"] = self.reader.wait_on_state(timeout_ms=3000)
|
|
|
|
thread = threading.Thread(target=_waiter, daemon=True)
|
|
thread.start()
|
|
self.assertTrue(waiter_started.wait(timeout=2.0))
|
|
time.sleep(0.05)
|
|
|
|
kernel_slot = self.writer.read_slots()
|
|
self.assertEqual(len(kernel_slot), 3)
|
|
self.assertTrue(all(slot.fsm_state == TradeStage.IDLE for slot in kernel_slot))
|
|
self.writer.write_slot(
|
|
TradeSlot(
|
|
slot_id=0,
|
|
trade_id="trade-zinc-1",
|
|
asset="BTCUSDT",
|
|
side=TradeSide.SHORT,
|
|
entry_price=100.0,
|
|
size=1.0,
|
|
initial_size=1.0,
|
|
leverage=2.0,
|
|
fsm_state=TradeStage.POSITION_OPEN,
|
|
)
|
|
)
|
|
thread.join(timeout=3.0)
|
|
self.assertFalse(thread.is_alive())
|
|
self.assertTrue(waiter_result["ok"])
|
|
slots = self.reader.read_slots()
|
|
self.assertEqual(len(slots), 3)
|
|
self.assertEqual(slots[0].trade_id, "trade-zinc-1")
|
|
self.assertEqual(slots[0].fsm_state, TradeStage.POSITION_OPEN)
|
|
self.assertTrue(all(slot.fsm_state == TradeStage.IDLE for slot in slots[1:]))
|
|
|
|
def test_in_memory_wait_notify_matches_signal_semantics(self) -> None:
|
|
plane = InMemoryZincPlane()
|
|
waiter_started = threading.Event()
|
|
waiter_result: dict[str, bool] = {"ok": False}
|
|
|
|
def _waiter() -> None:
|
|
waiter_started.set()
|
|
waiter_result["ok"] = plane.wait_on_state(timeout_ms=2000)
|
|
|
|
thread = threading.Thread(target=_waiter, daemon=True)
|
|
thread.start()
|
|
self.assertTrue(waiter_started.wait(timeout=2.0))
|
|
time.sleep(0.05)
|
|
plane.write_slot(
|
|
TradeSlot(
|
|
slot_id=0,
|
|
trade_id="trade-signal",
|
|
asset="BTCUSDT",
|
|
side=TradeSide.LONG,
|
|
entry_price=101.0,
|
|
size=1.0,
|
|
initial_size=1.0,
|
|
leverage=2.0,
|
|
fsm_state=TradeStage.POSITION_OPEN,
|
|
)
|
|
)
|
|
thread.join(timeout=3.0)
|
|
self.assertFalse(thread.is_alive())
|
|
self.assertTrue(waiter_result["ok"])
|
|
|
|
def test_real_control_plane_roundtrip_uses_open_existing_region(self) -> None:
|
|
prefix = f"dita_v2_control_{os.getpid()}_{uuid4().hex}"
|
|
plane = RealZincPlane(prefix=prefix, slot_count=1, create=True)
|
|
control = RealZincControlPlane(prefix=prefix, create=False)
|
|
try:
|
|
snapshot = control.read()
|
|
self.assertEqual(getattr(snapshot.mode, "value", snapshot.mode), KernelMode.NORMAL.value)
|
|
self.assertEqual(getattr(snapshot.verbosity, "value", snapshot.verbosity), KernelVerbosity.QUIET.value)
|
|
updated = control.update(ControlUpdate(mode=KernelMode.DEBUG, verbosity=KernelVerbosity.TRACE))
|
|
self.assertEqual(getattr(updated.mode, "value", updated.mode), KernelMode.DEBUG.value)
|
|
self.assertEqual(getattr(updated.verbosity, "value", updated.verbosity), KernelVerbosity.TRACE.value)
|
|
mirrored = plane.read_control()
|
|
self.assertEqual(getattr(mirrored.mode, "value", mirrored.mode), KernelMode.DEBUG.value)
|
|
self.assertEqual(getattr(mirrored.verbosity, "value", mirrored.verbosity), KernelVerbosity.TRACE.value)
|
|
finally:
|
|
control.close()
|
|
plane.close()
|
|
|
|
def test_real_control_plane_create_conflicts_with_existing_zinc_plane(self) -> None:
|
|
prefix = f"dita_v2_conflict_{os.getpid()}_{uuid4().hex}"
|
|
plane = RealZincPlane(prefix=prefix, slot_count=1, create=True)
|
|
try:
|
|
with self.assertRaises(FileExistsError):
|
|
RealZincControlPlane(prefix=prefix, create=True)
|
|
finally:
|
|
plane.close()
|
|
|
|
def test_kernel_accepts_real_control_plane_snapshot_strings(self) -> None:
|
|
prefix = f"dita_v2_kernel_real_cp_{os.getpid()}_{uuid4().hex}"
|
|
plane = RealZincPlane(prefix=prefix, slot_count=1, create=True)
|
|
control = RealZincControlPlane(prefix=prefix, create=False)
|
|
try:
|
|
kernel = ExecutionKernel(
|
|
max_slots=1,
|
|
control_plane=control,
|
|
venue=MockVenueAdapter(MockVenueScenario(emit_fill_on_submit=True, partial_fill_ratio=1.0)),
|
|
zinc_plane=plane,
|
|
)
|
|
kernel.update_control(
|
|
ControlUpdate(
|
|
mode=KernelMode.DEBUG,
|
|
verbosity=KernelVerbosity.TRACE,
|
|
trace_transitions=True,
|
|
)
|
|
)
|
|
outcome = kernel.process_intent(
|
|
KernelIntent(
|
|
**mk_intent_kwargs(
|
|
slot_id=0,
|
|
trade_id=f"trade-real-cp-{uuid4().hex}",
|
|
action=KernelCommandType.ENTER,
|
|
price=100.0,
|
|
size=1.0,
|
|
)
|
|
)
|
|
)
|
|
self.assertTrue(outcome.accepted)
|
|
self.assertEqual(outcome.diagnostic_code, KernelDiagnosticCode.OK)
|
|
self.assertEqual(kernel.slot(0).fsm_state, TradeStage.POSITION_OPEN)
|
|
self.assertEqual(getattr(kernel.control.mode, "value", kernel.control.mode), KernelMode.DEBUG.value)
|
|
self.assertEqual(getattr(kernel.control.verbosity, "value", kernel.control.verbosity), KernelVerbosity.TRACE.value)
|
|
finally:
|
|
control.close()
|
|
plane.close()
|
|
|
|
def test_kernel_and_zinc_fuzz_roundtrip_150_checks(self) -> None:
|
|
control = InMemoryControlPlane(
|
|
KernelControlSnapshot(mode=KernelMode.DEBUG, verbosity=KernelVerbosity.TRACE)
|
|
)
|
|
kernel = ExecutionKernel(
|
|
max_slots=3,
|
|
control_plane=control,
|
|
venue=MockVenueAdapter(MockVenueScenario(emit_fill_on_submit=True, partial_fill_ratio=1.0)),
|
|
zinc_plane=self.writer,
|
|
)
|
|
rng = random.Random(20260526)
|
|
|
|
for i in range(150):
|
|
slot_id = rng.randrange(0, 3)
|
|
slot = kernel.slot(slot_id)
|
|
op = rng.choice(
|
|
[
|
|
"enter",
|
|
"exit",
|
|
"mark",
|
|
"reconcile",
|
|
"control",
|
|
"event",
|
|
]
|
|
)
|
|
|
|
with self.subTest(iteration=i, slot=slot_id, op=op):
|
|
if op == "enter":
|
|
if slot.is_free():
|
|
kernel.process_intent(
|
|
KernelIntent(
|
|
**mk_intent_kwargs(
|
|
slot_id=slot_id,
|
|
trade_id=f"trade-{slot_id}-{i}",
|
|
action=KernelCommandType.ENTER,
|
|
price=100.0 + rng.random(),
|
|
size=1.0 + (rng.random() * 0.5),
|
|
leverage=1.5 + (rng.random() * 2.0),
|
|
)
|
|
)
|
|
)
|
|
elif op == "exit":
|
|
if slot.is_open():
|
|
kernel.process_intent(
|
|
KernelIntent(
|
|
**mk_intent_kwargs(
|
|
slot_id=slot_id,
|
|
trade_id=slot.trade_id,
|
|
action=KernelCommandType.EXIT,
|
|
price=99.0 + rng.random(),
|
|
size=max(0.1, slot.size or 0.1),
|
|
leverage=slot.leverage or 2.0,
|
|
)
|
|
)
|
|
)
|
|
elif op == "mark":
|
|
kernel.process_intent(
|
|
KernelIntent(
|
|
**mk_intent_kwargs(
|
|
slot_id=slot_id,
|
|
trade_id=slot.trade_id or f"trade-{slot_id}-{i}",
|
|
action=KernelCommandType.MARK_PRICE,
|
|
price=95.0 + rng.random() * 10.0,
|
|
size=max(slot.size, 1.0) if slot.size > 0 else 1.0,
|
|
leverage=slot.leverage or 2.0,
|
|
)
|
|
)
|
|
)
|
|
elif op == "reconcile":
|
|
kernel.process_intent(
|
|
KernelIntent(
|
|
**mk_intent_kwargs(
|
|
slot_id=slot_id,
|
|
trade_id=slot.trade_id or f"trade-{slot_id}-{i}",
|
|
action=KernelCommandType.RECONCILE,
|
|
price=100.0,
|
|
size=max(slot.size, 1.0) if slot.size > 0 else 1.0,
|
|
leverage=slot.leverage or 2.0,
|
|
)
|
|
)
|
|
)
|
|
elif op == "control":
|
|
kernel.update_control(
|
|
ControlUpdate(
|
|
mode=KernelMode.DEBUG if rng.random() < 0.7 else KernelMode.NORMAL,
|
|
verbosity=KernelVerbosity.TRACE if rng.random() < 0.5 else KernelVerbosity.VERBOSE,
|
|
trace_transitions=rng.random() < 0.5,
|
|
)
|
|
)
|
|
elif op == "event":
|
|
current = kernel.slot(slot_id)
|
|
if current.active_entry_order is not None:
|
|
event = VenueEvent(
|
|
timestamp=datetime.now(timezone.utc),
|
|
event_id=f"evt-{i}-{slot_id}",
|
|
trade_id=current.trade_id,
|
|
slot_id=slot_id,
|
|
kind=rng.choice(
|
|
[
|
|
KernelEventKind.ORDER_ACK,
|
|
KernelEventKind.PARTIAL_FILL,
|
|
KernelEventKind.FULL_FILL,
|
|
]
|
|
),
|
|
status=rng.choice(
|
|
[
|
|
VenueEventStatus.ACKED,
|
|
VenueEventStatus.PARTIALLY_FILLED,
|
|
VenueEventStatus.FILLED,
|
|
]
|
|
),
|
|
venue_order_id=current.active_entry_order.venue_order_id,
|
|
venue_client_id=current.active_entry_order.venue_client_id,
|
|
side=current.side,
|
|
asset=current.asset,
|
|
price=current.entry_price or 100.0,
|
|
size=current.size or 1.0,
|
|
filled_size=current.size or 1.0,
|
|
remaining_size=0.0,
|
|
)
|
|
kernel.on_venue_event(event)
|
|
elif current.active_exit_order is not None:
|
|
event = VenueEvent(
|
|
timestamp=datetime.now(timezone.utc),
|
|
event_id=f"evt-{i}-{slot_id}",
|
|
trade_id=current.trade_id,
|
|
slot_id=slot_id,
|
|
kind=rng.choice(
|
|
[
|
|
KernelEventKind.PARTIAL_FILL,
|
|
KernelEventKind.FULL_FILL,
|
|
KernelEventKind.CANCEL_ACK,
|
|
KernelEventKind.CANCEL_REJECT,
|
|
]
|
|
),
|
|
status=rng.choice(
|
|
[
|
|
VenueEventStatus.PARTIALLY_FILLED,
|
|
VenueEventStatus.FILLED,
|
|
VenueEventStatus.CANCELED,
|
|
VenueEventStatus.CANCELED_REJECTED,
|
|
]
|
|
),
|
|
venue_order_id=current.active_exit_order.venue_order_id,
|
|
venue_client_id=current.active_exit_order.venue_client_id,
|
|
side=current.side,
|
|
asset=current.asset,
|
|
price=current.entry_price or 100.0,
|
|
size=current.size or 1.0,
|
|
filled_size=min(current.size or 1.0, 0.5),
|
|
remaining_size=max(0.0, (current.size or 1.0) - 0.5),
|
|
)
|
|
kernel.on_venue_event(event)
|
|
|
|
writer_slots = self._slot_dicts(self.writer)
|
|
reader_slots = self._slot_dicts(self.reader)
|
|
kernel_slots = [slot.to_dict() for slot in kernel.state.slots]
|
|
|
|
self.assertEqual(writer_slots, reader_slots)
|
|
self.assertEqual(reader_slots, kernel_slots)
|
|
self.assertEqual(self.reader.read_control().mode, kernel.control.mode)
|
|
self.assertEqual(self.reader.read_control().verbosity, kernel.control.verbosity)
|
|
self.assertEqual(len(self.reader.read_intents()), len(self.writer.read_intents()))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|