fix: reconcile KIS exchange rejections

This commit is contained in:
jordan
2026-07-28 13:29:43 +09:00
parent 24c42d1c92
commit d6c2e2d28a
5 changed files with 89 additions and 7 deletions
@@ -28,6 +28,7 @@ class _ExchangeState:
self.submit_attempts = 0
self.orders: list[dict[str, str]] = []
self.fill_orders = False
self.reject_orders = False
def submit(self, body: dict[str, str]) -> tuple[bool, dict[str, object]]:
self.submit_attempts += 1
@@ -41,6 +42,7 @@ class _ExchangeState:
"ord_gno_brno": "91258",
"odno": f"{self.submit_attempts:010d}",
"tot_ccld_qty": "0",
"rjct_qty": "0",
"avg_prvs": "0",
"cncl_yn": "N",
}
@@ -58,15 +60,22 @@ class _ExchangeState:
def daily_orders(self) -> dict[str, object]:
rows = []
for order in self.orders:
if self.reject_orders and order["rjct_qty"] == "0":
order["rjct_qty"] = order["ord_qty"]
order["rmn_qty"] = "0"
row = dict(order)
if self.fill_orders:
if self.fill_orders and order["rjct_qty"] == "0":
row["tot_ccld_qty"] = row["ord_qty"]
row["avg_prvs"] = row["ord_unpr"]
rows.append(row)
return {"rt_cd": "0", "output1": rows}
def balance(self) -> dict[str, object]:
quantity = sum(int(order["ord_qty"]) for order in self.orders) if self.fill_orders else 0
quantity = (
sum(int(order["ord_qty"]) for order in self.orders if order["rjct_qty"] == "0")
if self.fill_orders
else 0
)
rows = [{"pdno": SYMBOL, "hldg_qty": str(quantity)}] if quantity else []
return {"rt_cd": "0", "output1": rows}
@@ -204,3 +213,39 @@ def test_timeout_before_exchange_accept_retries_only_after_confirmed_absence(mon
finally:
server.shutdown()
server.server_close()
def test_exchange_reject_after_broker_ack_rolls_back_and_allows_one_retry():
state = _ExchangeState(first_attempt_reaches_exchange=True)
state.reject_orders = True
server = _serve(state)
try:
repo, _slots, intents, execution, slot_id = _wire(_broker(server))
execution.run_once()
rejected = repo.fetch_slot(slot_id)
assert rejected.status is SlotState.INACTIVE
assert rejected.broker_order_id is None
assert state.submit_attempts == 1
state.reject_orders = False
state.fill_orders = True
retry = intents.submit_buy(
BuyIntent(
intent_id="virtual-buy-after-reject",
portfolio_id=PORTFOLIO,
qty=2,
entry_price=238_500,
)
)
assert retry.status == "admitted"
execution.run_once()
holding = repo.fetch_slot(slot_id)
assert holding.status is SlotState.HOLDING
assert holding.qty == 2
assert state.submit_attempts == 2
assert len(state.orders) == 2
finally:
server.shutdown()
server.server_close()