feat: resolve and persist actual order venue
This commit is contained in:
@@ -45,6 +45,10 @@ class OrderAck:
|
||||
accepted: bool
|
||||
broker_order_id: Optional[str] = None
|
||||
reason: Optional[str] = None
|
||||
# Actual venue used for submission. KIS resolves AUTO before the HTTP call;
|
||||
# execution persists this value with the broker order id so restart/cancel
|
||||
# never has to infer the original venue.
|
||||
venue: Optional[str] = None
|
||||
raw: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
|
||||
@@ -201,7 +201,11 @@ class ExecutionService:
|
||||
)
|
||||
)
|
||||
if ack.accepted and ack.broker_order_id:
|
||||
self._repo.mark_dispatched(slot.slot_id, ack.broker_order_id)
|
||||
self._repo.mark_dispatched(
|
||||
slot.slot_id,
|
||||
ack.broker_order_id,
|
||||
venue=ack.venue,
|
||||
)
|
||||
r.dispatched += 1
|
||||
if ack.reason and ack.reason.startswith("submit_outcome_unknown:"):
|
||||
_log.warning(
|
||||
@@ -643,6 +647,7 @@ class ExecutionService:
|
||||
fee=float(fs.fee),
|
||||
tax=float(fs.tax),
|
||||
executed_at=datetime.now(tz=timezone.utc),
|
||||
venue=slot.venue,
|
||||
)
|
||||
self._ledger_outbox.enqueue(trade)
|
||||
r.ledger_enqueued += 1
|
||||
|
||||
@@ -75,7 +75,9 @@ class BuyIntent:
|
||||
# slippage_pct: effective limit = entry_price*(1+pct/100) buy / *(1-pct/100) sell.
|
||||
timeout_sec: Optional[int] = None
|
||||
slippage_pct: Optional[float] = None
|
||||
venue: str = "KRX"
|
||||
# Strategy wire default. AUTO is resolved at the broker boundary so
|
||||
# strategies remain session-agnostic while explicit KRX/NXT/SOR is kept.
|
||||
venue: str = "AUTO"
|
||||
extra: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@@ -94,7 +96,7 @@ class SellIntent:
|
||||
# dcy-022 / REQ-068: execution policy (optional, backward-compat).
|
||||
timeout_sec: Optional[int] = None
|
||||
slippage_pct: Optional[float] = None
|
||||
venue: str = "KRX"
|
||||
venue: str = "AUTO"
|
||||
extra: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@@ -211,7 +213,7 @@ class IntentService:
|
||||
dcy-036 / REQ-114: entry gate — if entry_allowed_fn returns False,
|
||||
BuyIntent is rejected before any slot lookup."""
|
||||
|
||||
if intent.venue not in {"KRX", "NXT", "SOR"}:
|
||||
if intent.venue not in {"AUTO", "KRX", "NXT", "SOR"}:
|
||||
return IntentDecision(intent.intent_id, "rejected", None, "invalid_venue")
|
||||
|
||||
# dcy-036 / REQ-114: day-start entry gate (fail-closed).
|
||||
@@ -308,7 +310,7 @@ class IntentService:
|
||||
return IntentDecision(intent.intent_id, "rejected", None, "already_active")
|
||||
|
||||
def _admit_sell(self, intent: SellIntent) -> IntentDecision:
|
||||
if intent.venue not in {"KRX", "NXT", "SOR"}:
|
||||
if intent.venue not in {"AUTO", "KRX", "NXT", "SOR"}:
|
||||
return IntentDecision(intent.intent_id, "rejected", None, "invalid_venue")
|
||||
|
||||
slot = self._repo.fetch_slot(intent.slot_id)
|
||||
|
||||
@@ -57,6 +57,9 @@ class LedgerTrade:
|
||||
fee: float = 0.0
|
||||
tax: float = 0.0
|
||||
executed_at: Optional[datetime] = None
|
||||
# Actual order venue persisted in the Core outbox. Portfolio Hub remains
|
||||
# unchanged until its API contract explicitly accepts this additive field.
|
||||
venue: str = "KRX"
|
||||
|
||||
@property
|
||||
def correlation_id(self) -> str:
|
||||
|
||||
@@ -117,7 +117,7 @@ def make_intent_rpc_handler(
|
||||
# dcy-022 / REQ-068: execution policy (optional, backward-compat).
|
||||
timeout_sec=_opt_int(body.get("timeout_sec")),
|
||||
slippage_pct=_opt_float(body.get("slippage_pct")),
|
||||
venue=_opt_str(body.get("venue")) or "KRX",
|
||||
venue=_opt_str(body.get("venue")) or "AUTO",
|
||||
)
|
||||
d = intent_service.submit_buy(buy)
|
||||
elif intent_type == "sell":
|
||||
@@ -133,7 +133,7 @@ def make_intent_rpc_handler(
|
||||
# dcy-022 / REQ-068: execution policy (optional, backward-compat).
|
||||
timeout_sec=_opt_int(body.get("timeout_sec")),
|
||||
slippage_pct=_opt_float(body.get("slippage_pct")),
|
||||
venue=_opt_str(body.get("venue")) or "KRX",
|
||||
venue=_opt_str(body.get("venue")) or "AUTO",
|
||||
)
|
||||
d = intent_service.submit_sell(sell)
|
||||
else:
|
||||
@@ -627,4 +627,3 @@ def _parse_date(v) -> date_cls:
|
||||
|
||||
def _today() -> date_cls:
|
||||
return datetime.now(tz=timezone.utc).date()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user