Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
12 KiB
KRX 애프터마켓 개설 · NXT 제도개선 (시행 2026-09-14)
상태: 조사·기록만 완료. 코드 변경 0건. 관리자님 지시(2026-09-08): "내용만 확인해놔. 14일 이후에 키움 API가 어떻게 변경되는지 확인하고 작업하자." → §4 키움 API 확인이 모든 구현의 선행 조건이다. 확인 전에 §5 좌표를 손대지 말 것.
출처: 대신증권 공지 「KRX 애프터마켓 개설 및 NXT 제도개선 안내」 (2026-09-08 13:56 게시)
https://money2.daishin.com/E5/MBoard/PType_Basic/Mobile_Notice/DM_Basic_Read.aspx?seq=18257&page=1&p=4124&v=3090&m=3817
1. 공지 확정 사실
KRX 시간표
| 구분 | 변경 전 | 변경 후 |
|---|---|---|
| 장개시전 시간외 종가 | 08:30~08:40 | 현행 유지 |
| 정규장 | 09:00~15:30 | 현행 유지 |
| 장종료후 시간외 종가 | 15:40~16:00 | 현행 유지 |
| 장종료후 시간외 단일가 | 16:00~18:00 | 폐지 |
| KRX 애프터마켓 | 없음 | 16:00~20:00 신설 |
애프터마켓 매매 규칙
- 체결: 접속매매 (최초/최종 단일가 없음). VI 발동 시에만 단일가 전환
- ※ NXT 애프터마켓 개장 전 10분간(15:30~15:40)은 단일가매매 적용
- 제출가능 호가: 지정가 · 최우선지정가 · 최유리지정가 (IOC/FOK 허용) → 시장가 없음, 스톱지정가 없음
- 대상: 유가증권·코스닥의 주권/외국주권/DR/리츠/선박투자회사/투자회사/SOC
- 제외종목 9종: 30분 단위매매 · 거래정지 · 당일 정규장 미거래 · 투자경고 · 투자위험 · 이상급등 · 관리 · 초저유동 · 투자주의환기 · 투자유의
- 기존 시간외단일가에서 거래되던 ETF/ETN 거래불가
- 시세: 애프터마켓의 고가/저가/실시간 체결가 산출. 익일 기준가 참조가격은 정규장 종가
정규장 미체결 주문 — 자동 소멸 시점 (명문화됨)
| 구분 | KRX | NXT |
|---|---|---|
| 자동 증거금 해지 | 정규장 종료 후 15:35~ | 애프터마켓 종료 후 20:05~ |
| 미체결 주문 | 애프터마켓에서 재주문 필요 (미이전) | 애프터마켓까지 주문 유지 |
| 예시 | 09:00 주문 → 15:30 미체결 → 15:35~ 증거금 해지 → 16:00 이후 재주문 | 08:00 주문 → 20:00까지 미체결 → 20:00 이후 증거금 해지 |
NXT 제도개선
정적VI 도입 + 동적/정적VI 발동 시 단일가매매(2분) 전환
| 동적VI | 정적VI | |
|---|---|---|
| 참조가격 | 직전 체결가격 | 직전 단일가매매 가격 (없으면 기준가격) |
| 발동요건 | 코스피200 ±3% / 기타 ±6% | ±10% |
| 발동효과 | 단일가매매 전환(2분) | 〃 |
| 제출가능호가 | 지정가, 스톱지정가호가(메인마켓) | 〃 |
| 적용대상 | 모든 접속매매 체결 / 마켓별 최초가격 배제 | 모든 접속·단일가매매 체결(VI단일가 제외) / 마켓별 최초가격에도 적용 |
- 거래정지 후 재개 시 단일가매매: CB(시장) NXT 30분 중단 + 단일가 30초 (KRX 20분 + 10분) / 중요내용공시(종목) NXT 40분 정지 + 단일가 30초 (KRX 30분 + 10분)
- GTP(Good till Premarket) 전용호가 도입 — 프리마켓 제출 호가 전체에 적용 가능, 미체결잔량은 프리마켓 종료(08:50) 일괄 취소
- 프리마켓 상·하한가 주문가능 — 2026-08-12부터 한시 적용됐던 NXT 프리마켓 상·하한가 주문제한 해제
- 대주거래 09:00~20:00 확대 (KRX/NXT 동일) — 우리는 대주거래 미사용, 영향 없음
외부 교차 확인 (뉴스): 애프터마켓 16:0020:00 · 15:4016:00 시간외종가 유지 · ETF·ETN 거래불가 · 공식 종가는 15:30 정규장 종가 · 사이드카 없음·VI 있음.
2. 현재 코드가 믿고 있는 시간 모델
시간 경계는 scripts/orders/limits.json L37-49가 단일 진실 공급원이고 guards.py엔 시간 리터럴이 0개다(orders/__init__.py:22-24 설계 규칙).
guards.session_at() (guards.py:78-89) 세션 5종 + determine_routing() (guards.py:143-161):
| 세션 | 구간 | suffix | dmst_stex_tp |
|---|---|---|---|
NXT_PRE |
08:00:00–09:00:00 | _NX |
NXT |
| (틈) | 09:00:00–09:00:30 | — | ValueError |
KRX_NXT |
09:00:30–15:20:00 | _AL / '' |
SOR / KRX |
KRX_CLOSE |
15:20:00–15:30:00 | '' |
KRX |
NXT_AFTER |
15:30:00–20:00:00 | _NX |
NXT |
CLOSED |
그 외 | — | ValueError |
⚠️ 핵심: KRX 시간외 시장(종가·단일가)이 모델에 아예 없다. 15:30 이후는 전부 NXT로 취급한다. KRX 애프터마켓 신설이 정확히 이 가정을 깬다.
⚠️ 자산웹 phase는 별개의 하드코딩이다(behive_web.py:788-808) — 09:00~15:30=regular, 08:00~20:00=nxt, 그 외 closed. 프리(08:0009:00)와 애프터(15:3020:00)를 같은 nxt 값으로 구분하지 못한다.
3. 영향 분석 (2026-09-08 실측)
① 거래 가능해지는데 자산웹이 막는 종목 — 가장 실질적
ETF/ETN은 state/stock_codes.json 기준 1,063/1,064가 nxt_enable=False. 애프터마켓에서도 ETF/ETN은 거래불가이므로 현행 차단이 결과적으로 정당하다.
문제는 NXT 미상장 일반주. 전체 4,300종목 중 nxt_enable=False가 3,693개, ETF/ETN을 뺀 약 2,630개가 9/14부터 KRX 애프터마켓에서 거래 가능해진다.
| ETF/ETN (차단 유지 정당) | NXT 미상장 일반주 (신규 거래가능) | NXT 상장 | |
|---|---|---|---|
| 보유 37 | 12 | 15 | 10 |
| 관심 57 | 12 | 20 | 25 |
| 감시 45 | 0 | 32 | 13 |
보유분 해당 15종목: LG씨엔에스 · SK이터닉스 · 삼성전자우 · 파두 · 아난티 · 제닉스로보틱스 · 마키나락스 · 노루페인트 · 베뉴지 · 서부T&D · 진흥기업 · 피앤씨테크 · RF머트리얼즈 · WON 두산그룹포커스 · WON 초대형IB&금융지주
차단 경로: _market_phase_state()가 16:00~20:00을 nxt로 판정 → /api/quote_book이 nxt_enable=False 회신(behive_web.py:14687-14717) → 클라이언트가 📵 NXT 거래불가 라벨 + cls='closed'(behive_web.py:12853) → refreshSubmitGate()가 state.phaseCanTrade===false로 매수/매도 버튼 disable(behive_web.py:12928-12935).
② 감시 공백
| 감시 | 현재 커버 | 애프터마켓(16:00~20:00) |
|---|---|---|
trailing_monitor |
08:00–19:59 (plist 720엔트리) | ✅ 이미 커버 |
surge_monitor |
09:00–15:35 (MARKET_CLOSE=(15,35) L91, plist 396엔트리) |
❌ 급등락·VI 알림 0건 |
watchlist_monitor |
10:00/12:00/14:00 3회 (MARKET_CLOSE=(15,45) L48) |
❌ |
sim-scan |
09:00–15:30 (plist 196엔트리) | ❌ |
③ 부수 영향 지점
surge_monitor.get_limit_map()하루 1콜 캐시(L306-320) — 애프터마켓 가격제한폭이 정규장과 다르면 16:00 이후upl_pric/lst_pric이 틀린 값이 된다. 공지·뉴스에 제한폭 언급이 없어 미확정(§4-4).trailing_monitor.py:142실측 전제 재검증 필요 — "스톱주문은 장 마감 후 체결 없이 소멸한다(15:3018:21 사이)". 그 관측 구간이었던 시간외단일가(16:0018:00)가 폐지되고, 공지가 소멸 시점을 KRX 15:35~ / NXT 20:05~로 명문화했다. 재실측 없이는_notify_gone_batch의 "장 마감 취소 추정" 문구가 틀린 시각에 나간다.- 시장가 차단은 유지가 맞다 —
validate_market_order_session()(guards.py:195-205)이NXT_PRE/NXT_AFTER에서 MARKET을 거부한다. 애프터마켓 호가유형에도 시장가가 없어 근거가 오히려 늘어난다. - ⚠️
STOP_LIMIT은 세션 제약이 전무하다. 애프터마켓엔 스톱지정가가 없고 NXT 메인마켓엔 있으므로, 라우팅을 KRX로 바꾸는 순간 트레일링·스톱 발주가 깨진다. - 09:00:00–09:00:30 틈은
CLOSED→determine_routing이ValueError. 기존 하자이며 이번 변경과 무관하나 같이 손볼 후보. - 시간 가드가 두 계통으로 갈려 있다 —
limits.json기반은trailing_monitor단독이고,surge_monitor·watchlist_monitor·behive_web·stock_analysis는 각자 하드코딩. 제도 변경마다 파일별로 손봐야 한다. 통합하면 이후엔 JSON 편집 + plist 재생성 2단계로 줄어든다.
4. 키움 API 확인 체크리스트 — 다음 작업의 선행 조건
로컬 ~/.openclaw/docs/키움 REST API 문서.pdf는 2026-05-07 검증본으로 이번 제도 변경 이전판이고, 키움 OpenAPI 포털에서 관련 공지를 찾지 못했다.
⚠️ CLAUDE.md 규칙("suffix 패턴 추측 금지 — 2026-05-07 ka10004 사고")에 따라 아래 값을 지어내지 않는다.
dmst_stex_tp값 — 현재 매핑_EXCHANGE_BY_SUFFIX = {'_AL':'SOR', '_NX':'NXT', '':'KRX'}(kiwoom_order.py:36-41). 애프터마켓 주문이KRX로 그냥 나가는지,SOR가 자동 라우팅하는지, 신규 값이 생기는지.trde_tp값 — 현재'0'지정가 /'3'시장가 /'28'스톱지정가(kiwoom_order.py:31-34). 애프터마켓 전용 호가유형(최우선지정가·최유리지정가·IOC·FOK) 코드가 추가되는지.- 애프터마켓 참여 가능 여부 플래그 —
ka10099 nxtEnable은 NXT 상장 여부만 준다. 제외종목 9종류를 판별할 필드가 새로 생기는지, 아니면order_warning·state텍스트로 근사해야 하는지. - 애프터마켓 가격제한폭 —
ka10001/ka10095의upl_pric/lst_pric이 16:00 이후에도 정규장 기준값인지 애프터 전용 값인지.surge_monitor상·하한가 트리거 정확도가 여기 걸려 있다. - VI 필드 — NXT 정적VI 도입으로 실시간
1hbroadcast 페이로드가 확장되는지.surge_monitor가vi.active를 그대로 신뢰한다(L373-377). - 호가·시세 TR의 애프터마켓 구분 —
ka10004응답에 세션 구분 필드가 생기는지. 현재 자산웹은 시간외/애프터 구분 필드를 전혀 쓰지 않는다. - 미체결 조회(
ka10075) 동작 — KRX 주문이 15:35 증거금 해지 후 목록에서 즉시 빠지는지.trailing_monitor생존 판정이 이 응답에 전적으로 의존한다.
확인 방법: 9/14(월) 장에서 ① 키움 REST API 포털·공지 재확인 ② 16:00 이후 ka10095·ka10001 응답 실측(조회 전용, 안전) ③ 필요시 NXT 미상장 보유주 1주로 애프터마켓 실주문 검증.
5. 확인 후 손댈 좌표 (미리 특정)
§4 확인 전엔 손대지 않는다.
| 대상 | 파일:라인 | 성격 |
|---|---|---|
| 세션 정의 | scripts/orders/limits.json:37-49 |
애프터마켓 경계 추가 |
| 세션 판정 | scripts/orders/guards.py:78-89 (session_at) |
세션 1종 추가 |
| 라우팅 | scripts/orders/guards.py:143-161 (determine_routing) |
애프터 세션 라우팅 |
| 시장가 게이트 | scripts/orders/guards.py:195-205 |
애프터 세션 추가(거부 유지) |
| 거래소 코드 | scripts/orders/kiwoom_order.py:36-41 |
§4-1 결과 반영 |
| 자산웹 phase | scripts/behive_web.py:788-808, :812(_PHASE_BOUNDARIES_MIN) |
phase 분리 + 16:00 경계 |
| phase 라벨·게이트 | scripts/behive_web.py:12845-12874, :12928-12935 |
📵 NXT 거래불가 조건 재정의 |
| 호가 거래소 선택 | scripts/behive_web.py:14687-14717 |
애프터 세션 분기 |
| 급등락 감시 | scripts/surge_monitor.py:90-91, :306-320 + plist 396→약 660엔트리 |
시간 확대 + 제한폭 캐시 |
| 워치리스트 감시 | scripts/watchlist_monitor.py:47-48 + plist |
시간 확대 |
| 트레일링 문구·전제 | scripts/trailing_monitor.py:142, :487 |
소멸 시점 재실측 반영 |
| 시세 조회 거래소 | scripts/trailing_monitor.py:446 ('NX' if sess in ('NXT_PRE','NXT_AFTER') else 'AL') |
세션명 추가 시 동반 수정 필수 |
| 경계 테스트 | scripts/orders/tests/test_guards.py:45-72 |
12케이스 갱신 필수 |
| 정책 문서 | scripts/orders/__init__.py:38-42, memory/orders_module.md:38,41-42 |
"08:00–20:00 NXT" 서술 정정 |
⚠️ 20:00 종료가 유지되므로 guards.after_trading_day(= nxt_after_end)와 그 소비자(orders/trailing.py:692 is_arm_expired), trailing-monitor plist(720엔트리), briefing 20:10/20:30·trade-journal 21:00 트리거는 무변경 가능.