KRX Sidecar + Circuit Breaker Automation Runbook (KOSPI/KOSDAQ)
Date: 2026-02-25 (KST)
TL;DR
For KR live trading, Sidecar and Circuit Breaker (CB) are not "market news"โthey are execution-state transitions.
If your bot keeps routing as if nothing changed, you get the classic failure combo:
- phantom liquidity assumptions,
- reject/requeue loops,
- and expensive post-reopen slippage.
This runbook turns KRX stabilization rules into implementable trading-engine behavior.
1) Rule facts you should encode (not memorize)
1.1 KOSPI Sidecar (program order effectiveness suspension)
From ์ ๊ฐ์ฆ๊ถ์์ฅ ์ ๋ฌด๊ท์ ์ 16์กฐ:
- Trigger basis: most-liquid KOSPI200 futures contract (from prior day volume)
- Trigger condition: futures price moves ยฑ5% vs derivatives reference price, sustained 1 minute
- Action: 5 minutes suspension of program buy or sell quote effectiveness
- Not applied: within last 40 minutes before market close
- Applied only once per day: first qualifying event only
- Trigger counting starts after open + 5 minutes
Release:
- after 5 minutes, or
- at T-40m boundary, or
- when market resumes if a market-wide halt happened during sidecar window
1.2 KOSDAQ Sidecar
From ์ฝ์ค๋ฅ์์ฅ ์ ๋ฌด๊ท์ ์ 13์กฐ:
- Joint trigger (simultaneous, 1 minute):
- KOSDAQ150 futures contract moves ยฑ6%, and
- KOSDAQ150 index moves ยฑ3%
- Action: 5 minutes suspension of program buy/sell quote effectiveness
- Same practical constraints:
- first trigger only per day,
- trigger evaluation after open + 5 minutes,
- no new trigger inside last 40 minutes
1.3 Market-wide Circuit Breaker (CB)
From ์ ๊ฐ์ฆ๊ถ์์ฅ ์ ๋ฌด๊ท์ ์ 25์กฐ / ์ฝ์ค๋ฅ์์ฅ ์ ๋ฌด๊ท์ ์ 26์กฐ:
- Stage 1: index down >= 8% for 1 minute -> 20-minute market halt
- Stage 2: after Stage 1 reopen, index down >= 15% for 1 minute -> 20-minute halt
- Stage 3: after Stage 2 reopen, index down >= 20% for 1 minute -> trading day ends
From each market ์ํ์ธ์น(์ ๊ฐ ์ 39์กฐ, ์ฝ์ค๋ฅ ์ 31์กฐ):
- Stage 2 requires additional condition: at least 1% further drop vs Stage 1 halt point
- Stage 3 requires additional condition: at least 1% further drop vs Stage 2 halt point
- Stage 1/2 are only first occurrence each day
- Stage 1/2 not applied after T-40m, but Stage 3 still applies
- Stage 1 one-minute persistence counting starts after open + 1 minute
2) Execution architecture: split your state planes
Use separate but interacting state planes:
- Market-wide plane
NORMAL | CB_STAGE1_HALT | CB_STAGE2_HALT | CB_STAGE3_CLOSED
- Program-trading control plane
NONE | SIDECAR_BUY_BLOCK | SIDECAR_SELL_BLOCK
- Symbol execution plane
NORMAL | HALT_REOPEN_AUCTION | POST_HALT_RECOVERY
Do not reduce everything to one enum. You need composability for edge cases.
3) Router policy table (practical defaults)
CB_STAGE1/2_HALT
- cancel new child scheduling (except risk-reduction logic if allowed)
- freeze urgency escalators
- block stale quote refresh loops
Reopen phase (first single-price uncross after halt)
- do not send full-size catch-up child at first print
- start with 25-40% baseline clip
- enforce stricter worst-price guard (e.g., baseline -30% tolerance)
POST_HALT_RECOVERY (first 5-15 min)
- ramp 25% -> 50% -> 75% -> 100% if spread/impact normalizes
- require markout stabilization to advance each step
Sidecar active (buy/sell program block)
- disable blocked-side program logic for 5 minutes
- continue non-program paths only if compliant with your internal policy
- keep participation caps lower than normal during and right after release
4) Event ingestion design (donโt trust one source)
Use at least two independent channels:
- Primary: exchange/member notice stream (or broker market-status feed)
- Secondary: deterministic local detector from index/futures ticks + rule thresholds
Why:
- Notice stream is authoritative but can be delayed.
- Local detector is fast but may be wrong under feed gaps.
Recommended behavior:
- authoritative notice = state commit
- local detector = early warning + temporary guardrails
5) Minimal state machine (pseudo)
type MarketState = 'NORMAL' | 'CB1_HALT' | 'CB2_HALT' | 'CB3_CLOSED'
type SidecarState = 'NONE' | 'BUY_BLOCK' | 'SELL_BLOCK'
onEvent(e):
if e.type == 'CB_STAGE1_START': market = 'CB1_HALT'
if e.type == 'CB_STAGE2_START': market = 'CB2_HALT'
if e.type == 'CB_STAGE3_START': market = 'CB3_CLOSED'
if e.type == 'CB_REOPEN':
market = 'NORMAL'
enterRecoveryWindow(symbol='*', minutes=10)
if e.type == 'SIDECAR_BUY_START': sidecar='BUY_BLOCK'; setTimer(5m)
if e.type == 'SIDECAR_SELL_START': sidecar='SELL_BLOCK'; setTimer(5m)
if e.type == 'SIDECAR_END': sidecar='NONE'
preTradeCheck(order):
if market in ['CB1_HALT','CB2_HALT','CB3_CLOSED']: reject_or_queue(order)
if sidecar blocks order.programSide: reject_or_reroute(order)
applyRecoveryCaps(order)
6) Failure patterns to test before live
- Duplicate event replay (idempotency check)
- Out-of-order events (END arrives before START)
- Clock skew around T-40m boundary
- Sidecar during post-CB recovery
- Feed stall with missing END (timer + heartbeat reconciliation)
- Stage progression with insufficient extra -1% (should not false-trigger stage2/3)
7) Monitoring KPIs
Track separately for normal vs stabilization windows:
- slippage p95/p99
- first-10-min post-reopen markout
- reject ratio and retry depth
- queue age during halts
- participation overshoot incidents
- false state transitions (detector mismatch with official notice)
Bad smell:
- low reject ratio but exploding post-reopen markout = your re-entry is too aggressive.
8) Implementation checklist (copy/paste)
- Add market-state + sidecar-state stores with durable event log
- Add idempotency key:
eventType + market + tsBucket + source - Add T-40m and open+1m/open+5m rule gates
- Add staged recovery ramp for child scheduler
- Add fallback timer-expiry clear + authoritative reconciliation
- Add replay test fixture using historical halt days
- Add dashboard panel:
CB/Sidecar state + remaining timer + blocked flow
References
- KRX Law Portal โ ์ ๊ฐ์ฆ๊ถ์์ฅ ์
๋ฌด๊ท์ (bookid=210025251), especially:
- ์ 16์กฐ(ํ๋ก๊ทธ๋จ๋งค๋งคํธ๊ฐ์ ๊ด๋ฆฌ)
- ์ 25์กฐ(์ฃผ์์์ฅ ๋ฑ์ ๋งค๋งค๊ฑฐ๋์ค๋จ ๋ฑ)
- https://rule.krx.co.kr/
- KRX Law Portal โ ์ ๊ฐ์ฆ๊ถ์์ฅ ์
๋ฌด๊ท์ ์ํ์ธ์น (bookid=210162119), especially:
- ์ 20์กฐ(ํ๋ก๊ทธ๋จ๋งค๋งคํธ๊ฐ์ ํจ๋ ฅ์ ์ง์๊ณ ๋ฑ)
- ์ 39์กฐ(์ฃผ์์์ฅ ๋ฑ์ ๋งค๋งค๊ฑฐ๋์ค๋จ ๋ฑ)
- https://rule.krx.co.kr/
- KRX Law Portal โ ์ฝ์ค๋ฅ์์ฅ ์
๋ฌด๊ท์ (bookid=210150966), especially:
- ์ 13์กฐ(ํ๋ก๊ทธ๋จ๋งค๋งค ํธ๊ฐ ๋ฑ์ ๊ด๋ฆฌ ๋ฐ ๋ณด๊ณ )
- ์ 26์กฐ(์์ฅ์ ์ผ์์ค๋จ ๋ฑ)
- https://rule.krx.co.kr/
- KRX Law Portal โ ์ฝ์ค๋ฅ์์ฅ ์
๋ฌด๊ท์ ์ํ์ธ์น (bookid=210155599), especially:
- ์ 14์กฐ(ํ๋ก๊ทธ๋จ๋งค๋งคํธ๊ฐ์ ํจ๋ ฅ์ ์ง์๊ณ ๋ฑ)
- ์ 31์กฐ(์์ฅ์ ์ผ์์ค๋จ ๋ฑ)
- https://rule.krx.co.kr/
One-line takeaway
Treat Sidecar/CB as hard execution-state transitions, not soft "market context"โthat single design choice is what prevents halt-day slippage blowups in KR live trading.