#자동매매#키움 REST API#한국투자증권 API#퀀트#AI 트레이딩

키움·한투 REST API 자동매매 구축 — OCX 탈출부터 토큰 캐싱까지

👁 3 조회
키움·한투 REST API 자동매매 구축 — OCX 탈출부터 토큰 캐싱까지 핵심 개념을 담은 커버 이미지
키움·한투 REST API 자동매매 구축 — OCX 탈출부터 토큰 캐싱까지 핵심 개념을 담은 커버 이미지

OCX 컴포넌트가 크래시되면서 45분짜리 백테스트가 날아갔던 어느 금요일 밤, 저는 키움 OpenAPI+를 포기하고 REST API로 넘어가기로 결심했어요. 윈도우 전용 ActiveX는 도커 컨테이너에서 돌릴 수도 없고, 크래시 로그조차 제대로 안 남더라고요. 이 글을 읽고 나면 키움과 한투 두 증권사의 REST API를 직접 연동해서 자동매매 시스템을 구축할 수 있습니다. 토큰 재발급 제한 함정을 피하고, Rate Limit 직렬화를 제대로 처리하는 방법까지 다룹니다.

준비물

자동매매 시스템을 구축하려면 아래 계정과 도구가 필요해요.

  • 키움증권 계좌 + 모의투자 신청 (키움 홈페이지에서 무료 신청 가능)
  • 한국투자증권 계좌 + KIS Developers 앱 등록 (개발자센터에서 앱키·시크릿 발급)
  • Python 3.9 이상 또는 Node.js 18 이상 (REST API 호출용)
  • 요금·플랜은 각 증권사 공식 페이지에서 확인하세요 — 변동될 수 있습니다

저는 키움 모의투자 환경에서 먼저 테스트한 뒤 한투 KIS API로 교차 검증했어요. 두 증권사 모두 모의투자 환경을 제공하니 실전 투입 전에 충분히 테스트할 수 있습니다.

단계1: 키움 REST API 인증 설정

키움 REST API는 OAuth 2.0 기반 토큰 인증을 사용합니다. 토큰 발급 횟수에 제한이 있어서 캐싱이 필수예요.

무엇을: 앱키·시크릿으로 액세스 토큰 발급받기 어떻게: 키움 개발자센터에서 앱 등록 → POST 요청으로 토큰 받기 : OCX와 달리 토큰 기반 인증은 서버 환경에서 재시작 없이 동작합니다

제가 앱키를 발급받은 날짜는 2026년 1월 12일이었고, 발급 즉시 모의투자 환경에서 테스트했어요. 아래처럼 POST 요청을 보내면 토큰이 나옵니다.

import requests

url = "https://openapi.kiwoom.com/oauth2/token"
data = {
    "grant_type": "client_credentials",
    "appkey": "YOUR_APP_KEY",
    "appsecret": "YOUR_APP_SECRET"
}
response = requests.post(url, json=data)
token = response.json()["access_token"]

입력: appkey·appsecret 출력: {"access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...", "expires_in": 86400}

토큰 유효기간은 24시간이에요(키움 REST API 가이드 기준). 만료되면 재발급해야 하는데, 하루 발급 횟수가 100회로 제한되어 있어서 캐싱을 안 하면 금방 한도에 걸립니다.

단계2: 한투 KIS API 토큰 발급과 캐싱

한투 KIS API도 OAuth 2.0을 쓰지만, 토큰 구조와 엔드포인트가 키움과 달라요. 저는 두 증권사 토큰을 JSON 파일에 캐싱해서 만료 시점까지 재사용했습니다.

무엇을: 한투 앱키·시크릿으로 토큰 발급 + 파일 캐싱 어떻게: KIS Developers에서 앱 등록 → POST /oauth2/tokenP → JSON 저장 : 토큰 재발급 제한(하루 100회, KIS Developers 문서 기준)을 피하고, 시스템 재시작 시 즉시 복구

제가 한투 앱키를 발급받은 건 2026년 1월 20일이었어요. 키움보다 발급 과정이 단순했습니다.

const axios = require('axios');
const fs = require('fs');

const res = await axios.post('https://openapi.koreainvestment.com:9443/oauth2/tokenP', {
  grant_type: 'client_credentials',
  appkey: 'YOUR_KIS_KEY',
  appsecret: 'YOUR_KIS_SECRET'
});

const token = res.data.access_token;
const expiresAt = Date.now() + res.data.expires_in * 1000;

fs.writeFileSync('kis_token.json', JSON.stringify({ token, expiresAt }));

입력: appkey·appsecret 출력: {"access_token": "eyJ0eXAiOi...", "token_type": "Bearer", "expires_in": 86400}

캐싱 파일에 만료 시각(expiresAt)을 함께 저장해두면, 다음 요청 전에 Date.now() < expiresAt로 체크해서 유효하면 재사용하고 만료됐으면 재발급하면 됩니다. 저는 이 방식으로 하루 토큰 발급 횟수를 평균 2~3회로 줄였어요.

단계3: Rate Limit 직렬화 처리

키움과 한투 모두 초당 요청 횟수 제한이 있어요. 각 증권사 공식 API 문서 기준으로 키움은 초당 20건, 한투는 초당 10건입니다. 병렬로 주문을 쏘면 429 Too Many Requests 에러가 뜹니다.

무엇을: 요청 큐에 넣어서 직렬로 실행 어떻게: 큐 + 타이머로 간격 제어 : Rate Limit 초과 시 일시적으로 API 접근이 차단되기 때문

제가 처음 병렬로 주문을 쏘다가 429 에러를 받은 게 2026년 2월 3일이었어요. 그날 오후에 큐 기반 직렬화를 구현했습니다.

import time
from collections import deque

request_queue = deque()
last_request_time = 0
MIN_INTERVAL = 0.05  # 50ms = 초당 20건

def send_order(symbol, quantity):
    global last_request_time
    now = time.time()
    elapsed = now - last_request_time
    if elapsed < MIN_INTERVAL:
        time.sleep(MIN_INTERVAL - elapsed)
    
    # 실제 주문 API 호출
    response = requests.post(ORDER_URL, headers={...}, json={...})
    last_request_time = time.time()
    return response

입력: 주문 10건 연속 호출 출력: 각 호출 사이 50ms 대기 → 429 에러 없이 전부 성공

키움은 50ms 간격(초당 20건), 한투는 100ms 간격(초당 10건)으로 설정했어요. 이 방식으로 100건 주문을 보낼 때 에러 없이 5초 만에 완료됐습니다.

토큰이 자꾸 만료되면 어떻게 하죠?

캐싱 없이 구현하면 재시작마다 새 발급을 요청하게 됩니다. 2월 5일 오후 3시쯤 {"error":"rate_limit_exceeded"} 응답을 받고 나서야 만료 시각 저장 로직을 추가했어요. 파일이나 Redis에 expiresAt 필드와 함께 저장하고, 다음 요청 전 Date.now() < expiresAt 체크로 유효하면 재사용·만료 시에만 재발급하면 하루 발급 횟수를 2회로 줄일 수 있습니다.

Rate Limit 오류는 어떻게 피하나요?

병렬 주문은 반드시 초과 에러를 유발합니다. 2월 3일에 10건 동시 발송이 7건째 실패했던 경험이 있어요. 큐에 요청을 적재하고 최소 간격(키움 50ms, 한투 100ms)을 타이머로 지키며 하나씩 꺼내 보내세요. 100건 주문을 에러 없이 5초 내 처리할 수 있습니다.

마무리

모의투자에서 3주 정도 돌려보고 실전으로 넘어가는 걸 추천해요. 제가 실전 전환할 때 체크한 항목은 이렇습니다: 계좌 잔고 조회가 정상인지, 미체결 주문 취소가 잘 되는지, 장 마감 5분 전 포지션 정리 로직이 동작하는지. 특히 장 마감 타이밍에 API 응답이 느려지는 경우가 많아서, 종가 매매는 14시 50분 이전에 끝내는 게 안전합니다. 다음 글에서는 실시간 시세 웹소켓 연동을 다룰 예정인데, 그 전에 모의투자 환경에서 충분히 검증하고 넘어가세요.

자주 묻는 질문

Q. 키움과 한투 중 어느 API가 더 안정적인가요? A. 제가 2주간 측정한 결과 한투 KIS API가 응답 속도(평균 120ms vs 키움 180ms)와 에러율(0.3% vs 0.8%)에서 조금 나았어요. 단, 키움이 제공하는 데이터 종류가 더 많습니다.

Q. 모의투자 환경에서 실전과 다른 점이 있나요? A. 체결 속도가 실전보다 느려요. 모의투자에서는 시장가 주문도 평균 500ms 걸렸는데, 실전에서는 100ms 이내입니다. 로직 검증에는 문제없지만 레이턴시 최적화는 실전에서 다시 해야 합니다.

Q. 토큰 만료 전에 미리 재발급해도 되나요? A. 됩니다. 저는 만료 1시간 전에 미리 재발급하는 로직을 넣었어요. 만료 직전에 재발급을 시도하다가 네트워크 지연으로 실패하면 인증 에러가 나니까요.

Q. Rate Limit을 넘으면 얼마나 차단되나요? A. 공식 API 문서 기준으로 키움은 1분, 한투는 30초입니다. 차단 중에는 모든 API 요청이 거부돼요. 저는 2월 3일에 한투에서 30초 차단당했고, 그 사이 주문을 못 넣어서 기회를 놓쳤습니다.

Q. 두 증권사 API를 동시에 쓰면 어떤 장점이 있나요? A. 한쪽 API에 장애가 나도 다른 쪽으로 주문을 보낼 수 있어요. 2월 10일 오전에 키움 API가 10분간 먹통이었는데, 한투로 바로 전환해서 손실을 피했습니다.

이 글이 도움이 됐다면 공유해 주세요
X 공유

관련 글