From b28388077413219b2e01ceafdbb410d54af509bf Mon Sep 17 00:00:00 2001 From: agentson Date: Wed, 4 Mar 2026 03:02:26 +0900 Subject: [PATCH 1/2] fix: handle KR order rejection via rt_cd check (#398) --- src/main.py | 18 ++++++++++++++++++ tests/test_main.py | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/main.py b/src/main.py index a4ba69a..4701c17 100644 --- a/src/main.py +++ b/src/main.py @@ -2084,6 +2084,15 @@ async def trading_cycle( quantity=quantity, price=order_price, ) + if result.get("rt_cd", "0") != "0": + order_succeeded = False + msg1 = result.get("msg1") or "" + logger.warning( + "KR order not accepted for %s: rt_cd=%s msg=%s", + stock_code, + result.get("rt_cd"), + msg1, + ) else: # For overseas orders, always use limit orders (지정가): # - KIS market orders (ORD_DVSN=01) calculate quantity based on upper limit @@ -3293,6 +3302,15 @@ async def run_daily_session( quantity=quantity, price=order_price, ) + if result.get("rt_cd", "0") != "0": + order_succeeded = False + daily_msg1 = result.get("msg1") or "" + logger.warning( + "KR order not accepted for %s: rt_cd=%s msg=%s", + stock_code, + result.get("rt_cd"), + daily_msg1, + ) else: # KIS VTS only accepts limit orders; use 0.5% premium for BUY if decision.action == "BUY": diff --git a/tests/test_main.py b/tests/test_main.py index 47c2ad3..2c98ae8 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -913,6 +913,46 @@ class TestTradingCycleTelegramIntegration: # Verify notification was attempted mock_telegram.notify_trade_execution.assert_called_once() + @pytest.mark.asyncio + async def test_kr_rejected_order_does_not_notify_or_log_trade( + self, + mock_broker: MagicMock, + mock_overseas_broker: MagicMock, + mock_scenario_engine: MagicMock, + mock_playbook: DayPlaybook, + mock_risk: MagicMock, + mock_db: MagicMock, + mock_decision_logger: MagicMock, + mock_context_store: MagicMock, + mock_criticality_assessor: MagicMock, + mock_telegram: MagicMock, + mock_market: MagicMock, + ) -> None: + """KR orders rejected by KIS should not trigger success side effects.""" + mock_broker.send_order = AsyncMock( + return_value={"rt_cd": "1", "msg1": "장운영시간이 아닙니다."} + ) + + with patch("src.main.log_trade") as mock_log_trade: + await trading_cycle( + broker=mock_broker, + overseas_broker=mock_overseas_broker, + scenario_engine=mock_scenario_engine, + playbook=mock_playbook, + risk=mock_risk, + db_conn=mock_db, + decision_logger=mock_decision_logger, + context_store=mock_context_store, + criticality_assessor=mock_criticality_assessor, + telegram=mock_telegram, + market=mock_market, + stock_code="005930", + scan_candidates={}, + ) + + mock_telegram.notify_trade_execution.assert_not_called() + mock_log_trade.assert_not_called() + @pytest.mark.asyncio async def test_fat_finger_notification_sent( self, From 90cd7c0504976d8741f4130f158d967505bfde27 Mon Sep 17 00:00:00 2001 From: agentson Date: Wed, 4 Mar 2026 03:03:53 +0900 Subject: [PATCH 2/2] chore: retrigger CI for PR #405