키움 REST API 순위 조회 — rkinfo 함정 5가지
키움 REST API 에서 거래량·거래대금 상위 종목을 받는 TR 은 POST /api/dostk/rkinfo 에 모여 있습니다. ka10030 당일거래량상위, ka10031 전일거래량상위, ka10032 거래대금상위, ka10020 호가잔량상위, ka10023 거래량급증, ka10027 전일대비등락률상위가 여기 속합니다. 걸리는 곳은 다섯입니다. ⑴ 이름에 ‘순위’가 들어간다고 다 같은 경로가 아닙니다 — ka00198 실시간종목조회순위는 알고랩 납품 건에서 /api/dostk/stkinfo 로 동작을 확인했습니다. ⑵ 경로를 그대로 두고 api-id 헤더만 바꾸면 HTTP 200 에 return_code 오류로 조용히 실패합니다. ⑶ ka00198 의 qry_tp 는 1이 1분, 5가 30초라서 공식 예제의 1 을 그대로 쓰면 이름만 실시간입니다. ⑷ 순위 TR 에는 WebSocket 실시간이 없습니다 — 폴링뿐이고, PC 시계가 어긋나면 계속 묵은 값을 받습니다. ⑸ 같은 시각인데 HTS 영웅문 화면과 목록이 다른 이유는 대개 조회 조건 파라미터입니다.
이 글은 키움 REST API 자동매매 완전 가이드에서 순위 조회 한 가지만 떼어 낸 글입니다. 인증·토큰·TR limit 같은 공통 부분은 그 글을 먼저 보십시오.
1. 순위 조회 TR 은 어디에 있나
키움증권 공식 API 가이드의 순위정보 분류에 들어 있는 TR 은 다음과 같습니다. 국내주식 화면에서 “상위”·“급증”으로 부르는 목록이 대부분 여기 있습니다.
| api-id | 이름 | 자동매매에서 쓰는 자리 |
|---|---|---|
ka10030 | 당일거래량상위요청 | 장중 유니버스 축소 |
ka10031 | 전일거래량상위요청 | 장 시작 전 후보군 |
ka10032 | 거래대금상위요청 | 유동성 필터(거래량보다 안정적) |
ka10020 | 호가잔량상위요청 | 체결 가능성 판단 |
ka10021 | 호가잔량급증요청 | 수급 변화 감지 |
ka10022 | 잔량율급증요청 | 수급 변화 감지 |
ka10023 | 거래량급증요청 | 이벤트 포착 |
ka10027 | 전일대비등락률상위요청 | 급등·급락 후보 |
ka10029 | 예상체결등락률상위요청 | 동시호가 구간 |
ka00190 | 대량체결상위 | 대량 거래 감지 |
ka00196 | 체결금액대별매매비중 | 참여 주체 성격 추정 |
ka04196 | 수익률상위고객매매상세 | 참고용 |
공통 경로는 POST /api/dostk/rkinfo 이고, 방식은 다른 키움 REST API 와 같습니다. 도메인은 실전이 https://api.kiwoom.com, 모의투자가 https://mockapi.kiwoom.com 입니다.
2. 요청 실물 — 경로와 api-id 는 한 쌍이다
키움 REST API 는 URL 경로 하나에 여러 TR 을 묶고 api-id 헤더로 구분합니다. 이 구조 때문에 “잘 되던 코드에서 api-id 문자열만 바꾸면 되겠지”가 통하지 않습니다.
import requests
BASE = "https://api.kiwoom.com" # 모의투자는 https://mockapi.kiwoom.com
# ★ 경로와 api-id 를 한 쌍으로 묶어 둔다. 문자열만 갈아 끼우다 사고가 난다.
TR = {
"ka10030": "/api/dostk/rkinfo", # 당일거래량상위
"ka10032": "/api/dostk/rkinfo", # 거래대금상위
"ka00198": "/api/dostk/stkinfo", # 실시간종목조회순위 — 경로가 다르다
}
def call(api_id: str, body: dict, token: str, cont_yn="N", next_key=""):
url = BASE + TR[api_id]
headers = {
"Content-Type": "application/json;charset=UTF-8",
"authorization": f"Bearer {token}",
"api-id": api_id,
"cont-yn": cont_yn,
"next-key": next_key,
}
resp = requests.post(url, headers=headers, json=body, timeout=10)
resp.raise_for_status() # ← 이것만으로는 업무 오류를 못 잡는다
data = resp.json()
# ★ 키움은 업무 오류도 HTTP 200 으로 내려준다. return_code 를 반드시 본다.
rc = data.get("return_code")
if rc not in (0, None):
raise RuntimeError(f"키움 {api_id} 오류 rc={rc} msg={data.get('return_msg')}")
return data, resp.headers.get("cont-yn"), resp.headers.get("next-key")
실패가 예외로 안 잡힙니다. 경로와 api-id 가 어긋나도 서버는 HTTP 200 을 돌려주고 본문의 return_code 에만 오류가 담깁니다. resp.ok 나 raise_for_status() 만 걸어 둔 코드는 빈 리스트를 정상 응답으로 오해하고, 그 빈 목록이 전략까지 흘러가 “오늘은 조건에 맞는 종목이 없었다”로 조용히 끝납니다. 같은 함정을 키움 REST 주문 kt10000 편에서도 다뤘습니다.
자주 보는 업무 오류는 아래와 같습니다. 8050 은 코드 문제가 아니라 PC 등록 문제라, 개발자가 몇 시간을 코드에서 찾다가 결국 키움 포털에서 해결하는 대표적인 코드입니다.
| 코드 | 의미 | 실제로 해야 하는 일 |
|---|---|---|
1511 | 필수 파라미터 누락 | 바디 필드명 오타 확인(대소문자·언더스코어) |
8050 | 지정단말기 인증 실패 | 키움 OpenAPI 포털 → 마이페이지 → 단말기 관리에서 그 PC 를 등록 |
8051 | 시간 만료 | 접근토큰 재발급 |
8052 | IP 제한 | 서버 IP 가 바뀌었는지 확인(VPS 이전 시 자주 발생) |
8005 | 토큰이 유효하지 않음 | 같은 앱키로 다른 곳에서 토큰을 재발급했는지 확인 |
3. ka00198 의 qry_tp — 실시간이라는 이름의 1분 지연
ka00198 실시간종목조회순위는 이름에 ‘실시간’이 들어 있지만 WebSocket 이 아니라 REST 요청입니다. 요청 바디는 사실상 qry_tp 하나뿐인데, 이 값이 갱신 주기를 결정합니다.
| qry_tp | 집계 구간 | 비고 |
|---|---|---|
1 | 1분 | 공식 예제가 보여 주는 값 |
2 | 10분 | |
3 | 1시간 | |
4 | 당일 누적 | 장 전체 기준 |
5 | 30초 | HTS 영웅문 화면과 같은 주기 |
# 실측 응답(값은 예시). item_inq_rank 배열로 온다.
{
"item_inq_rank": [
{"stk_cd": "005930", "stk_nm": "삼성전자", "bigd_rank": "1",
"past_curr_prc": "75000", "base_comp_chgr": "+1.2",
"dt": "20260501", "tm": "123445"},
{"stk_cd": "000660", "stk_nm": "SK하이닉스", "bigd_rank": "2", "...": "..."}
],
"return_code": 0,
"return_msg": "정상적으로 처리되었습니다"
}
실제로 났던 사고입니다. 알고랩의 키움 REST 순위·뉴스 알림 납품 건에서 qry_tp 를 공식 예제대로 1 로 두고 운영했더니, 알림이 HTS 화면보다 1분씩 늦게 나갔습니다. 서버는 정상이고 폴링도 정상인데 데이터 자체가 1분 단위 집계였던 것입니다. “실시간”이라는 TR 이름이 30초 갱신을 보장하지 않습니다 — qry_tp="5" 로 바꾼 뒤에야 화면과 맞았습니다.
응답의 dt·tm 은 데이터가 만들어진 시각입니다. 폴링 결과를 신뢰할 수 있는지 확인하려면 응답을 받은 로컬 시각이 아니라 이 두 필드를 로그에 남기십시오. 값이 계속 같으면 갱신 주기 안에서 헛돌고 있다는 뜻입니다.
4. 순위 TR 에는 WebSocket 이 없다 — 폴링을 서버 시각에 맞춘다
키움 REST API 의 WebSocket 은 0B 주식체결, 0D 호가잔량 같은 종목 단위 실시간과 00 주문체결 통보, 04 잔고 통보를 다룹니다. 순위 계열은 등록 대상이 아니라서 REST 폴링만 가능합니다. 이 구조에서 흔한 실수는 “빠르게 받으려고 5초마다 호출”하는 것입니다. 서버가 30초마다 계산하므로 같은 값을 여섯 번 받고 호출 한도만 태웁니다.
더 골치 아픈 쪽은 PC 시계입니다. 실제 납품 PC 에서 NTP 동기화가 꺼져 있어 30초 지연이 고정으로 생긴 사례가 있었습니다. 매번 경계 직전에 호출하니 항상 직전 구간 값을 받았고, 로그만 보면 폴링은 정상이었습니다. 해결은 응답 헤더의 Date 로 서버 시각을 잡아 경계 직후에 호출하는 것입니다.
import time
from email.utils import parsedate_to_datetime
_offset = 0.0 # 서버시각 - 로컬시각
def sync_clock(resp):
"""응답 헤더 Date 로 서버 시각과의 차이를 잡아 둔다."""
global _offset
d = resp.headers.get("Date")
if d:
_offset = parsedate_to_datetime(d).timestamp() - time.time()
def next_wait(interval=30, buffer=1.5):
"""서버 시각 기준 다음 갱신 경계 + buffer 까지 대기한다."""
server_now = time.time() + _offset
boundary = ((int(server_now) // interval) + 1) * interval + buffer
return max(1.0, boundary - server_now)
while market_open():
data, _, _ = call("ka00198", {"qry_tp": "5"}, token)
rows = data.get("item_inq_rank") or []
if rows:
log.info("순위 갱신 dt=%s tm=%s 1위=%s",
rows[0]["dt"], rows[0]["tm"], rows[0]["stk_nm"])
else:
log.warning("순위 응답이 비어 있음 — return_code 와 장 운영시간 확인")
time.sleep(next_wait(30))
순위 응답이 비는 경우도 예외가 아니라 정상 상태일 수 있습니다. 장이 열리지 않은 날이 대표적입니다. 휴장일 판별은 KRX 휴장일 확인과 봇 스케줄링에서 다뤘고, 호출 한도 자체의 설계는 API 호출 제한 설계와 키움 REST 429 대응을 참고하십시오.
5. HTS 화면과 목록이 다를 때
같은 시각에 조회했는데 영웅문 화면과 목록이 다르면, 대개 조회 조건 파라미터가 기본값으로 들어간 것입니다. ka10020 호가잔량상위요청의 경우 바디에 거래량 구분 trde_qty_tp, 종목 조건 stk_cnd, 신용 조건 crd_cnd 같은 필드가 있습니다. HTS 화면에서는 사람이 상단 콤보박스로 골랐던 값들입니다.
enum 값을 추측해서 넣지 마십시오. 키움 명세의 코드 값은 한국어 표로 되어 있고, 잘못된 값을 넣어도 호출은 통과하는 경우가 있습니다. 그러면 에러 없이 ‘다른 조건의 목록’이 돌아오고, 이건 에러보다 나쁩니다. 조건 파라미터는 반드시 공식 가이드의 표를 보고 넣은 뒤, 같은 시각에 HTS 화면과 상위 5종목을 눈으로 대조해 한 번 검증하십시오.
또 하나 자주 놓치는 것은 거래소 구분입니다. 국내에 넥스트레이드(NXT)가 들어오면서 같은 종목이 거래소별로 나뉘어 집계될 수 있고, 종목코드에 접미사가 붙는 응답도 있습니다. 이 부분은 NXT·KRX 주문 라우팅에 정리해 뒀습니다.
붙이기 전 체크리스트
순위 조회를 봇에 넣기 전에 다섯 줄만 확인하십시오.
- 경로와
api-id를 한 쌍으로 상수화했는가(rkinfo/stkinfo혼동 방지) - 모든 응답에서
return_code를 먼저 확인하는가 ka00198의qry_tp가 의도한 주기인가(30초는5)- 폴링 시각을 응답 헤더
Date로 보정하는가 - 조건 파라미터를 넣고 HTS 화면과 한 번 대조했는가
고지. 이 글은 기술 자료이며 특정 종목·전략을 권유하지 않습니다. 본문의 api-id·경로·응답 필드는 키움증권 공식 API 가이드와 알고랩 납품 프로젝트의 실측을 대조해 정리했지만, 증권사 API 스펙은 예고 없이 바뀌므로 실제 파라미터 값과 코드 표는 반드시 키움증권 공식 문서에서 다시 확인하십시오. 알고랩(퀀트웍스)은 투자자문업·투자일임업을 영위하지 않으며, 고객이 지정한 규칙을 프로그램으로 구현해 드리는 도구 제공자입니다.