blackout: persist session_id across queued intent lifecycle (#375)
This commit is contained in:
@@ -23,6 +23,7 @@ class BlackoutWindow:
|
|||||||
class QueuedOrderIntent:
|
class QueuedOrderIntent:
|
||||||
market_code: str
|
market_code: str
|
||||||
exchange_code: str
|
exchange_code: str
|
||||||
|
session_id: str
|
||||||
stock_code: str
|
stock_code: str
|
||||||
order_type: str
|
order_type: str
|
||||||
quantity: int
|
quantity: int
|
||||||
|
|||||||
11
src/main.py
11
src/main.py
@@ -1004,6 +1004,7 @@ async def build_overseas_symbol_universe(
|
|||||||
def _build_queued_order_intent(
|
def _build_queued_order_intent(
|
||||||
*,
|
*,
|
||||||
market: MarketInfo,
|
market: MarketInfo,
|
||||||
|
session_id: str,
|
||||||
stock_code: str,
|
stock_code: str,
|
||||||
order_type: str,
|
order_type: str,
|
||||||
quantity: int,
|
quantity: int,
|
||||||
@@ -1013,6 +1014,7 @@ def _build_queued_order_intent(
|
|||||||
return QueuedOrderIntent(
|
return QueuedOrderIntent(
|
||||||
market_code=market.code,
|
market_code=market.code,
|
||||||
exchange_code=market.exchange_code,
|
exchange_code=market.exchange_code,
|
||||||
|
session_id=session_id,
|
||||||
stock_code=stock_code,
|
stock_code=stock_code,
|
||||||
order_type=order_type,
|
order_type=order_type,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
@@ -1025,6 +1027,7 @@ def _build_queued_order_intent(
|
|||||||
def _maybe_queue_order_intent(
|
def _maybe_queue_order_intent(
|
||||||
*,
|
*,
|
||||||
market: MarketInfo,
|
market: MarketInfo,
|
||||||
|
session_id: str,
|
||||||
stock_code: str,
|
stock_code: str,
|
||||||
order_type: str,
|
order_type: str,
|
||||||
quantity: int,
|
quantity: int,
|
||||||
@@ -1038,6 +1041,7 @@ def _maybe_queue_order_intent(
|
|||||||
queued = BLACKOUT_ORDER_MANAGER.enqueue(
|
queued = BLACKOUT_ORDER_MANAGER.enqueue(
|
||||||
_build_queued_order_intent(
|
_build_queued_order_intent(
|
||||||
market=market,
|
market=market,
|
||||||
|
session_id=session_id,
|
||||||
stock_code=stock_code,
|
stock_code=stock_code,
|
||||||
order_type=order_type,
|
order_type=order_type,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
@@ -1208,7 +1212,6 @@ async def process_blackout_recovery_orders(
|
|||||||
|
|
||||||
accepted = result.get("rt_cd", "0") == "0"
|
accepted = result.get("rt_cd", "0") == "0"
|
||||||
if accepted:
|
if accepted:
|
||||||
runtime_session_id = get_session_info(market).session_id
|
|
||||||
log_trade(
|
log_trade(
|
||||||
conn=db_conn,
|
conn=db_conn,
|
||||||
stock_code=intent.stock_code,
|
stock_code=intent.stock_code,
|
||||||
@@ -1220,7 +1223,7 @@ async def process_blackout_recovery_orders(
|
|||||||
pnl=0.0,
|
pnl=0.0,
|
||||||
market=market.code,
|
market=market.code,
|
||||||
exchange_code=market.exchange_code,
|
exchange_code=market.exchange_code,
|
||||||
session_id=runtime_session_id,
|
session_id=getattr(intent, "session_id", get_session_info(market).session_id),
|
||||||
)
|
)
|
||||||
logger.info(
|
logger.info(
|
||||||
"Recovered queued order executed: %s %s (%s) qty=%d price=%.4f source=%s",
|
"Recovered queued order executed: %s %s (%s) qty=%d price=%.4f source=%s",
|
||||||
@@ -2057,6 +2060,7 @@ async def trading_cycle(
|
|||||||
return
|
return
|
||||||
if _maybe_queue_order_intent(
|
if _maybe_queue_order_intent(
|
||||||
market=market,
|
market=market,
|
||||||
|
session_id=runtime_session_id,
|
||||||
stock_code=stock_code,
|
stock_code=stock_code,
|
||||||
order_type=decision.action,
|
order_type=decision.action,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
@@ -2104,6 +2108,7 @@ async def trading_cycle(
|
|||||||
return
|
return
|
||||||
if _maybe_queue_order_intent(
|
if _maybe_queue_order_intent(
|
||||||
market=market,
|
market=market,
|
||||||
|
session_id=runtime_session_id,
|
||||||
stock_code=stock_code,
|
stock_code=stock_code,
|
||||||
order_type=decision.action,
|
order_type=decision.action,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
@@ -3264,6 +3269,7 @@ async def run_daily_session(
|
|||||||
continue
|
continue
|
||||||
if _maybe_queue_order_intent(
|
if _maybe_queue_order_intent(
|
||||||
market=market,
|
market=market,
|
||||||
|
session_id=runtime_session_id,
|
||||||
stock_code=stock_code,
|
stock_code=stock_code,
|
||||||
order_type=decision.action,
|
order_type=decision.action,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
@@ -3301,6 +3307,7 @@ async def run_daily_session(
|
|||||||
continue
|
continue
|
||||||
if _maybe_queue_order_intent(
|
if _maybe_queue_order_intent(
|
||||||
market=market,
|
market=market,
|
||||||
|
session_id=runtime_session_id,
|
||||||
stock_code=stock_code,
|
stock_code=stock_code,
|
||||||
order_type=decision.action,
|
order_type=decision.action,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ def test_recovery_batch_only_after_blackout_exit() -> None:
|
|||||||
intent = QueuedOrderIntent(
|
intent = QueuedOrderIntent(
|
||||||
market_code="KR",
|
market_code="KR",
|
||||||
exchange_code="KRX",
|
exchange_code="KRX",
|
||||||
|
session_id="KRX_REG",
|
||||||
stock_code="005930",
|
stock_code="005930",
|
||||||
order_type="BUY",
|
order_type="BUY",
|
||||||
quantity=1,
|
quantity=1,
|
||||||
@@ -64,6 +65,7 @@ def test_requeued_intent_is_processed_next_non_blackout_cycle() -> None:
|
|||||||
intent = QueuedOrderIntent(
|
intent = QueuedOrderIntent(
|
||||||
market_code="KR",
|
market_code="KR",
|
||||||
exchange_code="KRX",
|
exchange_code="KRX",
|
||||||
|
session_id="KRX_REG",
|
||||||
stock_code="005930",
|
stock_code="005930",
|
||||||
order_type="BUY",
|
order_type="BUY",
|
||||||
quantity=1,
|
quantity=1,
|
||||||
@@ -90,6 +92,7 @@ def test_queue_overflow_drops_oldest_and_keeps_latest() -> None:
|
|||||||
first = QueuedOrderIntent(
|
first = QueuedOrderIntent(
|
||||||
market_code="KR",
|
market_code="KR",
|
||||||
exchange_code="KRX",
|
exchange_code="KRX",
|
||||||
|
session_id="KRX_REG",
|
||||||
stock_code="000001",
|
stock_code="000001",
|
||||||
order_type="BUY",
|
order_type="BUY",
|
||||||
quantity=1,
|
quantity=1,
|
||||||
@@ -100,6 +103,7 @@ def test_queue_overflow_drops_oldest_and_keeps_latest() -> None:
|
|||||||
second = QueuedOrderIntent(
|
second = QueuedOrderIntent(
|
||||||
market_code="KR",
|
market_code="KR",
|
||||||
exchange_code="KRX",
|
exchange_code="KRX",
|
||||||
|
session_id="KRX_REG",
|
||||||
stock_code="000002",
|
stock_code="000002",
|
||||||
order_type="BUY",
|
order_type="BUY",
|
||||||
quantity=1,
|
quantity=1,
|
||||||
@@ -110,6 +114,7 @@ def test_queue_overflow_drops_oldest_and_keeps_latest() -> None:
|
|||||||
third = QueuedOrderIntent(
|
third = QueuedOrderIntent(
|
||||||
market_code="KR",
|
market_code="KR",
|
||||||
exchange_code="KRX",
|
exchange_code="KRX",
|
||||||
|
session_id="KRX_REG",
|
||||||
stock_code="000003",
|
stock_code="000003",
|
||||||
order_type="SELL",
|
order_type="SELL",
|
||||||
quantity=2,
|
quantity=2,
|
||||||
|
|||||||
@@ -6543,6 +6543,7 @@ def test_blackout_queue_overflow_keeps_latest_intent() -> None:
|
|||||||
with patch("src.main.BLACKOUT_ORDER_MANAGER", manager):
|
with patch("src.main.BLACKOUT_ORDER_MANAGER", manager):
|
||||||
assert _maybe_queue_order_intent(
|
assert _maybe_queue_order_intent(
|
||||||
market=market,
|
market=market,
|
||||||
|
session_id="KRX_REG",
|
||||||
stock_code="005930",
|
stock_code="005930",
|
||||||
order_type="BUY",
|
order_type="BUY",
|
||||||
quantity=1,
|
quantity=1,
|
||||||
@@ -6551,6 +6552,7 @@ def test_blackout_queue_overflow_keeps_latest_intent() -> None:
|
|||||||
)
|
)
|
||||||
assert _maybe_queue_order_intent(
|
assert _maybe_queue_order_intent(
|
||||||
market=market,
|
market=market,
|
||||||
|
session_id="KRX_REG",
|
||||||
stock_code="000660",
|
stock_code="000660",
|
||||||
order_type="BUY",
|
order_type="BUY",
|
||||||
quantity=2,
|
quantity=2,
|
||||||
@@ -6564,6 +6566,7 @@ def test_blackout_queue_overflow_keeps_latest_intent() -> None:
|
|||||||
batch = manager.pop_recovery_batch()
|
batch = manager.pop_recovery_batch()
|
||||||
assert len(batch) == 1
|
assert len(batch) == 1
|
||||||
assert batch[0].stock_code == "000660"
|
assert batch[0].stock_code == "000660"
|
||||||
|
assert batch[0].session_id == "KRX_REG"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -6587,6 +6590,7 @@ async def test_process_blackout_recovery_executes_valid_intents() -> None:
|
|||||||
intent.quantity = 1
|
intent.quantity = 1
|
||||||
intent.price = 100.0
|
intent.price = 100.0
|
||||||
intent.source = "test"
|
intent.source = "test"
|
||||||
|
intent.session_id = "NXT_AFTER"
|
||||||
intent.attempts = 0
|
intent.attempts = 0
|
||||||
|
|
||||||
blackout_manager = MagicMock()
|
blackout_manager = MagicMock()
|
||||||
@@ -6617,7 +6621,7 @@ async def test_process_blackout_recovery_executes_valid_intents() -> None:
|
|||||||
assert row is not None
|
assert row is not None
|
||||||
assert row[0] == "BUY"
|
assert row[0] == "BUY"
|
||||||
assert row[1] == 1
|
assert row[1] == 1
|
||||||
assert row[2] == "KRX_REG"
|
assert row[2] == "NXT_AFTER"
|
||||||
assert row[3].startswith("[blackout-recovery]")
|
assert row[3].startswith("[blackout-recovery]")
|
||||||
|
|
||||||
|
|
||||||
@@ -6642,6 +6646,7 @@ async def test_process_blackout_recovery_drops_policy_rejected_intent() -> None:
|
|||||||
intent.quantity = 1
|
intent.quantity = 1
|
||||||
intent.price = 100.0
|
intent.price = 100.0
|
||||||
intent.source = "test"
|
intent.source = "test"
|
||||||
|
intent.session_id = "KRX_REG"
|
||||||
intent.attempts = 0
|
intent.attempts = 0
|
||||||
|
|
||||||
blackout_manager = MagicMock()
|
blackout_manager = MagicMock()
|
||||||
@@ -6691,6 +6696,7 @@ async def test_process_blackout_recovery_drops_intent_on_excessive_price_drift()
|
|||||||
intent.quantity = 1
|
intent.quantity = 1
|
||||||
intent.price = 100.0
|
intent.price = 100.0
|
||||||
intent.source = "test"
|
intent.source = "test"
|
||||||
|
intent.session_id = "US_PRE"
|
||||||
intent.attempts = 0
|
intent.attempts = 0
|
||||||
|
|
||||||
blackout_manager = MagicMock()
|
blackout_manager = MagicMock()
|
||||||
@@ -6741,6 +6747,7 @@ async def test_process_blackout_recovery_drops_overseas_intent_on_excessive_pric
|
|||||||
intent.quantity = 1
|
intent.quantity = 1
|
||||||
intent.price = 100.0
|
intent.price = 100.0
|
||||||
intent.source = "test"
|
intent.source = "test"
|
||||||
|
intent.session_id = "KRX_REG"
|
||||||
intent.attempts = 0
|
intent.attempts = 0
|
||||||
|
|
||||||
blackout_manager = MagicMock()
|
blackout_manager = MagicMock()
|
||||||
@@ -6790,6 +6797,7 @@ async def test_process_blackout_recovery_requeues_intent_when_price_lookup_fails
|
|||||||
intent.quantity = 1
|
intent.quantity = 1
|
||||||
intent.price = 100.0
|
intent.price = 100.0
|
||||||
intent.source = "test"
|
intent.source = "test"
|
||||||
|
intent.session_id = "KRX_REG"
|
||||||
intent.attempts = 0
|
intent.attempts = 0
|
||||||
|
|
||||||
blackout_manager = MagicMock()
|
blackout_manager = MagicMock()
|
||||||
|
|||||||
Reference in New Issue
Block a user