AlgoLab Blog · 트러블슈팅 · 2026 최신

KIS API 에러코드 완전 정리 — EGW00201·토큰 만료부터 주문 오류까지

KIS · 한국투자 2026-05-25 · 약 10분 읽기 · 알고랩 AlgoLab
한 줄 요약 KIS API 에러의 90%는 ① 호출 제한 초과(EGW00201) ② 토큰 만료(EGW00121) ③ tr_id 환경 불일치 ④ 입력값 누락 4가지에서 나옵니다. 이 글은 알고랩이 40건+ KIS 봇을 제작하며 모은 자주 막히는 에러코드 11가지를 증상·원인·해결 코드로 정리한 트러블슈팅 가이드입니다.

KIS API(한국투자증권 Developers)로 자동매매를 만들 때, 코드가 멈추는 지점은 거의 정해져 있습니다. 토큰이 만료되거나, 호출이 너무 잦거나, tr_id를 잘못 썼거나 — 그리고 그때마다 EGW00201 같은 알 수 없는 코드가 응답에 찍힙니다.

이 글은 KIS API에서 자주 마주치는 에러코드 11가지를 카테고리별로 정리했습니다. 지금 받은 에러코드를 아래 목차에서 찾아 바로 이동하셔도 됩니다. 발급 단계부터 처음 시작하신다면 → KIS API 발급부터 첫 주문까지 30분을 먼저 보세요.

이 글에서 해결하는 11가지

  1. 먼저 알 것 — 응답 구조(rt_cd / msg_cd / msg1)
  2. EGW00201 — 초당 거래건수 초과
  3. EGW00121 — 토큰이 유효하지 않음
  4. EGW00123 — 기간이 만료된 토큰
  5. EGW00133 — 토큰 발급 요청 과다
  6. tr_id 오류 — 실전/모의 혼동
  7. 모의투자 미지원 TR
  8. 계좌번호 형식 오류
  9. SetInputValue 필수값 누락
  10. 해외주식 권한·거래소 코드 오류
  11. 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
국내주식 현금 매수TTTC0802UVTTC0802U
국내주식 현금 매도TTTC0801UVTTC0801U
국내주식 정정·취소TTTC0803UVTTC0803U

해결: 환경 플래그로 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 사용 동의를 안 했거나 ② 거래소 코드를 잘못 지정.

해결:

미국 프리마켓 자동매매처럼 해외주식 자동화의 실전 사례는 → 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가지 습관

자주 묻는 질문

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시간 빠른 답변 가능합니다.

무료 상담 시작하기