키움 REST API 종가가 HTS와 다른 이유

키움 REST API 종가가 HTS와 다른 이유

키움 REST API 종가가 HTS와 달랐다. 2026년 9월 21일 월요일 저녁, 그날 받은 값을 처음으로 HTS와 나란히 놓고 맞춰 본 날이다. SK하이닉스 종가가 API에서는 1,879,000원, HTS에서는 1,878,000원이었다.

같은 자리에서 코스피 지수도 틀렸다. 7,007.72여야 할 값이 그 100배로 저장돼 있었다.

어느 쪽도 API가 틀린 값을 준 것은 아니었다. 그 숫자가 어느 시장에서 찍힌 값인지, 몇 배 단위인지를 내가 몰랐을 뿐이다. 이 글을 읽고 나면 종목코드 뒤 접미사가 무엇을 고르는지, 기본 일봉의 지난 종가가 어느 시장의 값인지, 응답의 숫자 칸을 어떻게 읽어야 하는지 알 수 있다.

먼저 결론

키움 REST API 일봉(`ka10081`)은 그날 저녁에 받으면 오후 3시 30분의 거래소 종가를 준다. HTS 기본 화면은 저녁 8시까지 이어지는 넥스트레이드 체결을 합친 통합 값이다. 그날 저녁 두 값이 다른 이유다.

지난 봉이 되면 키움 일봉의 종가도 넥스트레이드 마지막 체결로 바뀌어 HTS와 같아진다. 대신 이번엔 거래소 종가와 달라진다.

지수는 100을 곱한 정수로, 종목은 원 단위로 온다. 같은 `cur_prc`라는 칸 이름에 TR마다 다른 것이 담긴다.

키움 REST API의 숫자는 어느 시장 값인지 말해 주지 않는다

[키움 REST API] 응답은 전부 문자열이다. 문서는 칸 이름과 설명 한 줄을 줄 뿐, 그 숫자가 어느 시장에서 체결된 값인지 몇 배 단위인지는 적혀 있지 않다.

2025년 3월 넥스트레이드가 문을 연 뒤로 하루의 종가는 하나가 아니다. 오후 3시 30분에 끝나는 거래소 정규장의 종가가 있고, 저녁 8시까지 이어지는 넥스트레이드의 마지막 체결이 있고, 거래소와 넥스트레이드를 합친 통합 시세가 있다.

더 곤란한 건 시가와 거래량이 거래소 값과 한 자리까지 같다는 점이다. 몇 종목만 골라 맞춰 보면 그냥 통과해 버린다. 나는 바로 전날 [KRX API 종가가 증권사 화면과 달랐던 일]을 겪고도 원인을 끝까지 짚지 못했다.

키움 REST API 종가, 지난 봉은 넥스트레이드 마지막 체결이다

키움 종목코드는 뒤에 붙는 접미사로 시장을 고른다. SK하이닉스라면 이렇게 된다.

종목 코드받는 값
000660기본 – 아래에서 설명한다
000660_NX넥스트레이드
000660_AL통합 (HTS 기본 화면이 보여주는 값)
000660_KRX빈 응답 – 거래소 전용 코드는 없다

함정은 기본 코드였다. 9월 18일 봉을 보면 시가와 거래량은 거래소 공식 값과 같은데 종가가 1,849,000원이다. 거래소 종가는 1,857,000원이었고, `_NX`로 물었더니 1,849,000원이 나왔다. 지난 봉의 종가는 넥스트레이드에서 저녁 8시까지 이어진 마지막 체결이었던 셈이다. 주봉과 월봉도 마찬가지였다.

그날 봉은 또 사정이 달랐다. 9월 21일 저녁 8시 2분, 11분, 31분에 세 번 받았는데 종가는 세 번 다 1,879,000원, 거래소 종가 그대로였다. 지난 봉은 넥스트레이드 종가인데 그날 봉은 거래소 종가였으니, 어느 시점엔가 넥스트레이드 값으로 바뀐다고 봐야 한다. 같은 봉을 저녁과 다음 날 두 번 받아 확인한 것은 아니라서, 여기까지는 두 관측을 이은 추론이다.

그래서 받는 법을 바꿨다. 그날 저녁에 받은 종가를 적어 두고, 지난 종가는 키움에서 다시 가져오지 않는다. 다음 날 거래소 하루치 데이터로 적어 둔 값을 한 번 더 맞춰 보고, 어긋난 가격은 거래소 값으로 고친다.

키움 REST API 종가가 종목코드(기본 · _NX · _AL)와 받는 시각에 따라 어느 시장의 값이 되는지 그린 시간축
키움 REST API 종가가 종목코드(기본 · _NX · _AL)와 받는 시각에 따라 어느 시장의 값이 되는지 그린 시간축 – 기본 코드는 그날 저녁에는 거래소 종가를, 지난 봉에서는 넥스트레이드 종가를 준다.

숫자 칸마다 어느 시장의 몇 배 값인지 적어 두고 읽는다

키움 REST API 응답은 종가 말고도 칸마다 사정이 달랐다. 실제로 받아 보고 확인한 것만 옮긴다.

– `ka10001`(주식기본정보)의 `cur_prc`는 통합 값이다. 그날의 기준가 `base_pric`은 전날 거래소 종가에서 나오고, HTS 통합 화면의 등락률도 이 기준가를 분모로 쓴다.

– 같은 `ka10001`의 가격 칸에는 `+3120`, `-1680`처럼 부호가 붙는다. 이 부호는 오르내린 방향일 뿐 음수가 아니라서, `-1680`은 1,680원이다.

– 지수 일봉 `ka20006`은 100을 곱한 정수 문자열로 온다. `”700772″`가 7,007.72다. 종목 일봉 `ka10081`은 원 단위다.

– 종목 일봉에는 등락률 칸이 없다. 같은 행의 `pred_pre`(전일 대비)는 종가와 맞지 않아서, 등락률은 전날 행의 종가로 직접 구한다.

그래서 숫자를 읽는 함수는 모르는 모양이 오면 조용히 넘기지 않고 멈추게 했다. 지금 지수 수집기에 들어 있는 코드다(주석은 조금 줄였다).

def _parse_index_x100(value: str) -> int:

    """`ka20006` 의 지수 문자열을 곱하지 않고 그대로 정수로 읽는다.

    부호·소수점·콤마 없는 숫자만 온다(600봉 전부 실측) — 숫자가 아닌 문자가 섞이면

    조용히 넘기지 않고 예외로 드러낸다.

    """

    if not value.isdigit():

        raise ValueError(f"ka20006 지수 값이 숫자만이 아니다: {value!r}")

    return int(value)

소수점이나 부호가 하나라도 섞이면 여기서 예외가 난다. 단위를 잘못 알고 있다는 신호를, 틀린 값이 저장되기 전에 받는 셈이다.

시험은 다 통과했는데 지수가 100배였다

지수 수집기는 처음에 `”7007.72″` 같은 소수 문자열이 온다고 보고, 거기에 100을 곱해 정수로 저장하게 짜여 있었다. 구현은 Claude Code에 맡겼다. 실제 응답을 받아 보기 전이라 시험용 응답도 문서의 칸 이름을 보고 지어 넣었는데, 그 응답이 소수 문자열이었다. 지어낸 응답 위에서 시험은 전부 통과했다.

실제 응답은 이미 100을 곱한 정수였다. 수집기는 거기에 100을 한 번 더 곱했고, 월요일 저녁 첫 실호출 뒤 HTS와 맞춰 보는 자리에서야 그게 드러났다. 시험이 다 통과해도 틀린 것을 잡은 건 매일 보는 HTS 화면이었다.

고치는 일은 간단했다. 지어낸 응답을 지우고 실제 응답 70봉을 녹화해 시험을 그 위로 옮겼다. 이제는 9월 21일 종가 `700772`가 HTS의 7,007.72와 같다는 것을 시험이 직접 확인한다.

민망한 건 규칙이 이미 있었다는 점이다. 응답 모양은 지어내지 않고 녹화한다. 구현을 맡길 때부터 적어 둔 규칙인데, 이번엔 녹화가 구현 뒤로 밀리면서 지켜지지 않았다. 문서를 보고 지어낸 응답에는 내가 이미 믿고 있는 단위가 그대로 담기니, 바로 그 단위가 틀렸을 때 시험이 잡아 줄 리 없다.

그래서 규칙을 더하는 대신 순서를 바꿨다. 이제 녹화는 구현을 맡기기 전, 일을 나누는 단계에서 먼저 떠 둔다.

하루 전에 내린 결론이 뒤집혔다

키움 REST API 종가를 두고 처음 결론을 낸 것은 2026년 9월 20일이었다. 거래소 API와 키움 API의 종가를 2,762종목 전수로 맞춰 보니 2,330종목이 갈렸다. 그때 나는 HTS에 찍힌 삼성전자 9월 17일 종가 256,000원이 키움 쪽과 같다는 이유로 키움이 맞다고 정했다.

이튿날 접미사를 알고 나서 다시 보니, 그 256,000원은 HTS 통합 화면의 값이었다. 키움 일봉의 지난 종가도 넥스트레이드 값이었으니 두 값이 같았던 건 둘 다 거래소 종가가 아니어서였다. 84%가 갈린 것도 키움 쪽 지난 종가가 넥스트레이드 값이었기 때문으로 정리했다. 다만 넥스트레이드에서 거래되지 않는 종목까지 어긋났던 일은 아직 풀지 못했다.

결국 판단에 쓰는 종가는 거래소 종가로 돌아왔다. 다음 날 기준가와 상한가가 거래소 종가에서 나오고, 코스피 지수와 시점도 같기 때문이다. 원천은 여전히 키움이지만 어느 시장의 값을 적는지가 바뀌었다.

고가와 저가도 한 번 더 고쳤다. 처음엔 지난 봉의 시가·고가·저가·거래량이 거래소와 같다고 적었는데, 두 종목만 확인한 결과였다. 나흘 뒤 전종목으로 맞춰 보니 고가와 저가는 약 2할이 달랐고, 지금은 지난 날의 고가와 저가도 거래소 값으로 적는다.

결과와 한계

2026년 10월 현재 저녁 배치는 그날 종가를 키움 기본 코드로 받아 적고, 다음 날 거래소 하루치로 종가·고가·저가·거래량을 맞춰 본다. 가격이 어긋나면 거래소 값으로 고쳐 적고, 거래량은 어긋난 수만 센다. 종목 차트는 아직 짓는 중인데, 키움이 주는 대로 그리기로 정해 두었다. 지난 봉 종가가 넥스트레이드 값이라는 걸 알고 쓰는 것이고, 차이는 대개 1% 안이다.

아직 모르는 것도 있다. 그날 종가가 언제 넥스트레이드 값으로 덮이는지 재지 못했고, 그날 저녁 봉의 고가와 저가가 거래소 값인지도 확인하지 않았다. 거래량을 거래소 것만 세면서 빠지는 넥스트레이드 몫이 큰 종목에서는 3분의 1쯤 되는데, 그게 신호에 어떤 영향을 주는지는 쓰면서 볼 생각이다.

무엇을 어디까지 만들었는지는 [RichRich 프로젝트 페이지]에 정리해 두고 있다. [키움 REST API로 어떤 데이터를 받는지]는 앞선 글에 있다. 토큰이 거부되고 호출이 막혔던 일은 따로 정리하고 있다.

숫자를 믿기 전에, 그 숫자가 어느 시장에서 언제 찍힌 값인지부터 묻는다.

이 글의 요약

키움 REST API 일봉의 종가는 그날 저녁에 받으면 거래소 종가이고, 지난 봉이 되면 넥스트레이드 마지막 체결이다.

HTS 기본 화면은 넥스트레이드를 합친 통합 값이라, 그날 저녁에 받은 키움 REST API 종가와 다르다.

지수는 100을 곱한 정수로, 종목은 원 단위로 오고, `ka10001` 가격 칸의 부호는 방향을 뜻한다.

지어낸 시험용 응답으로는 단위 착오를 못 잡아서, 실제 응답을 녹화해 HTS와 맞춰 본다.

자주 묻는 것

키움 REST API 종가가 HTS와 다른 이유는 뭔가?

그날 저녁에 받은 키움 REST API 종가는 오후 3시 30분의 거래소 종가이고, HTS 기본 화면은 저녁 8시까지의 넥스트레이드 체결을 합친 통합 값이기 때문이다. 지난 봉이 되면 키움 일봉의 종가도 넥스트레이드 마지막 체결이라 HTS와 같아지고, 대신 거래소 종가와 달라진다.

거래소 정규장 종가만 받으려면 어떻게 하나?

키움에는 거래소 전용 과거 일봉 코드가 없다(`_KRX`는 빈 응답). 나는 그날 저녁 기본 코드로 받은 종가를 적어 두고 다음 날 거래소 데이터로 맞춰 본다.

키움 REST API 지수 값은 어떤 단위로 오나?

`ka20006`은 지수를 100을 곱한 정수 문자열로 준다. `”700772″`가 7,007.72다. 받는 쪽에서 소수로 알고 한 번 더 곱하면 100배가 된다.

이 기록을 쓰는 사람에 대해서는 [소개]에 적어두었다.

  • 이 글은 개인의 학습·개발 기록이며 투자 권유가 아닙니다.
  • 투자 판단과 그 결과는 투자자 본인에게 있습니다.