KIS 야간선물옵션 API — 체결통보가 2개로 갈린다
H0IFCNI0 하나로 선물·옵션을 다 받지만,
야간은 선물 H0MFCNI0 + 옵션 H0EUCNI0 두 개를 따로 등록해야 합니다.
하나만 걸어 두면 나머지 절반의 체결 통보가 오지 않습니다.
시세도 마찬가지여서 야간선물은 H0MFCNT0, 야간옵션은 H0EUCNT0이라
두 계열 사이에 문자열 규칙이 없습니다.
야간파생 봇의 사고는 전략이 아니라 배선에서 납니다.
주간에 멀쩡히 돌던 코드를 야간 세션에 그대로 올리면,
주문은 나가는데 체결 통보가 안 오거나 웹소켓은 붙어 있는데 한 틱도 안 들어옵니다.
이 글은 한국투자증권 공식 저장소 koreainvestment/open-trading-api의
examples_llm/domestic_futureoption/ 파이썬 예제와 API 메타데이터를
2026년 9월 20일 기준으로 직접 읽어 야간 경로만 추려낸 것입니다.
주간 주문 TTTO1101U 편은
따로 있으니, 여기서는 야간에만 달라지는 것만 다룹니다.
이 글에서 다루는 것
- 함정 1 — 야간 TR 접두어가 세 갈래다 (
STTN·TTTN·CTFN) - 함정 2 — 조회는 URL이 바뀌는데 주문은 안 바뀐다
- 함정 3 — 웹소켓은
H0MF(선물)·H0EU(옵션), 주간과 한 글자도 안 겹친다 - 함정 4 — 체결통보가 하나에서 둘로 갈린다
- 함정 5 — 야간선물에는 예상체결이 없다
- 함정 6 — 공식 예제의
tr_key가 서로 안 맞는다 - 응답 필드에서 실제로 쓰는 것
- 세션 자체 — 시간·계좌·모의투자
- 최소 구현 골격
- 이 글이 다루지 않는 것
함정 1 — 야간 TR 접두어가 세 갈래다
"야간이면 TR ID 앞부분을 바꾸면 되겠지" 하고 치환 함수를 하나 만들면 절반만 맞습니다.
공식 저장소 domestic_futureoption_functions.py의 TR ID를 기능별로 늘어놓으면 이렇습니다.
| 기능 | 주간 실전 | 야간 실전 | 바뀌는 부분 |
|---|---|---|---|
| 선물옵션 주문 | TTTO1101U | STTN1101U | TTTO → STTN |
| 정정취소주문 | TTTO1103U | TTTN1103U | TTTO → TTTN |
| 주문가능 조회 | TTTO5105R | STTN5105R | TTTO → STTN |
| 주문체결 내역조회 | TTTO5201R | STTN5201R | TTTO → STTN |
| 잔고현황 | CTFO6118R | CTFN6118R | CTFO → CTFN |
| 증거금 상세 | — | CTFN7107R | 야간 전용 |
같은 "야간"인데 접두어가 STTN·TTTN·CTFN 셋입니다.
주문은 STTN인데 정정취소만 TTTN이고,
잔고 쪽은 아예 다른 계열인 CTFO에서 O 한 글자만 N으로 바뀝니다.
tr.replace("TTTO", "STTN") 같은 함수를 쓰면 정정취소와 잔고가 조용히 틀립니다.
그래서 치환하지 않고 표를 상수로 박아 둡니다. "왜 정정취소만 안 되지"를 새벽 세 시에 찾는 것보다 훨씬 쌉니다.
# 야간 TR 매핑 — 규칙이 없으므로 표로 관리한다
NGT_TR = {"order":"STTN1101U", "order_cancel":"TTTN1103U", # ← 접두어가 다르다
"psbl_order":"STTN5105R", "ccnl":"STTN5201R",
"balance":"CTFN6118R", "margin":"CTFN7107R"}
DAY_TR = {"order":"TTTO1101U", "order_cancel":"TTTO1103U",
"psbl_order":"TTTO5105R", "ccnl":"TTTO5201R",
"balance":"CTFO6118R"}
함정 2 — 조회는 URL이 바뀌는데 주문은 안 바뀐다
TR ID를 표로 정리하고 나면 다음 함정이 기다립니다. 엔드포인트 경로입니다. 야간 조회 API는 경로 자체가 다릅니다.
| 기능 | 주간 경로 | 야간 경로 |
|---|---|---|
| 잔고현황 | /trading/inquire-balance | /trading/inquire-ngt-balance |
| 주문가능 | /trading/inquire-psbl-order | /trading/inquire-psbl-ngt-order |
| 주문체결내역 | /trading/inquire-ccnl | /trading/inquire-ngt-ccnl |
| 증거금 상세 | — | /trading/ngt-margin-detail |
| 주문 | /trading/order | /trading/order (동일) |
| 정정취소 | /trading/order-rvsecncl | /trading/order-rvsecncl (동일) |
앞은 전부 /uapi/domestic-futureoption/v1입니다.
여기서 "야간이면 경로에 -ngt-를 끼워 넣자"는 규칙을 만들면
주문이 존재하지 않는 주소로 나갑니다.
조회는 "경로 + TR 둘 다" 바뀌고, 주문은 "TR만" 바뀝니다.
래퍼를 한 겹 만들 때 is_night 플래그 하나로 두 가지를 동시에 처리하려 들면 여기서 어긋납니다.
함정 3 — 웹소켓은 H0MF·H0EU, 주간과 한 글자도 안 겹친다
주간 국내선물옵션 실시간 TR은 기초자산별로 다섯 계열입니다 —
지수선물 H0IF, 지수옵션 H0IO, 주식선물 H0ZF, 주식옵션 H0ZO, 상품선물 H0CF.
야간에는 이 다섯이 전부 쓰이지 않고 야간 전용 두 계열로 대체됩니다.
| 구독 항목 | 주간 | 야간 |
|---|---|---|
| 선물 체결가 | H0IFCNT0 / H0ZFCNT0 / H0CFCNT0 | H0MFCNT0 |
| 선물 호가 | H0IFASP0 / H0ZFASP0 / H0CFASP0 | H0MFASP0 |
| 옵션 체결가 | H0IOCNT0 / H0ZOCNT0 | H0EUCNT0 |
| 옵션 호가 | H0IOASP0 / H0ZOASP0 | H0EUASP0 |
| 옵션 예상체결 | H0ZOANC0 (주식옵션만) | H0EUANC0 |
| 선물 예상체결 | H0ZFANC0 (주식선물만) | 없음 |
| 체결통보 | H0IFCNI0 하나 | H0MFCNI0 + H0EUCNI0 둘 |
야간선물이 H0MF, 야간옵션이 H0EU입니다.
선물·옵션을 가르는 글자가 F/O도 아니고 야간을 가리키는 공통 글자도 없습니다.
주간 체계(H0 + 기초자산 2글자 + CNT0/ASP0)를 코드로 조립하던 라우터가 있다면
야간은 통째로 예외 처리해야 합니다.
왜 옵션이 EU인가 — 공식 설명은 없습니다.
다만 KRX가 자체 야간거래를 열기 전 야간 파생은 EUREX 연계거래였고,
KRX 공식 안내도 자체 야간거래 대상 상품(10개)이 "기존 Eurex 연계거래(5개)보다 크게 확대"됐다고 적고 있습니다.
확인된 사실이 아니라 관찰이니, "EU니까 유럽/유렉스"라고 의미를 추론하지 말고
단순한 식별자로만 다루십시오.
함정 4 — 체결통보가 하나에서 둘로 갈린다
이 글에서 딱 하나만 가져가야 한다면 이겁니다.
주간에는 선물옵션 실시간체결통보가 H0IFCNI0 하나라
선물이든 옵션이든 같은 구독으로 들어옵니다.
그래서 대부분의 코드가 체결통보 등록을 한 줄로 짜 놓습니다.
야간에는 그게 두 개입니다.
# 주간 — 한 번 등록하면 선물·옵션 체결이 모두 들어온다
ws.subscribe("H0IFCNI0", tr_key=HTS_ID)
# 야간 — 반드시 두 번 등록해야 한다
ws.subscribe("H0MFCNI0", tr_key=HTS_ID) # KRX야간선물 실시간체결통보
ws.subscribe("H0EUCNI0", tr_key=HTS_ID) # KRX야간옵션 실시간체결통보
하나만 등록하면 나머지 절반은 영원히 조용합니다. 그런데 주문은 정상적으로 나가고 체결도 됩니다. 봇 입장에서는 "접수됐는데 체결 이벤트가 안 온다" → 미체결로 간주 → 재주문, 이 흐름으로 중복 진입이 생길 수 있습니다.
다행히 파서는 하나만 만들어도 됩니다.
H0MFCNI0과 H0EUCNI0의 응답 필드 구성이
cust_id·acnt_no·oder_no·cntg_qty·cntg_unpr·
cntg_yn·rfus_yn 등 19개로 완전히 같기 때문입니다.
⚠ 다만 종목코드 필드가 stck_shrn_iscd이고 공식 한글명이
"주식 단축 종목코드"입니다. 선물옵션 체결통보인데 라벨은 주식이니
한글명이 아니라 영문 필드명으로 다루십시오.
함정 5 — 야간선물에는 예상체결이 없다
야간에도 단일가 구간이 있으니 예상체결을 받아 두려는 시도를 흔히 합니다.
그런데 공식 저장소의 야간 실시간 목록에는
H0EUANC0(KRX야간옵션 실시간예상체결) 하나뿐이고
야간선물 예상체결에 해당하는 TR이 없습니다.
주간도 예상체결(ANC0)은 주식선물 H0ZFANC0·주식옵션 H0ZOANC0만 있고
지수선물·지수옵션에는 아예 없습니다.
즉 "야간 단일가 예상체결을 선물에서 받아 타이밍을 잡는다"는 설계는
등록 단계에서부터 성립하지 않고, 체결가(H0MFCNT0)·호가(H0MFASP0)로
대체 설계를 해야 합니다.
함정 6 — 공식 예제의 tr_key가 서로 안 맞는다
야간 실시간 예제를 그대로 복사하면 종목코드 자릿수가 파일마다 다릅니다.
| 파일 | TR | 예제의 tr_key |
|---|---|---|
krx_ngt_futures_ccnl.py | H0MFCNT0 | "101W9000" (8자리) |
krx_ngt_futures_asking_price.py | H0MFASP0 | "101W9000" (8자리) |
krx_ngt_option_ccnl.py | H0EUCNT0 | "101W9000" (8자리) |
krx_ngt_option_asking_price.py | H0EUASP0 | "101W09" (6자리) |
inquire_psbl_ngt_order.py | STTN5105R | pdno="101W09" (6자리) |
게다가 krx_ngt_option_ccnl.py는 옵션 체결가 API인데
docstring의 인자 설명이 "선물단축종목코드"로 되어 있고, 예제 값도 선물 계열 코드입니다.
그래서 예제의 종목코드는 신뢰 대상이 아닙니다.
공식 저장소도 각 실시간 예제 상단에
"종목코드 마스터파일 파이썬 정제코드는 한국투자증권 Github 참고"라고 stocks_info 경로를 안내하고 있습니다.
야간 계약을 다루는 봇이라면 마스터파일에서 그날의 유효 종목코드를 받아 쓰는 절차를
구독 전에 반드시 넣으십시오. 월물이 바뀌면 하드코딩한 코드는 그날부터 빈 스트림이 됩니다.
응답 필드에서 실제로 쓰는 것
야간선물 체결 H0MFCNT0 — 48개 필드
이름·순서가 주간 지수선물과 거의 같지만, 봇에서 실제로 손이 가는 건 몇 개뿐입니다.
# H0MFCNT0 응답 컬럼 중 실제로 쓰는 것
futs_shrn_iscd 선물 단축 종목코드 bsop_hour 영업 시간
futs_prpr 선물 현재가 last_cnqn 최종 거래량(이번 체결)
acml_vol 누적 거래량 hts_thpr HTS 이론가
mrkt_basis 시장 베이시스 thpr_basis 이론 베이시스
dprt 괴리율
hts_otst_stpl_qty HTS 미결제 약정 수량
otst_stpl_qty_icdc 미결제 약정 수량 증감
futs_askp1 / futs_bidp1 선물 매도호가1 / 매수호가1
dynm_mxpr / dynm_llam 실시간 상한가 / 하한가
dynm_prc_limt_yn 실시간 가격제한 구분
⚠ dynm_mxpr·dynm_llam·dynm_prc_limt_yn은
실시간(동적) 가격제한입니다. 정적 상·하한과 별개로 움직이는 값이라,
지정가를 계산해 내보내는 로직이 있다면 이 값을 참조해야
범위를 벗어난 주문이 거부되는 일을 줄일 수 있습니다.
야간옵션 체결 H0EUCNT0 — 그리스가 함께 온다
옵션 쪽은 프리미엄·내재가치·시간가치와 그리스 전부가 체결 메시지에 실려 옵니다.
# H0EUCNT0 응답 중 옵션 전용 필드
prmm_val 프리미엄값 invl_val 내재가치값 tmvl_val 시간가치값
delta 델타 gama 감마 vega 베가 theta 세타 rho 로우
# ↑ 철자 주의: gamma 아님
hts_ints_vltl HTS 내재변동성
unas_hist_vltl 역사적 변동성
감마 필드명이 gama입니다. gamma가 아닙니다.
msg["gamma"]로 접근하면 KeyError가 나고,
.get("gamma", 0)으로 감싸 두면 조용히 0이 됩니다.
그리스를 쓰는 헤지 로직이라면 이 한 글자가 전략을 통째로 무력화합니다.
공식 컬럼 정의 그대로 gama를 써야 합니다.
야간 잔고 CTFN6118R — 연속조회가 붙는다
필수 파라미터는 넷입니다 — CANO·ACNT_PRDT_CD·
MGNA_DVSN(01:개시 / 02:유지)·
EXCC_STAT_CD(1:정산 / 2:본정산).
응답은 output1(종목별 배열)과 output2(계좌 요약)이고
CTX_AREA_FK200·CTX_AREA_NK200과 헤더 tr_cont로 페이지를 넘깁니다
(M·F면 다음 장이 있습니다).
청산 로직은 output1의 cblc_qty·lqd_psbl_qty·excc_unpr를,
새벽 마진 감시는 output2의 mmga_tot_amt(유지증거금총금액)·
mtnc_rt(유지비율)·isfc_amt(부족금액)·add_mgna_tota를 봅니다.
⚠ 야간 주문가능 STTN5105R은
max_ord_psbl_qty와 tot_psbl_qty가 둘 다 "최대주문가능수량",
lqd_psbl_qty와 lqd_psbl_qty_1이 둘 다 "청산가능수량"입니다.
한글명으로는 못 고르니 실계좌 응답을 찍어 보고 영문 키를 고정하십시오.
세션 자체 — 시간·계좌·모의투자
배선보다 앞서 확인할 것이 셋 있습니다. 여기서 막히면 코드가 아무리 맞아도 주문이 안 나갑니다.
① 거래 시간
KRX는 2025년 6월 9일 자체 야간파생상품시장을 개시했고, 공식 안내는 대상 상품이 10개로 "기존 Eurex 연계거래(5개)보다 크게 확대"됐다고 밝히고 있습니다. 거래는 18시부터 익일 6시까지입니다. 스케줄러가 "장 시간 = 09:00~15:30"으로 박혀 있으면 야간에는 아예 깨어나지 않습니다. 호가접수·단일가 구간과 휴장일은 바뀌므로 KRX·한국투자증권 공지로 확인하십시오.
② 계좌 요건
야간파생은 기존 파생 계좌라도 별도 동의 절차가 걸려 있는 경우가 있습니다. 주간 주문은 잘 나가는데 야간에만 거부된다면 코드를 뒤지기 전에 계좌 상태부터 확인하는 편이 빠릅니다. API 스펙이 아니라 약관 영역입니다.
③ 모의투자
공식 저장소에서 모의투자 계열(V로 시작) TR은
VTTO1101U·VTTO1103U·VTTO5105R·VTFO6118R처럼
주간 기능에만 붙어 있고,
STTN1101U·TTTN1103U·CTFN6118R 같은
야간 전용 TR에 대응하는 모의 코드는 보이지 않습니다.
모의투자에서 검증되는 범위가 주간까지라는 뜻이라,
야간은 최소 계약 수로 실계좌에서 한 번 통과시키는 단계를 일정에 따로 넣어야 합니다.
최소 구현 골격
지금까지의 함정을 반영하면 골격은 이 정도입니다 — TR 선택 → 경로 선택 → 구독 등록.
BASE = "/uapi/domestic-futureoption/v1"
PATH = { # 조회만 -ngt- 가 끼어든다
("balance", 0): f"{BASE}/trading/inquire-balance",
("balance", 1): f"{BASE}/trading/inquire-ngt-balance",
("psbl_order", 0): f"{BASE}/trading/inquire-psbl-order",
("psbl_order", 1): f"{BASE}/trading/inquire-psbl-ngt-order",
("ccnl", 0): f"{BASE}/trading/inquire-ccnl",
("ccnl", 1): f"{BASE}/trading/inquire-ngt-ccnl",
("order", 0): f"{BASE}/trading/order", # 주문은 주·야 동일
("order", 1): f"{BASE}/trading/order",
}
def call(op, night, params):
tr = (NGT_TR if night else DAY_TR)[op] # 함정 1의 표
url = PATH[(op, int(night))] # 함정 2의 표
return http_call(url, tr_id=tr, params=params)
def subscribe(ws, night, fut, opt, hts_id):
if night:
ws.subscribe("H0MFCNT0", fut); ws.subscribe("H0MFASP0", fut)
ws.subscribe("H0EUCNT0", opt); ws.subscribe("H0EUASP0", opt)
ws.subscribe("H0MFCNI0", hts_id) # ★ 체결통보 — 선물
ws.subscribe("H0EUCNI0", hts_id) # ★ 체결통보 — 옵션
else:
ws.subscribe("H0IFCNT0", fut); ws.subscribe("H0IFASP0", fut)
ws.subscribe("H0IOCNT0", opt); ws.subscribe("H0IOASP0", opt)
ws.subscribe("H0IFCNI0", hts_id) # 주간은 하나로 충분
세션이 바뀌는 18시 정각과 새벽 6시에는 구독을 해제하고 다시 등록하는 전환 지점이 필요합니다. 24시간 봇 운영에서 이야기하는 재기동·세션 전환 설계가 야간파생에서는 선택이 아니라 필수에 가깝습니다.
정리하면 — 야간 TR 접두어는 STTN·TTTN·CTFN 셋,
조회만 경로가 바뀌고 주문은 그대로,
실시간은 선물 H0MF · 옵션 H0EU,
체결통보는 반드시 두 개,
야간선물 예상체결은 없음,
예제 종목코드는 마스터파일로 대체.
이 여섯 개를 코드에 박아 두면 야간 배선에서 새벽에 깨어날 일이 크게 줄어듭니다.
이 글이 다루지 않는 것
- 야간에 무엇을 사고팔지는 다루지 않습니다. 이 글은 배선만 다룹니다. 레버리지 상품의 위험은 별개이고, 야간은 유동성이 주간과 다르다는 점도 설계에서 따로 봐야 합니다.
- 실계좌 호출로 검증한 값이 아닙니다. TR ID·경로·필드명은 공식 저장소 표기입니다.
- 다른 증권사의 야간 지원 여부는 다루지 않습니다. HTS·MTS에서 야간 거래가 되는 것과 API로 야간 주문이 되는 것은 별개이니, 증권사 API 비교에서 그 구분부터 확인하십시오.
자주 묻는 것
야간에 주간 TR을 등록해 두면 어떻게 되나요?
데이터가 오지 않습니다. 연결은 유지되고 오류도 뜨지 않는 경우가 많아
"웹소켓은 붙었는데 조용하다"로 보입니다.
야간 세션에는 H0MFCNT0·H0EUCNT0 계열로 갈아타야 합니다.
체결통보를 두 개 등록하면 중복으로 오지 않나요?
아닙니다. H0MFCNI0은 야간선물 체결만,
H0EUCNI0은 야간옵션 체결만 보냅니다.
겹치지 않으므로 둘 다 등록해야 전부 받습니다.
야간 종목코드는 어디서 받나요?
공식 저장소의 stocks_info 마스터파일입니다.
예제의 101W9000·101W09는 설명용이라 자릿수도 파일마다 다르고
월물이 바뀌면 무효가 됩니다.
야간 증거금은 주간 API로 볼 수 없나요?
야간 전용 CTFN7107R이 따로 있습니다. MGNA_DVSN_CD로
01:위탁 / 02:유지를 구분하고 응답이 세 덩어리로 옵니다.
tot_risk_mgna·netrisk_brkg_mgna·add_mgna_tot_amt가
새벽 감시의 핵심 값입니다.
야간선물옵션 봇을 만들면 수익이 나나요?
이 글은 그 판단을 하지 않습니다. 야간파생은 레버리지 상품이고 손실이 원금을 넘을 수 있는 구조입니다. 거래 시간이 길어진다는 건 기회가 늘어난다는 뜻이 아니라 감시 시간과 슬리피지·유동성 변수가 늘어난다는 뜻에 가깝습니다.
야간 세션까지 도는 봇을 맡기려면
야간파생은 전략보다 배선에서 사고가 납니다. 세션 전환·체결통보 이중 등록·마진 감시까지
무엇을 어떻게 붙일지부터 같이 정리해 드립니다. 24시간 빠른 답변 가능합니다.
main 브랜치의
examples_llm/domestic_futureoption/ 파이썬 예제와 API 메타데이터를
2026년 9월 20일 기준으로 읽어 정리했습니다.
본문의 TR ID·엔드포인트 경로·요청 파라미터·응답 필드명은 전부 그 시점의 공식 표기이며,
실계좌 호출 결과로 검증한 것이 아닙니다. 코드 예시는 구조를 보이기 위한 골격으로 그대로 실행되는 완제품이 아닙니다.
KRX 야간파생상품시장의 개시일과 대상 상품 수는 한국거래소 공식 안내를 따랐고,
거래 시간·호가접수 구간·휴장일·계좌 요건은 공지에 따라 변경될 수 있으므로
반드시 한국거래소와 한국투자증권 개발자 포털의 현재 내용으로 대조하십시오.
선물·옵션은 레버리지가 적용되어 손실이 투자원금을 초과할 수 있습니다.
이 글은 특정 종목·상품이나 매매 시점에 대한 권유를 담고 있지 않으며,
수익률이나 시장 방향에 대한 어떠한 전망도 하지 않습니다.
알고랩(퀀트웍스)은 투자자문업·투자일임업을 영위하지 않으며, 고객이 정한 규칙을 코드로 구현하는 도구 제작 서비스를 제공합니다.
투자 판단과 그 결과의 책임은 전적으로 투자자 본인에게 있습니다.