exec(unified): L2 foundation — contract §2 + whether-maker Router §6, pure, 26 tests
First code of the Unified Execution Layer (SPEC_UNIFIED_EXEC_LAYER_20260714.md). Pure policy, stdlib+Decimal only, zero I/O, zero venue knowledge, zero importers elsewhere — adopting it breaks nothing (freeze-safe; operator unparked the build 2026-07-14). - contract.py: ExecutionRequest input surface (§2.1) + V-TYPES (Side, UrgencyClass, ProtectiveSpec, ExecutionAdvice), frozen, validated-at-construction, illegal states unrepresentable. 'an asset, a size, and a prayer'. - router.py: decide(request) -> RoutingDecision — total pure map of the §6 urgency ladder. Encodes A1 adjudication verdict in the architecture: Router=whether-maker, SmartPlacer=where-in-book via the wants_placement/pre_submit seam. Complementary. - _constants.py: policy magnitudes with provenance; PROVISIONAL ones flagged for L8/L10 calibration (never vibes, never a hardcoded cadence). - test_exec_unified.py: 26 behaviour + mutation-litmus tests. Verified RED under CATASTROPHIC->MAKER and ACQUIRE cross_on_expiry->True mutations. Not yet wired: PINK drive-loop port (§7), venue dialect (§11), telemetry (§12). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
136
prod/exec_unified/router.py
Normal file
136
prod/exec_unified/router.py
Normal file
@@ -0,0 +1,136 @@
|
||||
"""The whether-maker policy machine (spec §6 urgency ladder).
|
||||
|
||||
Adjudication verdict (spec §17-A1, ratified here in code): the Router and SmartPlacer
|
||||
are **complementary, not competitors**. The Router decides *whether* to rest as maker
|
||||
and how hard to work the order (reprice budget, TTL discipline, give-up rule). The
|
||||
SmartPlacer decides *where in the book* the maker quote sits — it plugs into the
|
||||
``pre_submit`` seam (``wants_placement`` below) and is free to return a replacement
|
||||
plan. Neither subsumes the other; this module is the Router half and knows nothing
|
||||
about order books, offsets, or venues.
|
||||
|
||||
PURE: no I/O, no clock, no venue, no ambient state. ``decide()`` is a total function of
|
||||
the request alone. Everything time/price-dependent is expressed as a *rule the drive
|
||||
loop enforces* (§7), not as a value read here — that is what keeps this layer
|
||||
parity-invisible and venue-side-portable (C1).
|
||||
|
||||
Provenance: prod/docs/SPEC_UNIFIED_EXEC_LAYER_20260714.md §4, §6, §17-A1.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
|
||||
from . import _constants as K
|
||||
from .contract import ExecutionRequest, UrgencyClass
|
||||
|
||||
|
||||
class ExecutionMethod(Enum):
|
||||
MAKER = "MAKER" # rest post-only (GTX); the only certified fill-improvement path (§4-16)
|
||||
TAKER = "TAKER" # cross the spread now (MARKET / marketable)
|
||||
|
||||
|
||||
class TtlDiscipline(Enum):
|
||||
IMMEDIATE = "immediate" # act now, no resting (CATASTROPHIC)
|
||||
BOUNDED_MS = "bounded_ms" # rest up to a fixed wall-clock bound, then cross (PROTECT)
|
||||
DEADLINE = "deadline" # rest until caller's deadline_ms, then cross (ROTATE)
|
||||
UNBOUNDED = "unbounded" # rest patiently; do NOT cross on expiry (ACQUIRE abandons)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RoutingDecision:
|
||||
"""What the Router decided — the plan the drive loop executes (§7).
|
||||
|
||||
Carries *rules*, not live values: ``max_ms`` is a bound the loop measures against
|
||||
its injected clock; the Router itself never reads a clock.
|
||||
"""
|
||||
|
||||
method: ExecutionMethod
|
||||
max_reprices: int # chase budget; 0 = place-once (no chase)
|
||||
ttl: TtlDiscipline
|
||||
cross_on_expiry: bool # on TTL/reprice exhaustion: cross (True) or abandon (False)
|
||||
wants_placement: bool # invite SmartPlacer to set the offset (pre_submit seam)
|
||||
ignore_advice: bool # advice is inadmissible (CATASTROPHIC only, by law)
|
||||
max_ms: int | None = None # wall-clock bound for BOUNDED_MS; else None
|
||||
giveup_regression_frac: Decimal | None = None # HARVEST: cross if regression eats this of unrealized
|
||||
rationale: str = ""
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.max_reprices < 0:
|
||||
raise ValueError("max_reprices cannot be negative")
|
||||
if (self.ttl is TtlDiscipline.BOUNDED_MS) != (self.max_ms is not None):
|
||||
raise ValueError("max_ms must be set iff ttl is BOUNDED_MS")
|
||||
|
||||
|
||||
def decide(request: ExecutionRequest) -> RoutingDecision:
|
||||
"""Map urgency → routing policy. Total, pure, deterministic (spec §6).
|
||||
|
||||
The five promises this enforces (spec §2.3): CATASTROPHIC is never delayed; WHAT is
|
||||
never changed (this function reads urgency, never mutates side/size/asset); advice is
|
||||
ignored for CATASTROPHIC by law.
|
||||
"""
|
||||
u = request.urgency
|
||||
|
||||
if u is UrgencyClass.CATASTROPHIC:
|
||||
# Taker MARKET immediately. No cleverness. Ever. Advice ignored by law (§6).
|
||||
return RoutingDecision(
|
||||
method=ExecutionMethod.TAKER,
|
||||
max_reprices=0,
|
||||
ttl=TtlDiscipline.IMMEDIATE,
|
||||
cross_on_expiry=True,
|
||||
wants_placement=False,
|
||||
ignore_advice=True,
|
||||
rationale="CATASTROPHIC: cross now, no resting, advice inadmissible",
|
||||
)
|
||||
|
||||
if u is UrgencyClass.PROTECT:
|
||||
# Maker at touch, one reprice, ≤2 s total, then cross (§6).
|
||||
return RoutingDecision(
|
||||
method=ExecutionMethod.MAKER,
|
||||
max_reprices=K.PROTECT_REPRICE_LIMIT,
|
||||
ttl=TtlDiscipline.BOUNDED_MS,
|
||||
max_ms=K.PROTECT_MAX_MS,
|
||||
cross_on_expiry=True,
|
||||
wants_placement=False, # at touch, not an offset model
|
||||
ignore_advice=False,
|
||||
rationale="PROTECT: maker@touch, 1 reprice, cross at 2s",
|
||||
)
|
||||
|
||||
if u is UrgencyClass.HARVEST:
|
||||
# Maker at target ± SmartPlacer offset; chase ≤ N; give up on regression → cross (§6).
|
||||
return RoutingDecision(
|
||||
method=ExecutionMethod.MAKER,
|
||||
max_reprices=K.HARVEST_MAX_CHASES,
|
||||
ttl=TtlDiscipline.UNBOUNDED, # bounded by chases + regression, not wall-clock
|
||||
cross_on_expiry=True, # give-up crosses (harvest still wants the fill)
|
||||
wants_placement=True,
|
||||
ignore_advice=False,
|
||||
giveup_regression_frac=K.HARVEST_GIVEUP_REGRESSION_FRAC,
|
||||
rationale="HARVEST: maker@target±offset, chase<=N, cross on regression give-up",
|
||||
)
|
||||
|
||||
if u is UrgencyClass.ROTATE:
|
||||
# Patient maker; TTL from caller's deadline_ms; cross at TTL (§6).
|
||||
return RoutingDecision(
|
||||
method=ExecutionMethod.MAKER,
|
||||
max_reprices=K.HARVEST_MAX_CHASES, # patient chasing within the deadline
|
||||
ttl=TtlDiscipline.DEADLINE,
|
||||
cross_on_expiry=True,
|
||||
wants_placement=True,
|
||||
ignore_advice=False,
|
||||
rationale="ROTATE: patient maker, cross at caller deadline",
|
||||
)
|
||||
|
||||
if u is UrgencyClass.ACQUIRE:
|
||||
# Patient maker inside spread; abandon, never chase (§4-1: a missed entry is free).
|
||||
return RoutingDecision(
|
||||
method=ExecutionMethod.MAKER,
|
||||
max_reprices=K.ACQUIRE_MAX_CHASES, # == 0: no chase
|
||||
ttl=TtlDiscipline.UNBOUNDED,
|
||||
cross_on_expiry=False, # ABANDON on expiry — do NOT cross
|
||||
wants_placement=True,
|
||||
ignore_advice=False,
|
||||
rationale="ACQUIRE: patient maker inside spread, abandon (never chase, never cross)",
|
||||
)
|
||||
|
||||
raise ValueError(f"unhandled urgency {u!r}") # unreachable given the enum is closed
|
||||
Reference in New Issue
Block a user