feat: propagate intent venue through execution

This commit is contained in:
jordan
2026-07-29 16:55:20 +09:00
parent 7084304c9f
commit 479cb39a7e
22 changed files with 314 additions and 19 deletions
+17 -12
View File
@@ -197,6 +197,7 @@ class ExecutionService:
qty=qty,
limit_price=limit,
order_type="00" if limit is not None else "01",
venue=slot.venue,
)
)
if ack.accepted and ack.broker_order_id:
@@ -548,12 +549,14 @@ class ExecutionService:
return
qty = int(slot.qty or 0)
try:
accepted = self._broker.cancel_order(
slot.broker_order_id,
side=side,
symbol=slot.symbol or "",
qty=qty,
)
cancel_kwargs = {
"side": side,
"symbol": slot.symbol or "",
"qty": qty,
}
if slot.venue != "KRX":
cancel_kwargs["venue"] = slot.venue
accepted = self._broker.cancel_order(slot.broker_order_id, **cancel_kwargs)
r.timeout_cancelled += 1
_log.warning(
"timeout cancel sent: slot=%s status=%s broker_order_id=%s "
@@ -665,12 +668,14 @@ class ExecutionService:
side = "buy" if slot.status is SlotState.PENDING_BUY else "sell"
qty = int(slot.qty or 0)
try:
self._broker.cancel_order(
slot.broker_order_id,
side=side,
symbol=slot.symbol or "",
qty=qty,
)
cancel_kwargs = {
"side": side,
"symbol": slot.symbol or "",
"qty": qty,
}
if slot.venue != "KRX":
cancel_kwargs["venue"] = slot.venue
self._broker.cancel_order(slot.broker_order_id, **cancel_kwargs)
except Exception: # noqa: BLE001 - best-effort
_log.warning(
"operator cancel failed: slot=%s broker_order_id=%s",
+12
View File
@@ -75,6 +75,7 @@ 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"
extra: dict[str, Any] = field(default_factory=dict)
@@ -93,6 +94,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"
extra: dict[str, Any] = field(default_factory=dict)
@@ -152,6 +154,7 @@ class IntentService:
"entry_price": intent.entry_price,
"strategy_id": intent.strategy_id,
"sell_strategy_id": intent.sell_strategy_id,
"venue": intent.venue,
}
prior = self._dedup(intent.intent_id, "buy", payload)
if prior is not None:
@@ -169,6 +172,7 @@ class IntentService:
"reason": intent.reason,
"sell_strategy_id": intent.sell_strategy_id,
"qty": intent.qty,
"venue": intent.venue,
}
prior = self._dedup(intent.intent_id, "sell", payload)
if prior is not None:
@@ -207,6 +211,9 @@ 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"}:
return IntentDecision(intent.intent_id, "rejected", None, "invalid_venue")
# dcy-036 / REQ-114: day-start entry gate (fail-closed).
# None or True → pass; False → reject new entry.
# SellIntent is NOT checked (청산 경로는 차단하지 않음 AC-5).
@@ -292,6 +299,7 @@ class IntentService:
take_profit_price=intent.take_profit_price,
timeout_sec=effective_timeout,
slippage_pct=intent.slippage_pct,
venue=intent.venue,
extra={"intent_id": intent.intent_id, "symbol": symbol},
)
except SlotStateMismatchError:
@@ -300,6 +308,9 @@ 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"}:
return IntentDecision(intent.intent_id, "rejected", None, "invalid_venue")
slot = self._repo.fetch_slot(intent.slot_id)
if slot is None:
return IntentDecision(intent.intent_id, "rejected", None, "slot_not_found")
@@ -342,6 +353,7 @@ class IntentService:
qty=intent.qty,
timeout_sec=effective_timeout,
slippage_pct=intent.slippage_pct,
venue=intent.venue,
extra={"intent_id": intent.intent_id},
)
except SlotStateMismatchError:
+2 -1
View File
@@ -117,6 +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",
)
d = intent_service.submit_buy(buy)
elif intent_type == "sell":
@@ -132,6 +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",
)
d = intent_service.submit_sell(sell)
else:
@@ -626,4 +628,3 @@ def _parse_date(v) -> date_cls:
def _today() -> date_cls:
return datetime.now(tz=timezone.utc).date()