VIOLET V2b: ScriptedVenue + ExecDeadlineDriver (event-driven TTL @sub-second)
exec_driver.py lifts PINK's TTL-resolution logic (_exec_after_submit / _handle_expired_working, live-proven) into a standalone driver with injected ports (router/submit/pump/slot_view/venue_flat/ref-price) and replaces the 1s polling sweep with one DeadlineScheduler deadline per working order. The driver is the TIMING authority (router clamps TTLs >=0.5s — its internal deadline is vestigial here); the router stays the POLICY authority. R1 preserved verbatim: exit TTL -> MARKET escalation on the SAME trade_id; post-only reject -> schedule_in(0) through the one shared resolution path; venue-truth requote gate fails safe. scripted_venue.py subclasses MockVenueAdapter (zero shared edits) with per-trade directives: IMMEDIATE_FILL / REST_THEN_FILL / REST_THEN_EXPIRE / POST_ONLY_REJECT / CANCEL_REJECT / FILL_RACES_CANCEL; deferred fills release through reconcile() (the production pump seam), never the 50ms subscribe() poll. 17 new tests incl. full-kernel CANCEL->venue mapping, fill-races-cancel, bounded retry chains, on_fill deadline cancellation, fail-safe probe. Router 77 green untouched; shared files clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
137
prod/clean_arch/violet/test_violet_scripted_venue.py
Normal file
137
prod/clean_arch/violet/test_violet_scripted_venue.py
Normal file
@@ -0,0 +1,137 @@
|
||||
"""V2b: ScriptedVenue — directive semantics + kernel CANCEL mapping."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
|
||||
sys.path.insert(0, "/mnt/dolphinng5_predict")
|
||||
sys.path.insert(0, "/mnt/dolphinng5_predict/nautilus_dolphin")
|
||||
|
||||
import pytest
|
||||
|
||||
from prod.clean_arch.dita_v2.contracts import (
|
||||
KernelCommandType,
|
||||
KernelEventKind,
|
||||
KernelIntent,
|
||||
TradeSide,
|
||||
TradeStage,
|
||||
)
|
||||
from prod.clean_arch.violet.scripted_venue import Directive, ScriptedVenue
|
||||
|
||||
|
||||
def _intent(tid: str, action=KernelCommandType.ENTER, *, order_type="LIMIT",
|
||||
limit_price=99.5, ref=100.0) -> KernelIntent:
|
||||
return KernelIntent(
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
intent_id=tid, trade_id=tid, slot_id=0,
|
||||
asset="BTCUSDT", side=TradeSide.SHORT, action=action,
|
||||
reference_price=ref, target_size=1.0, leverage=1.0,
|
||||
exit_leg_ratios=(1.0,), reason="test", metadata={},
|
||||
stage=TradeStage.INTENT_CREATED,
|
||||
order_type=order_type, limit_price=limit_price,
|
||||
)
|
||||
|
||||
|
||||
def test_rest_then_expire_acks_only_and_cancel_pops():
|
||||
v = ScriptedVenue()
|
||||
v.set_directive("T1", Directive.REST_THEN_EXPIRE)
|
||||
events = v.submit(_intent("T1"))
|
||||
assert [e.kind for e in events] == [KernelEventKind.ORDER_ACK]
|
||||
assert len(v.open_orders()) == 1
|
||||
order = v.open_orders()[0]
|
||||
assert order.internal_trade_id == "T1"
|
||||
out = v.cancel(order)
|
||||
assert [e.kind for e in out] == [KernelEventKind.CANCEL_ACK]
|
||||
assert v.open_orders() == []
|
||||
assert v.reconcile() == [] # nothing ever falls due
|
||||
|
||||
|
||||
def test_rest_then_fill_releases_via_reconcile_at_limit_price():
|
||||
v = ScriptedVenue()
|
||||
v.set_directive("T2", Directive.REST_THEN_FILL, fill_delay_ms=10.0)
|
||||
v.submit(_intent("T2", limit_price=99.25))
|
||||
assert v.reconcile() == [] # not due yet
|
||||
time.sleep(0.02)
|
||||
fills = v.reconcile()
|
||||
assert [e.kind for e in fills] == [KernelEventKind.FULL_FILL]
|
||||
assert fills[0].price == 99.25 # maker fills at the limit
|
||||
assert fills[0].filled_size == 1.0
|
||||
assert v.reconcile() == [] # released exactly once
|
||||
|
||||
|
||||
def test_post_only_reject():
|
||||
v = ScriptedVenue()
|
||||
v.set_directive("T3", Directive.POST_ONLY_REJECT)
|
||||
events = v.submit(_intent("T3"))
|
||||
assert [e.kind for e in events] == [KernelEventKind.ORDER_REJECT]
|
||||
assert v.open_orders() == []
|
||||
|
||||
|
||||
def test_fill_races_cancel():
|
||||
"""Cancel is rejected and the fill surfaces on the next reconcile —
|
||||
the late-WS-fill-beats-cancel race."""
|
||||
v = ScriptedVenue()
|
||||
v.set_directive("T4", Directive.FILL_RACES_CANCEL)
|
||||
v.submit(_intent("T4"))
|
||||
order = v.open_orders()[0]
|
||||
out = v.cancel(order)
|
||||
assert [e.kind for e in out] == [KernelEventKind.CANCEL_REJECT]
|
||||
fills = v.reconcile()
|
||||
assert [e.kind for e in fills] == [KernelEventKind.FULL_FILL]
|
||||
assert fills[0].trade_id == "T4"
|
||||
|
||||
|
||||
def test_cancel_reject_directive():
|
||||
v = ScriptedVenue()
|
||||
v.set_directive("T5", Directive.CANCEL_REJECT)
|
||||
v.submit(_intent("T5"))
|
||||
out = v.cancel(v.open_orders()[0])
|
||||
assert [e.kind for e in out] == [KernelEventKind.CANCEL_REJECT]
|
||||
assert v.reconcile() == [] # no phantom fill
|
||||
|
||||
|
||||
def test_prefix_lookup_covers_retries():
|
||||
v = ScriptedVenue()
|
||||
v.set_directive("T6", Directive.REST_THEN_EXPIRE)
|
||||
v.set_directive("T6-r1", Directive.IMMEDIATE_FILL)
|
||||
assert [e.kind for e in v.submit(_intent("T6"))] == [KernelEventKind.ORDER_ACK]
|
||||
kinds = [e.kind for e in v.submit(_intent("T6-r1"))]
|
||||
assert KernelEventKind.FULL_FILL in kinds # own directive wins
|
||||
kinds_m = [e.kind for e in v.submit(_intent("T6-m"))]
|
||||
assert kinds_m == [KernelEventKind.ORDER_ACK] # falls back to T6 prefix
|
||||
|
||||
|
||||
def test_no_directive_is_parent_default():
|
||||
v = ScriptedVenue()
|
||||
kinds = [e.kind for e in v.submit(_intent("T7"))]
|
||||
assert KernelEventKind.FULL_FILL in kinds
|
||||
|
||||
|
||||
def test_kernel_cancel_reaches_venue_with_right_order():
|
||||
"""Full kernel drive: ENTER (resting LIMIT) then CANCEL via
|
||||
process_intent — the CANCEL must reach ScriptedVenue.cancel with the
|
||||
venue_order_id of the resting quote and pop it."""
|
||||
from prod.clean_arch.dita_v2.launcher import build_launcher_bundle
|
||||
|
||||
venue = ScriptedVenue()
|
||||
venue.set_directive("T-CXL", Directive.REST_THEN_EXPIRE)
|
||||
bundle = build_launcher_bundle(venue_mode="MOCK", max_slots=1, venue=venue)
|
||||
kernel = bundle.kernel
|
||||
|
||||
kernel.process_intent(_intent("T-CXL"))
|
||||
assert venue.submits == ["T-CXL"]
|
||||
assert len(venue.open_orders()) == 1
|
||||
resting_oid = venue.open_orders()[0].venue_order_id
|
||||
|
||||
cancel = _intent("T-CXL", action=KernelCommandType.CANCEL,
|
||||
order_type="MARKET", limit_price=0.0)
|
||||
kernel.process_intent(cancel)
|
||||
assert venue.cancels == ["T-CXL"]
|
||||
assert venue.open_orders() == [] # CANCEL_ACK popped it
|
||||
assert resting_oid # mapping existed end-to-end
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(pytest.main([__file__, "-v"]))
|
||||
Reference in New Issue
Block a user