키움 실시간 주문체결 00 — 잔고 04와 주문상태 913
00(주문체결)과 04(잔고)는 item을 빈 배열로 둡니다.
공식 명세가 종목코드 등록과 상관 없이 ACCESS TOKEN을 발급한 계좌에 주문 접수·체결·정정·취소가 발생할 경우 수신된다고 적고 있기 때문입니다.
주문 진행 단계는 913(주문상태), 완료 판정은 902(미체결수량)가 0인지,
정정·취소의 원주문은 904(원주문번호)로 봅니다.
한 주문에 이벤트가 여러 번 오므로 9203(주문번호)과 909(체결번호)로 중복을 걸러야 합니다.
키움 REST API 실시간 시세 — 0B·0D 등록과 FID에서
접속·로그인·REG 등록까지의 공통 절차를 다뤘습니다. 이 글은 그중
시세가 아니라 내 계좌에서 벌어진 일을 받는 두 항목만 떼어 정리한 것입니다.
체결 알림을 텔레그램으로 보내거나, 주문을 낸 뒤 붙었는지 확인하려면 결국 여기로 옵니다.
0B와 00은 이름만 비슷하고 완전히 다르다
가장 먼저 정리해야 할 혼동입니다. 둘 다 "체결"이라는 단어가 들어가지만 성격이 반대입니다.
0B 주식체결 | 00 주문체결 | |
|---|---|---|
| 무엇 | 시장에서 일어난 체결 | 내 계좌의 주문 사건 |
item | 종목코드 필요 (005930) | 빈 배열로 둔다 |
| 기준 | 등록한 종목 | ACCESS TOKEN을 발급한 계좌 |
| 언제 | 그 종목이 체결될 때마다 | 접수·체결·정정·취소가 생길 때 |
| 대표 FID | 10 현재가 · 15 거래량 | 913 주문상태 · 902 미체결수량 |
공식 명세는 00 설명에 "ACCESS TOKEN 발급과 상관없이 해당 종목의 체결내역을 보고싶으신 경우에 0B를 이용 부탁드립니다"라고
친절하게 갈라 적어 두었습니다. 남의 체결을 보려면 0B, 내 주문을 보려면 00입니다.
등록 패킷 — item은 비운다
# 주문체결(00)과 잔고(04)를 함께 등록
{
"trnm": "REG",
"grp_no": "2", # 시세용 그룹과 분리해 두면 해지가 쉽다
"refresh": "1",
"data": [{"item": [], "type": ["00", "04"]}]
}
item에 값을 넣어도 무시되지만, 넣지 않는 편이 의도가 분명합니다.
공식 파이썬 예제(subscribe_domestic_order_fill_pubsub.py)도
"data": [{"item": [], "type": ['00']}]로 빈 배열을 씁니다.
그룹번호를 시세와 나누십시오. grp_no를 전부 "1"로 쓰면
시세 구독을 정리하려고 REMOVE를 보낼 때 계좌 이벤트 구독까지 함께 끊깁니다.
체결 알림이 조용히 멈추는 사고의 흔한 원인입니다.
주문체결(00) FID — 실제로 쓰는 것만
실시간 메시지는 이렇게 들어옵니다.
{
"trnm": "REAL",
"data": [{
"type": "00",
"name": "주문체결",
"item": "005930",
"values": {
"9201": "1234567890", # 계좌번호
"9203": "0000123", # 주문번호
"9001": "A005930", # 종목코드
"913": "체결", # 주문상태
"900": "10", # 주문수량
"901": "72000", # 주문가격
"902": "4", # 미체결수량 ← 0이면 끝난 주문
"910": "72000", # 체결가
"911": "6", # 체결량 ← 이번 이벤트분
"909": "0000045", # 체결번호
"904": "0000000", # 원주문번호 (정정·취소일 때 채워짐)
"938": "108", # 당일매매수수료
"939": "0" # 당일매매세금
}
}]
}
| FID | 한글명 | 봇에서 쓰는 곳 |
|---|---|---|
9203 | 주문번호 | 내가 낸 주문과 매칭하는 기본 키 |
904 | 원주문번호 | 정정·취소가 어느 주문에 걸린 것인지 |
913 | 주문상태 | 접수·확인·체결 등 진행 단계 (표시용) |
902 | 미체결수량 | 완료 판정은 이 값으로 |
900 / 901 | 주문수량 / 주문가격 | 요청과 접수 내용 대조 |
910 / 911 | 체결가 / 체결량 | 이번 이벤트에서 붙은 분량 |
914 / 915 | 단위체결가 / 단위체결량 | 분할 체결 상세 |
903 | 체결누계금액 | 평균단가 계산의 재료 |
909 | 체결번호 | 중복 제거 키 |
905 / 906 / 907 | 주문구분 / 매매구분 / 매도수구분 | 매수·매도 방향 판별 |
908 | 주문/체결시간 | 이벤트 시각 |
938 / 939 | 당일매매수수료 / 당일매매세금 | 실현손익 계산에 반드시 반영 |
919 | 거부사유 | 주문이 거절됐을 때의 원인 |
2134 / 2135 / 2136 | 거래소구분 / 구분명 / SOR여부 | KRX·NXT 중 어디로 나갔는지 |
10010 | 2026-09-12 21시부로 제거 — 아래 설명 |
10010은 2026-09-12 21시부로 00(주문체결)에서 삭제됐습니다.
KRX 시간외단일가가 2026-09-14 폐지되고 애프터마켓(16:00~20:00)이 신설되면서,
키움 오픈API도 시간외단일가 계열을 함께 정리했습니다.
오픈API 적용(2026-09-12 21시)과 제도 적용(2026-09-14)의 날짜가 달라서,
주말에 재기동한 봇은 월요일 장 전에 이미 없어진 값을 읽고 있었을 수 있습니다.
실무상 확인할 것은 둘입니다 —
⑴ 00 콜백에서 10010을 읽는 코드가 남아 있으면 제거하십시오
(.get("10010")로 감싼 경우 조용히 None이 되어 티가 나지 않습니다).
⑵ 수신 창을 20시까지 넓히십시오. 애프터마켓이 생기면서 체결 이벤트가 들어오는 시간대가 늘었는데,
"15:30이면 세션 종료"로 짜인 재기동·종료 스케줄이 그대로면 그 구간의 00·04를 통째로 놓칩니다.
자세한 삭제 목록은 시간외단일가 TR 삭제 편에 정리했습니다.
삭제·추가 항목은 공지로 계속 바뀌므로 키움 오픈API 공식 가이드의 현재 FID 목록으로 대조하십시오.
913 문자열로 분기하지 마십시오.
상태 표기는 증권사 화면 용어라 언제든 바뀔 수 있고, 부분체결처럼 같은 문자열이 여러 번 오는 상황도 있습니다.
"이 주문이 끝났는가"는 902(미체결수량)가 0인지로 판단하고,
913은 로그와 알림 문구에만 쓰는 편이 튼튼합니다.
919(거부사유)에 값이 들어오면 그건 체결이 아니라 거절이므로 재시도 로직을 따로 태워야 합니다.
한 주문에 이벤트가 여러 번 온다
공식 명세가 접수·체결·정정·취소를 모두 수신 대상으로 적고 있습니다. 10주 지정가 매수 하나를 내면 실제로는 대략 이런 순서로 들어옵니다.
| 순서 | 913 | 911 체결량 | 902 미체결 | 의미 |
|---|---|---|---|---|
| 1 | 접수 | — | 10 | 주문이 들어감 |
| 2 | 체결 | 4 | 6 | 부분체결 |
| 3 | 체결 | 6 | 0 | 완료 |
이벤트마다 911을 그냥 더하면 수량이 부풀 수 있습니다.
재접속 직후 중복 수신이 생기거나 알림 처리가 두 번 돌면 그대로 장부가 어긋납니다.
누적 대신 902 같은 절대값을 신뢰하고,
굳이 누적해야 한다면 (9203, 909) 쌍을 집합에 넣어 이미 본 이벤트인지 확인하십시오.
seen = set() # 이미 처리한 (주문번호, 체결번호)
orders = {} # 주문번호 -> 상태
def on_order_event(v):
ono = v.get("9203") # 주문번호
fill = v.get("909") # 체결번호
key = (ono, fill)
if fill and key in seen: # 중복 이벤트는 버린다
return
if fill:
seen.add(key)
st = orders.setdefault(ono, {"code": v.get("9001"), "filled": 0, "fee": 0})
if v.get("919"): # 거부사유가 있으면 체결이 아니다
st["rejected"] = v["919"]
return
if v.get("911"):
st["filled"] += int(v["911"]) # 참고용 누적
st["remaining"] = int(v.get("902") or 0) # 판정은 항상 이 값으로
st["fee"] = int(v.get("938") or 0)
st["tax"] = int(v.get("939") or 0)
st["done"] = st["remaining"] == 0 # 완료 판정
잔고(04) FID — 체결이 있을 때만 온다
04는 주문 체결이 발생할 경우에 수신된다고 명세에 적혀 있습니다.
보유 종목의 시세가 움직이는 것만으로는 오지 않습니다.
| FID | 한글명 | 비고 |
|---|---|---|
9001 | 종목코드 | 어느 종목의 잔고가 바뀌었는지 |
930 | 보유수량 | 체결 반영 후 수량 |
931 | 매입단가 | 평균 매입가 |
932 | 총매입가(당일누적) | 당일 기준 누적 |
933 | 주문가능수량 | 매도 주문 수량의 상한 |
945 / 946 | 당일순매수량 / 매도·매수구분 | 당일 방향 |
950 | 당일총매도손익 | 당일 실현 합계 |
8019 | 손익률(실현손익) | 실현 기준 수익률 |
990 / 991 | 당일실현손익(유가) / 손익율 | 현금 매매분 |
992 / 993 | 당일실현손익(신용) / 손익율 | 신용 매매분 |
307 | 기준가 | 전일 종가 기준 |
27 / 28 | (최우선)매도호가 / 매수호가 | 즉시 청산가 추정 |
평가금액 화면을 04만으로 만들면 값이 멈춰 보입니다.
체결이 없으면 메시지가 안 오기 때문입니다. 실시간 평가액이 필요하면
보유 종목을 0B로 함께 구독해 10(현재가)을 곱하거나,
계좌평가잔고 kt00018을 주기적으로 조회하십시오.
930(보유수량)과 933(주문가능수량)은 다릅니다.
미수·대용·이미 걸어 둔 매도 주문 등으로 갈릴 수 있어,
매도 수량은 930이 아니라 933을 상한으로 잡아야 주문 거절이 줄어듭니다.
매수 쪽 여력은 실시간이 아니라
주문가능금액 kt00010으로 확인합니다.
실시간만으로는 부족한 구간
실시간은 붙어 있는 동안의 사건만 밀어 줍니다. 다음 세 구간은 구조적으로 공백이 생깁니다.
- 봇 재시작 사이 — 프로세스가 죽어 있던 동안의 체결은 다시 오지 않습니다.
- 재접속 사이 — 소켓이 끊기면 등록도 사라지므로
LOGIN→REG를 다시 해야 하고, 그 몇 초의 사건은 놓칩니다. - 수동 주문 — HTS·MTS에서 사람이 낸 주문도 같은 계좌면 옵니다. 봇이 모르는 주문번호가 들어와도 죽지 않도록 방어하십시오.
그래서 실무 구성은 실시간을 신호로, REST를 정답으로 쓰는 이중화입니다. 복귀 직후 체결내역 kt00009와 미체결 ka10075로 상태를 한 번 맞추고, 다음 주문 수량은 내부 장부가 아니라 조회 결과로 계산합니다. 실현손익 집계는 실현손익 ka10072 쪽이 기준입니다.
체결 알림을 텔레그램으로 보낼 때는 00이 가장 자연스러운 재료입니다.
9001(종목코드)·907(매도수구분)·911(체결량)·910(체결가)만 있으면 문장 하나가 나옵니다.
다만 부분체결마다 알림이 가면 시끄러우니 902가 0이 될 때만 보내는 식으로 묶으십시오.
구성 방법은 텔레그램 봇 모니터링과 원격 제어에 정리해 두었습니다.
자주 묻는 질문
모의투자에서도 00·04가 오나요?
모의 도메인은 wss://mockapi.kiwoom.com:10000이고, 실전 키로 모의에 붙으면
8030·8031(투자구분이 달라 앱키·토큰 사용 불가)로 막힙니다.
또 공식 오류 코드에 8104(모의투자에서 지원하지 않는 API)가 있으므로,
모의에서 되는 범위는 계정 기준으로 직접 확인하시는 편이 안전합니다.
계좌가 여러 개면 어떻게 되나요?
수신 기준이 ACCESS TOKEN을 발급한 계좌이므로 9201(계좌번호)로 구분됩니다.
봇이 특정 계좌만 다룬다면 9201이 내 계좌인지 먼저 검사하고 아니면 무시하십시오.
수수료·세금이 실시간으로 정확한가요?
938·939는 당일 기준값입니다. 정산·환급이나 세금 계산 규정에 따라
최종 금액과 달라질 수 있으니, 성과 집계는 실시간 값이 아니라 조회 API 결과로 다시 맞추십시오.
비용을 빼먹은 백테스트가 왜 위험한지는
백테스트 거래비용 반영에 정리해 두었습니다.
2026-08-29 기준으로 키움증권 공식 저장소(Kiwoom-Securities/Kiwoom-REST-API)가 배포하는
API 명세 kiwoom/_data/kiwoom_api_spec.json의 실시간 항목 주문체결(00)·잔고(04) 원문과
공식 예제 examples/국내주식/실시간시세/subscribe_domestic_order_fill_pubsub.py의
항목 매핑에서 확인한 필드명·FID·설명을 기준으로 작성했습니다.
본문의 코드는 구조를 보여주기 위한 예시이며 그대로 실전에 쓰라는 뜻이 아닙니다.
FID 구성·수신 조건·모의투자 지원 범위는 증권사 공지로 예고 없이 바뀝니다.
운영 전 개발자 포털의 현재 명세로 대조하십시오. 이 글은 수익이나 시장 방향을 예측하지 않으며 세무 상담이 아닙니다.
체결이 새지 않는 봇, 만들어 드립니다
실시간 주문체결 수신, 중복 제거, 재접속 후 REST 대조, 텔레그램 체결 알림까지 묶어서 실제로 돌아가는 자동매매 프로그램으로 만들어 드립니다. 24시간 빠른 답변 가능합니다.
무료 상담 시작하기