KIS API 에러코드 완전 정리 — EGW00201·토큰 만료부터 주문 오류까지
KIS API(한국투자증권 Developers)로 자동매매를 만들 때, 코드가 멈추는 지점은 거의 정해져 있습니다. 토큰이 만료되거나, 호출이 너무 잦거나, tr_id를 잘못 썼거나 — 그리고 그때마다 EGW00201 같은 알 수 없는 코드가 응답에 찍힙니다.
이 글은 KIS API에서 자주 마주치는 에러코드 11가지를 카테고리별로 정리했습니다. 지금 받은 에러코드를 아래 목차에서 찾아 바로 이동하셔도 됩니다. 발급 단계부터 처음 시작하신다면 → KIS API 발급부터 첫 주문까지 30분을 먼저 보세요.
이 글에서 해결하는 11가지
- 먼저 알 것 — 응답 구조(rt_cd / msg_cd / msg1)
- EGW00201 — 초당 거래건수 초과
- EGW00121 — 토큰이 유효하지 않음
- EGW00123 — 기간이 만료된 토큰
- EGW00133 — 토큰 발급 요청 과다
- tr_id 오류 — 실전/모의 혼동
- 모의투자 미지원 TR
- 계좌번호 형식 오류
- SetInputValue 필수값 누락
- 해외주식 권한·거래소 코드 오류
- hashkey 누락 (주문 API)
0. 먼저 알 것 — KIS 응답 구조
KIS API의 모든 응답에는 3개의 표준 필드가 있습니다. 에러 진단은 항상 이 순서로 합니다.
| 필드 | 의미 | 해석 |
|---|---|---|
rt_cd | 처리 결과 코드 | 0 = 성공, 그 외 = 실패 |
msg_cd | 메시지 코드 | EGW00201 등 — 원인 식별용 |
msg1 | 메시지 문자열 | 사람이 읽는 설명 |
def check_response(res):
"""KIS 응답 표준 검증"""
data = res.json()
if data.get("rt_cd") != "0":
msg_cd = data.get("msg_cd", "?")
msg1 = data.get("msg1", "").strip()
raise RuntimeError(f"KIS 에러 [{msg_cd}] {msg1}")
return data
봇의 모든 호출을 이 함수로 감싸면, 에러가 났을 때 어떤 코드인지 즉시 로그에 남습니다. 진단의 출발점입니다.
호출 제한 에러
1EGW00201 — 초당 거래건수를 초과하였습니다
증상: 처음 몇 번은 잘 되다가 갑자기 EGW00201로 응답이 막힘.
원인: KIS API는 초당 호출 제한이 있습니다. 실전투자 초당 약 20건, 모의투자 초당 약 1건입니다. 빠른 루프로 여러 종목 시세를 연속 조회하면 초과합니다.
해결: time.sleep 단순 대기보다, 호출 간격을 일정하게 유지하는 Rate Limiter를 두는 것이 안전합니다.
import time
class RateLimiter:
def __init__(self, calls_per_sec):
self.interval = 1.0 / calls_per_sec
self.last = 0.0
def wait(self):
gap = time.time() - self.last
if gap < self.interval:
time.sleep(self.interval - gap)
self.last = time.time()
# 실전: limiter = RateLimiter(15) # 20건 한도에 안전 마진
# 모의: limiter = RateLimiter(0.8) # 1건 한도
# 사용: 매 호출 직전
limiter.wait()
res = requests.get(url, headers=headers, params=params)
💡 모의투자가 더 빡빡합니다: 모의투자는 초당 약 1건이라, 모의에서 잘 돌던 다종목 봇이 실전에서 다르게 동작하거나 그 반대가 흔합니다. Rate Limiter 값을 환경별로 분리하세요.
토큰·인증 에러
2EGW00121 — 토큰이 유효하지 않습니다
증상: 어제까지 잘 되던 봇이 다음 날 갑자기 인증 오류.
원인: KIS 액세스 토큰은 발급 후 24시간이 지나면 만료됩니다. 만료된 토큰을 헤더에 넣으면 거부됩니다.
해결: 토큰을 캐시에 저장하고 23시간마다 자동 갱신합니다.
import os, json, time, requests
TOKEN_CACHE = ".kis_token.json"
def get_token_cached():
"""만료 임박 시 자동 갱신되는 토큰 반환"""
if os.path.exists(TOKEN_CACHE):
with open(TOKEN_CACHE) as f:
data = json.load(f)
if data["expires_at"] > time.time():
return data["token"]
# 만료 → 재발급
url = f"{os.getenv('KIS_BASE_URL')}/oauth2/tokenP"
body = {"grant_type": "client_credentials",
"appkey": os.getenv("KIS_APP_KEY"),
"appsecret": os.getenv("KIS_APP_SECRET")}
d = requests.post(url, json=body).json()
data = {"token": d["access_token"],
"expires_at": time.time() + 23 * 3600}
with open(TOKEN_CACHE, "w") as f:
json.dump(data, f)
return data["token"]
3EGW00123 — 기간이 만료된 token
증상: EGW00123 메시지와 함께 호출 거부.
원인: EGW00121과 사실상 같은 계열 — 토큰 유효기간 경과. 캐시에 저장한 토큰의 만료 시각 계산이 틀렸거나, 서버·로컬 시계 차이로 "아직 살아있다"고 오판한 경우입니다.
해결: 만료 마진을 넉넉히(23시간) 두고, EGW001 계열 에러를 받으면 캐시를 폐기하고 강제 재발급하는 폴백을 둡니다.
def call_with_retry(request_fn):
"""EGW001 계열 에러 시 토큰 강제 갱신 후 1회 재시도"""
try:
return request_fn(get_token_cached())
except RuntimeError as e:
if "EGW001" in str(e):
if os.path.exists(TOKEN_CACHE):
os.remove(TOKEN_CACHE) # 캐시 폐기
return request_fn(get_token_cached()) # 재발급 후 재시도
raise
4EGW00133 — 토큰 발급 요청 과다
증상: 토큰을 발급받으려는데 EGW00133 류의 거부.
원인: 토큰 발급 엔드포인트는 1분에 1회 이상 호출하면 차단됩니다. 매 API 호출마다 토큰을 새로 발급하면 바로 막힙니다.
해결: 위 2번의 캐시 패턴 필수. 토큰은 발급받아 재사용하는 자원이지, 매번 새로 만드는 게 아닙니다. 봇 전체에서 get_token_cached()만 호출하세요.
⚠️ 가장 흔한 초보 실수: "인증이 필요하니까" 매 함수마다 토큰을 새로 발급 → 몇 번 호출 후 EGW00133으로 전면 차단. 토큰은 1개를 받아 23시간 동안 돌려쓰는 것입니다.
환경·tr_id 에러
5tr_id 오류 — 실전/모의 혼동
증상: 시세 조회는 되는데 주문만 실패. 또는 모의에서 만든 코드가 실전에서 전부 실패.
원인: KIS는 거래성 호출마다 tr_id(거래 ID)를 헤더에 넣는데, 실전과 모의의 tr_id가 다릅니다.
| 거래 | 실전 tr_id | 모의 tr_id |
|---|---|---|
| 국내주식 현금 매수 | TTTC0802U | VTTC0802U |
| 국내주식 현금 매도 | TTTC0801U | VTTC0801U |
| 국내주식 정정·취소 | TTTC0803U | VTTC0803U |
해결: 환경 플래그로 tr_id를 자동 전환합니다.
def order_tr_id(side, paper=True):
if side == "buy":
return "VTTC0802U" if paper else "TTTC0802U"
if side == "sell":
return "VTTC0801U" if paper else "TTTC0801U"
raise ValueError(side)
6모의투자 미지원 TR
증상: tr_id를 모의용으로 정확히 넣었는데도 특정 호출만 실패.
원인: 일부 TR(특정 시세·해외·고급 주문 등)은 모의투자 환경 자체가 지원하지 않습니다. 모의에서 안 되는 기능을 모의에서 테스트하려 한 것입니다.
해결: 해당 기능은 실전 환경에서 최소 금액으로 검증합니다. KIS 공식 문서의 TR 목록에서 "모의투자 지원" 여부를 미리 확인하세요. 봇 설계 시 모의에서 검증 가능한 기능과 그렇지 않은 기능을 구분해 두는 것이 좋습니다.
입력값·계좌 에러
7계좌번호 형식 오류
증상: 주문·잔고 조회가 계좌 관련 메시지로 거부.
원인: KIS는 계좌번호를 종합계좌번호(CANO, 8자리)와 상품코드(ACNT_PRDT_CD, 2자리)로 분리해서 받습니다. 12345678-01을 통째로 넣으면 실패합니다.
ACCOUNT = "12345678-01"
CANO, ACNT_PRDT_CD = ACCOUNT.split("-")
# body 에 각각 따로 담는다
body = {"CANO": CANO, "ACNT_PRDT_CD": ACNT_PRDT_CD, ...}
8필수 입력값(파라미터) 누락
증상: rt_cd가 0이 아닌데 메시지가 모호함.
원인: TR마다 필수 파라미터가 다릅니다. 시세 조회의 FID_COND_MRKT_DIV_CODE, FID_INPUT_ISCD처럼 하나라도 빠지면 실패합니다.
해결: KIS 공식 문서의 해당 TR 요청 명세를 그대로 복사해 모든 필드를 채우세요. 빈 값이라도 키는 존재해야 하는 경우가 많습니다.
9hashkey 누락 — 주문 API
증상: 시세는 되는데 주문 호출이 거부되거나 위변조 관련 메시지.
원인: KIS의 주문성 POST 호출은 요청 body를 hashkey API로 먼저 해시화한 값을 헤더에 넣어야 하는 경우가 있습니다. 시세 조회(GET)에는 필요 없어 빠뜨리기 쉽습니다.
def get_hashkey(body):
url = f"{BASE_URL}/uapi/hashkey"
headers = {"content-type": "application/json",
"appkey": APP_KEY, "appsecret": APP_SECRET}
res = requests.post(url, headers=headers, data=json.dumps(body))
return res.json()["HASH"]
# 주문 호출 헤더에 추가
headers["hashkey"] = get_hashkey(body)
해외주식 에러
10해외주식 권한·거래소 코드 오류
증상: 국내주식은 다 되는데 해외주식 호출만 권한 오류.
원인: ① 한국투자증권 홈페이지에서 해외주식 API 사용 동의를 안 했거나 ② 거래소 코드를 잘못 지정.
해결:
- 한투 홈페이지 → 해외주식 API 사용 동의 체크
- 거래소 코드 정확히 지정:
NAS(나스닥),NYS(뉴욕),AMS(아멕스),HKS(홍콩),TSE(도쿄) 등
미국 프리마켓 자동매매처럼 해외주식 자동화의 실전 사례는 → KIS API 미국 프리마켓 자동손절 실전 제작기 참고.
11해외주식 시장가 주문 불가
증상: 해외주식 주문에 시장가(ORD_DVSN 시장가)를 넣으면 거부.
원인: KIS 해외주식은 시장가 주문을 지원하지 않거나 제한적입니다. 국내주식 코드를 그대로 해외에 적용한 경우입니다.
해결: 해외주식은 지정가 기반으로 설계하고, "시장가처럼" 빠른 체결이 필요하면 현재가 ± 슬리피지 폭의 지정가로 넣습니다.
빠른 진단 체크리스트
| 에러 / 증상 | 가장 흔한 원인 | 해결 번호 |
|---|---|---|
| EGW00201 | 초당 호출 초과 | 오류 1 |
| EGW00121 / EGW00123 | 토큰 만료 | 오류 2·3 |
| EGW00133 | 토큰 발급 과다 | 오류 4 |
| 주문만 실패 | tr_id 환경 불일치 / hashkey 누락 | 오류 5·9 |
| 모의에서 특정 기능만 실패 | 모의 미지원 TR | 오류 6 |
| 계좌 관련 거부 | 계좌번호 분리 안 함 | 오류 7 |
| 해외주식만 실패 | 해외 API 미동의 / 거래소 코드 | 오류 10·11 |
✅ 에러를 90% 줄이는 4가지 습관
- 모든 응답을
rt_cd로 검증하고msg_cd를 로그에 남긴다 - 토큰은 캐시해서 23시간 재사용한다 (절대 매번 발급 ❌)
- Rate Limiter를 환경별로 분리 적용한다
- tr_id는
paper플래그로 자동 전환한다
자주 묻는 질문
Q. EGW00201 에러는 무엇인가요?
초당 거래건수(호출량) 초과입니다. 실전 초당 약 20건, 모의 약 1건 한도. Rate Limiter로 호출 간격을 관리하세요.
Q. 토큰 만료(EGW00121)는 어떻게 막나요?
토큰은 24시간 후 만료됩니다. 캐시에 저장해 23시간마다 자동 갱신하고, EGW001 계열 에러 시 캐시 폐기 후 재발급하는 폴백을 두세요.
Q. 모의투자에서 주문이 안 됩니다.
tr_id가 실전/모의로 다릅니다(실전 TTTC···, 모의 VTTC···). 일부 TR은 모의 자체를 미지원합니다.
Q. rt_cd, msg_cd, msg1은 무엇인가요?
rt_cd=결과코드(0이면 성공), msg_cd=메시지코드(EGW00201 등), msg1=설명 문자열. rt_cd로 성패 판단 후 msg_cd로 원인을 찾습니다.
Q. 해외주식이 권한 오류로 거부됩니다.
한투 홈페이지에서 해외주식 API 사용 동의가 필요하고, 거래소 코드(NAS/NYS/AMS/HKS)를 정확히 지정해야 합니다.
마무리
KIS API 에러는 코드가 낯설어 막막해 보이지만, 실제로는 호출 제한·토큰·환경·입력값 4가지 카테고리로 거의 다 설명됩니다. 위 4가지 습관만 들이면 운영 중 에러가 90% 줄어듭니다.
에러 대응에 시간을 쏟기보다 전략에 집중하고 싶다면, 알고랩이 KIS API 발급부터 토큰 자동 갱신·에러 핸들링·24시간 무중단 운영까지 통합 제작해드립니다.
KIS 자동매매 봇 맞춤 제작
토큰 자동 갱신, 에러 핸들링, Rate Limit 관리, 24시간 무중단 운영까지 — 알고랩이 통합 패키지로 제작합니다.
24시간 빠른 답변 가능합니다.