diff --git a/docs/plans/2026-03-04-issue-409-kr-session-exchange-routing-design.md b/docs/plans/2026-03-04-issue-409-kr-session-exchange-routing-design.md new file mode 100644 index 0000000..f8c9b94 --- /dev/null +++ b/docs/plans/2026-03-04-issue-409-kr-session-exchange-routing-design.md @@ -0,0 +1,103 @@ +# Issue #409 Design - KR Session-Aware Exchange Routing + +## Context +- Issue: #409 (bug: KR 세션별 거래소 미분리 - 스크리닝/주문/이중상장 우선순위 미처리) +- Related runtime observation targets: #318, #325 +- Date: 2026-03-04 +- Confirmed approach: Option 2 (routing module introduction) + +## Goals +1. Ensure domestic screening uses session-specific exchange market code. +2. Ensure domestic order submission explicitly sets exchange routing code. +3. Add dual-listing routing priority logic (spread/liquidity aware) with safe fallback. +4. Keep existing behavior stable for non-KR flows and existing risk/order policy guards. +5. Enable runtime observability for #409 while monitoring #318/#325 in parallel. + +## Non-Goals +- Replacing current session classification model. +- Introducing new market sessions or changing session boundaries. +- Refactoring overseas order flow. + +## Architecture +### New Component +- Add `KRExchangeRouter` (new module, e.g. `src/broker/kr_exchange_router.py`). +- Responsibility split: + - `classify_session_id`: session classification only. + - `KRExchangeRouter`: final domestic exchange selection (`KRX`/`NXT`) for ranking and order. + - `KISBroker`: inject resolved routing values into request params/body. + +### Integration Points +- `KISBroker.fetch_market_rankings` + - Session-aware market division code: + - `KRX_REG` -> `J` + - `NXT_PRE`, `NXT_AFTER` -> `NX` +- `KISBroker.send_order` + - Explicit `EXCG_ID_DVSN_CD` is always set. +- `SmartVolatilityScanner._scan_domestic` + - Ensure domestic ranking API path resolves exchange consistently with current session. + +## Data Flow +1. Scanner path: + - Determine `session_id`. + - `resolve_for_ranking(session_id)`. + - Inject `J` or `NX` into ranking API params. +2. Order path: + - Pass `session_id` into order path. + - `resolve_for_order(stock_code, session_id)`. + - Single listing: session default exchange. + - Dual listing: select by spread/liquidity heuristic when data is available. + - Data unavailable/error: fallback to session default. + - Send order with explicit `EXCG_ID_DVSN_CD`. +3. Observability: + - Log `session_id`, `resolved_exchange`, `routing_reason`. + +## Dual-Listing Routing Priority +- Preferred decision source: spread/liquidity comparison. +- Deterministic fallback: session-default exchange. +- Proposed reasons in logs: + - `session_default` + - `dual_listing_spread` + - `dual_listing_liquidity` + - `fallback_data_unavailable` + +## Error Handling +- Router does not block order path when auxiliary data is unavailable. +- Fail-open strategy for routing selection (fallback to session default) while preserving existing API/network error semantics. +- `send_order` exchange field omission is forbidden by design after this change. + +## Testing Strategy +### Unit +- Router mapping by session (`KRX_REG`, `NXT_PRE`, `NXT_AFTER`). +- Dual-listing routing priority and fallback. +- Broker order body includes `EXCG_ID_DVSN_CD`. +- Ranking params use session-aware market code. + +### Integration/Regression +- `smart_scanner` domestic calls align with session exchange. +- Existing order policy tests remain green. +- Re-run regression sets covering #318/#325 related paths. + +### Runtime Observation (24h) +- Restart program from working branch build. +- Run runtime monitor for up to 24h. +- Verify and track: + - #409: session-aware routing evidence in logs. + - #318: ATR dynamic stop evidence. + - #325: ATR/pred_down_prob injection evidence. +- If anomalies are detected during monitoring, create separate issue tickets with evidence and links. + +## Acceptance Criteria +1. No domestic ranking call uses hardcoded KRX-only behavior across NXT sessions. +2. No domestic order is sent without `EXCG_ID_DVSN_CD`. +3. Dual-listing path has explicit priority logic and deterministic fallback. +4. Tests pass for new and affected paths. +5. Runtime monitor evidence is collected for #409, #318, #325; anomalies are ticketed. + +## Risks and Mitigations +- Risk: Increased routing complexity introduces regressions. + - Mitigation: isolate router, high-coverage unit tests, preserve existing interfaces where possible. +- Risk: Runtime events for #318/#325 may not naturally occur in 24h. + - Mitigation: mark as `NOT_OBSERVED` and keep issue state based on evidence policy; do not force-close without proof. + +## Planned Next Step +- Invoke `writing-plans` workflow and produce implementation plan before code changes.