fix: KR session-aware exchange routing (#409) #411

Merged
jihoson merged 8 commits from feature/issue-409-kr-session-exchange-routing into main 2026-03-04 23:06:09 +09:00
Showing only changes of commit 296b89d95f - Show all commits

View File

@@ -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.