전체 흐름 한눈에 보기
자동매매 시스템을 키움 REST API로 구축하려면 아래 단계를 순서대로 밟아야 합니다. 각 단계가 이전 단계의 결과물을 입력으로 받기 때문에, 한 단계라도 빠뜨리면 다음 단계에서 오류가 발생합니다.
| 단계 | 작업 | 사용 API / 도구 | 결과물 |
|---|---|---|---|
| 0단계 — 계좌 준비 | 키움증권 계좌 개설, 공동인증서 발급 | 키움증권 홈페이지·영웅문S# 앱 | 계좌번호 |
| 1단계 — API 사용 신청 | REST API 사용 등록, AppKey·SecretKey 발급, 운영 IP 등록 | openapi.kiwoom.com → API 사용신청 | AppKey, SecretKey |
| 2단계 — 개발 환경 구성 | Python 3.10 이상 설치, 가상환경 생성, requests·websocket-client·python-dotenv 설치 | pip, venv | 프로젝트 폴더 |
| 3단계 — 접근토큰 발급 | AppKey+SecretKey로 OAuth 토큰 발급 | au10001 POST /oauth2/token | Bearer 토큰 (24시간 유효) |
| 4단계 — 시세 데이터 조회 | 현재가·호가·차트(일봉/분봉) 조회 | ka10001, ka10002, ka10080, ka10081 등 | 종목 시세 JSON |
| 5단계 — 실시간 데이터 수신 | WebSocket 연결로 체결가·호가 스트리밍 | wss://api.kiwoom.com:10000 | 실시간 틱 데이터 |
| 6단계 — 전략 엔진 구현 | 수집 데이터 기반 매매 신호 생성 | pandas, numpy, ta-lib 등 | BUY/SELL 신호 |
| 7단계 — 주문 실행 | 매수·매도·정정·취소 주문 전송 | kt10000, kt10001, kt10002, kt10003 | 주문번호 |
| 8단계 — 잔고·체결 확인 | 계좌 평가 잔고, 체결 내역 조회 | kt00018, kt00007 | 포지션 상태 |
| 9단계 — 리스크 관리 | 손절/익절, 최대 손실 한도, 포지션 사이징 | 자체 로직 + kt10002/kt10003 | 리스크 리포트 |
| 10단계 — 모니터링·로깅 | 전체 시스템 상태 감시, 에러 알림, 거래 기록 | logging, Telegram/Slack Bot | 운영 대시보드 |
이 표의 각 단계를 아래에서 하나씩 상세히 풀어 설명합니다.
1. 키움 REST API란 무엇인가
키움 REST API는 2025년 3월 키움증권이 출시한 차세대 트레이딩 인터페이스입니다. 기존 Open API+는 Windows 전용 ActiveX(OCX) 기반이라 32비트 Python에 PyQt의 QAxContainer가 필수였고, macOS나 Linux에서는 사용 자체가 불가능했습니다. REST API는 이 제약을 해결하기 위해 표준 HTTP(S) 프로토콜 위에 설계되었으며, 운영체제와 프로그래밍 언어에 구애받지 않고 어디서든 호출할 수 있습니다.
핵심 특징을 정리하면 다음과 같습니다. 모든 요청은 POST 메서드를 사용하고, Content-Type은 application/json;charset=UTF-8으로 고정됩니다. 운영 도메인은 https://api.kiwoom.com이고, 모의투자 도메인은 https://mockapi.kiwoom.com이며 모의투자는 KRX 종목만 지원합니다. 실시간 데이터는 WebSocket을 사용하며, 운영 주소는 wss://api.kiwoom.com:10000, 모의투자 주소는 wss://mockapi.kiwoom.com:10000입니다. 응답 포맷은 모두 JSON이며, 인증은 OAuth 2.0 Client Credentials 방식을 따릅니다.
2. 작동 원리 — 요청-응답 사이클 상세 분해
키움 REST API의 모든 통신은 하나의 일관된 패턴을 따릅니다. 이 패턴을 이해하면 시세 조회든 주문이든 모두 같은 구조로 코딩할 수 있습니다.
첫째, 클라이언트가 Header에 authorization(Bearer 토큰)과 api-id(TR 코드)를 세팅합니다. 둘째, Body에 해당 TR이 요구하는 파라미터를 JSON으로 담아 POST 요청을 보냅니다. 셋째, 서버가 응답 Header에 cont-yn(연속조회여부)과 next-key(연속조회키)를 돌려주고, Body에 데이터를 JSON으로 반환합니다. 넷째, cont-yn이 Y이면 next-key 값을 다음 요청 Header에 실어 다시 POST를 보내 나머지 데이터를 수신합니다. 이 연속조회(페이징) 메커니즘 덕분에 대량 데이터도 끊기지 않고 받을 수 있습니다.
TR 코드는 기능별로 접두어가 다릅니다. au로 시작하면 인증(au10001 토큰 발급, au10002 토큰 폐기), ka로 시작하면 조회(ka10001 현재가, ka10002 호가, ka10080 분봉, ka10081 일봉, ka10171 조건검색 목록 등), kt로 시작하면 거래(kt10000 매수, kt10001 매도, kt10002 정정, kt10003 취소, kt00018 잔고 조회 등)입니다.
3.0단계 — 계좌와 API 사용 신청
키움증권 비대면 계좌를 개설한 뒤, openapi.kiwoom.com에 접속하여 REST API 사용을 신청합니다. 신청 과정에서 모의투자용 AppKey·SecretKey와 실전투자용 AppKey·SecretKey가 각각 발급됩니다. 실전투자 키는 발급 횟수가 제한되므로 반드시 안전한 곳에 저장해야 합니다. 실전투자의 경우 API를 호출할 서버의 공인 IP를 사전에 등록해야 하며, 미등록 IP에서 요청하면 인증 오류가 발생합니다. 모의투자는 IP 등록이 필요 없으므로 개발 초기에는 모의투자 환경에서 시작하는 것이 안전합니다.
4.1단계 — 개발 환경 구성
REST API는 HTTP 통신이므로 별도의 OCX 모듈 설치가 필요 없습니다. Python 3.10 이상이면 충분하고, Windows·macOS·Linux 어디서든 동작합니다. 프로젝트를 다음과 같이 구성합니다.
KiwoomTrader/
├── venv/ # 가상환경
├── cfg/
│ └── risk_config.yaml # 리스크 규칙
├── secrets/
│ └── .env # AppKey, SecretKey, Token
├── src/
│ ├── auth.py # 토큰 발급·갱신
│ ├── market_data.py # 시세·차트 조회
│ ├── realtime.py # WebSocket 실시간
│ ├── order.py # 주문 실행
│ ├── account.py # 잔고·체결 조회
│ ├── strategy.py # 전략 엔진
│ └── monitor.py # 모니터링·알림
├── logs/
├── main.py
└── requirements.txt
requirements.txt에는 requests, websocket-client, python-dotenv, pandas, numpy를 기록합니다. 가상환경을 만들고 패키지를 설치하는 명령은 다음과 같습니다.
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install requests websocket-client python-dotenv pandas numpy
5.2단계 — 접근토큰(Access Token) 발급
접근토큰은 키움 API 서버에 본인을 증명하는 전자 열쇠입니다. 모든 API 호출의 Header에 이 토큰을 Bearer 형식으로 포함시켜야 합니다. 토큰은 발급 후 24시간 뒤 만료되므로, 자동매매 시스템에서는 만료 시점 5분 전에 자동으로 재발급하는 로직을 반드시 구현해야 합니다.
토큰 발급 API의 사양은 다음과 같습니다. TR 코드는 au10001이고, URL은 /oauth2/token입니다. Body에 grant_type(고정값 client_credentials), appkey, secretkey 세 필드를 보내면, 서버가 token(접근토큰 문자열), token_type(Bearer), expires_dt(만료일시, 예: 20250806151009 형태), return_code(0이면 성공), return_msg를 반환합니다.
파이썬 구현 예시입니다.
import os, json, requests
from datetime import datetime
from dotenv import load_dotenv
load_dotenv("secrets/.env")
class KiwoomAuth:
def __init__(self, is_mock=True):
self.host = "[https://mockapi.kiwoom.com](https://mockapi.kiwoom.com)" if is_mock else "[https://api.kiwoom.com](https://api.kiwoom.com)"
self.app_key = os.getenv("KIWOOM_APP_KEY")
self.secret_key = os.getenv("KIWOOM_SECRET_KEY")
self.token = None
self.expires_dt = None
def issue_token(self):
url = f"{self.host}/oauth2/token"
headers = {"Content-Type": "application/json;charset=UTF-8"}
body = {
"grant_type": "client_credentials",
"appkey": self.app_key,
"secretkey": self.secret_key
}
resp = requests.post(url, headers=headers, json=body)
data = resp.json()
if data.get("return_code") == 0:
self.token = f"Bearer {data['token']}"
self.expires_dt = datetime.strptime(data["expires_dt"], "%Y%m%d%H%M%S")
return True
raise Exception(f"토큰 발급 실패: {data.get('return_msg')}")
def get_token(self):
from datetime import timedelta
if self.token is None or datetime.now() >= self.expires_dt - timedelta(minutes=5):
self.issue_token()
return self.token
.env 파일은 다음과 같이 작성합니다.
KIWOOM_APP_KEY=발급받은앱키
KIWOOM_SECRET_KEY=발급받은시크릿키
토큰 발급 시 가장 흔한 오류는 실전투자 환경에서 IP 미등록(401/403 응답)입니다. openapi.kiwoom.com의 계좌 App Key 관리 화면에서 현재 서버의 공인 IP가 등록되어 있는지 반드시 확인해야 합니다.
6.3단계 — 시세 데이터 조회
시세 조회는 REST 방식으로 이루어집니다. 대표적인 TR 코드와 용도를 정리하면, ka10001은 주식 기본정보(현재가, 전일대비, 거래량 등), ka10002는 주식 호가(매수·매도 10단계), ka10080은 주식 분봉차트(1분/3분/5분/10분/15분/30분/60분), ka10081은 주식 일봉차트, ka00198은 실시간 종목 조회 순위입니다.
일봉 차트를 조회하는 파이썬 예시입니다.
def get_daily_chart(auth, stock_code, base_date="20260318"):
url = f"{auth.host}/api/dostk/chart"
headers = {
"Content-Type": "application/json;charset=UTF-8",
"authorization": auth.get_token(),
"api-id": "ka10081"
}
body = {
"stk_cd": stock_code,
"base_dt": base_date,
"adj_prc_tp": "1" # 수정주가 반영
}
resp = requests.post(url, headers=headers, json=body)
return resp.json()
연속조회가 필요한 경우(데이터가 많아 한 번에 다 안 올 때)에는 응답 Header의 cont-yn이 Y인지 확인하고, Y이면 next-key 값을 다음 요청 Header에 실어 반복 호출합니다.
def get_full_chart(auth, stock_code, tr_id="ka10081"):
all_data = []
cont_yn = "N"
next_key = ""
while True:
headers = {
"Content-Type": "application/json;charset=UTF-8",
"authorization": auth.get_token(),
"api-id": tr_id,
"cont-yn": cont_yn,
"next-key": next_key
}
body = {"stk_cd": stock_code, "base_dt": "20260318", "adj_prc_tp": "1"}
resp = requests.post(f"{auth.host}/api/dostk/chart", headers=headers, json=body)
all_data.extend(resp.json().get("data", []))
cont_yn = resp.headers.get("cont-yn", "N")
next_key = resp.headers.get("next-key", "")
if cont_yn != "Y":
break
import time; time.sleep(0.25) # 초당 5회 제한 준수
return all_data
7.4단계 — WebSocket 실시간 데이터 수신
차트나 현재가 조회는 요청할 때마다 한 번의 스냅샷을 돌려주지만, 자동매매에서는 가격이 변할 때마다 즉시 반응해야 합니다. 이를 위해 키움은 WebSocket 프로토콜을 통한 실시간 스트리밍을 제공합니다.
WebSocket 연결 주소는 운영 환경 wss://api.kiwoom.com:10000, 모의투자 wss://mockapi.kiwoom.com:10000이며, 경로는 /api/dostk/websocket입니다. 연결 후 원하는 TR 코드와 종목코드를 JSON으로 보내면, 해당 종목의 체결가·호가가 실시간으로 스트리밍됩니다. 조건검색 실시간(ka10174)을 활용하면 영웅문4에서 만든 조건검색식에 편입/이탈되는 종목을 실시간으로 받을 수 있어, 종목 발굴과 주문을 하나의 파이프라인으로 연결할 수 있습니다.
import websocket, json
def on_message(ws, message):
data = json.loads(message)
print(f"실시간 수신: {data}")
def on_open(ws):
# 실시간 체결가 등록 예시
subscribe = {"trnm": "REGSRT", "stk_cd": "005930"}
ws.send(json.dumps(subscribe))
ws_url = "wss://mockapi.kiwoom.com:10000/api/dostk/websocket"
ws = websocket.WebSocketApp(ws_url, on_open=on_open, on_message=on_message)
ws.run_forever()
8.5단계 — 주문 실행
주문 관련 TR 코드는 네 가지입니다. kt10000은 매수, kt10001은 매도, kt10002는 정정, kt10003은 취소입니다. 주문 유형은 총 15가지를 지원하며, 실무에서 가장 많이 쓰는 것은 지정가(00)와 시장가(03)입니다.
주문 요청의 Header에는 authorization(Bearer 토큰)과 api-id(TR 코드)가 필수이고, Body에는 계좌번호, 종목코드, 주문수량, 주문가격(시장가일 때는 0), 주문유형 등을 담습니다.
def place_buy_order(auth, stock_code, qty, price=0, order_type="03"):
url = f"{auth.host}/api/dostk/order"
headers = {
"Content-Type": "application/json;charset=UTF-8",
"authorization": auth.get_token(),
"api-id": "kt10000"
}
body = {
"acnt_no": os.getenv("KIWOOM_ACCOUNT"),
"stk_cd": stock_code,
"order_qty": str(qty),
"order_prc": str(price),
"hoga_tp": order_type # 00:지정가, 03:시장가
}
resp = requests.post(url, headers=headers, json=body)
return resp.json()
정정 주문(kt10002)은 원래 주문번호(orgn_ord_no)와 새로운 가격·수량을 보내고, 취소 주문(kt10003)은 원래 주문번호와 취소 수량을 보냅니다. 네트워크 재시도 시 중복 주문을 방지하려면 멱등성 키(Idempotency Key)를 Header에 추가하는 것이 좋습니다.
9.6단계 — 잔고 및 체결 확인
주문을 낸 뒤에는 실제로 체결되었는지, 현재 보유 종목의 평가 금액은 얼마인지 확인해야 합니다. kt00018(계좌평가잔고내역요청)은 보유 종목별 매입가, 현재가, 평가손익, 수익률을 반환하고, kt00007(계좌별주문체결내역상세요청)은 당일 주문 내역과 체결 상태를 반환합니다. 이 두 TR을 주기적으로 호출하여 포지션 현황을 최신 상태로 유지하는 것이 자동매매의 핵심입니다.
10. API 호출 시 반드시 지켜야 하는 제약 조건
키움 REST API는 초당 최대 5회의 요청을 허용합니다. 이 제한은 시세 조회와 주문 모두에 적용되며, 초과하면 HTTP 429(Too Many Requests) 응답을 받습니다. 안정적인 운영을 위해 요청 간격을 200~300밀리초로 유지하는 것이 권장됩니다. 또한 일부 소스에서는 REST API의 일일 요청 횟수가 약 30회로 제한된다는 언급이 있으나, 이는 특정 TR이나 베타 시기의 정책일 수 있으므로 공식 FAQ(openapi.kiwoom.com)에서 최신 정보를 확인해야 합니다.
토큰은 24시간 유효하며, 만료 후에는 기존 토큰이 즉시 무효화됩니다. 장 운영 중에 토큰이 만료되면 주문 실패로 직결되므로, 만료 5분 전 자동 갱신 로직은 필수입니다.
11. 자동매매 시스템의 5계층 아키텍처
실전 자동매매 시스템은 다섯 개의 독립적인 계층으로 분리하여 설계하는 것이 유지보수와 장애 대응에 유리합니다.
첫째, 데이터 수집 계층은 REST API로 일봉·분봉 과거 데이터를 수집하고, WebSocket으로 실시간 체결가·호가를 수신합니다. 둘째, 전략 엔진 계층은 수집된 데이터에 기술적 지표(이동평균, MACD, RSI, 볼린저 밴드 등)를 적용하여 매수·매도 신호를 생성합니다. 셋째, 주문 실행 계층은 신호를 받아 kt10000/kt10001로 주문을 전송하고, 체결 결과를 감시합니다. 넷째, 리스크 관리 계층은 포지션 사이징(계좌 대비 최대 비율), 종목당 최대 수량, 손절선(stop-loss), 익절선(take-profit), 일일 최대 손실 한도, 갭 가드(전일 대비 시가 갭이 일정 비율 초과 시 진입 포기) 등을 관장합니다. 다섯째, 모니터링 계층은 모든 요청·응답·에러를 로그로 남기고, 이상 상황 발생 시 Telegram이나 Slack으로 알림을 보냅니다.
이 다섯 계층을 느슨하게 결합(loose coupling)하면, 전략을 바꿀 때 주문 로직을 건드리지 않아도 되고, 장애가 발생해도 해당 계층만 재시작할 수 있습니다.
12. 주요 오류 코드와 대응법
키움 REST API에서 자주 만나는 오류와 대응법을 정리합니다. return_code가 0이 아닌 경우 오류이며, HTTP 상태 코드와 함께 return_msg에 원인이 기술됩니다. 401이나 403 응답은 토큰 만료 또는 IP 미등록을 의미하므로 토큰 재발급과 IP 화이트리스트를 점검합니다. 429 응답은 초당 요청 제한 초과이므로 요청 간격을 늘려야 합니다. 500/502/503/504 응답은 서버 측 일시 장애이므로 지수 백오프(2초, 4초, 8초)로 재시도합니다. Open API+ 시절의 오류코드 중 -200(시세 과부하), -308(주문전송 과부하)은 REST API에서는 HTTP 상태 코드로 대체되지만, return_msg에 유사한 메시지가 포함될 수 있으므로 로그를 반드시 남겨야 합니다.
13. 기존 Open API+와의 비교
키움 Open API+는 2016년경 출시된 COM/OCX 방식의 레거시 API로, Windows 32비트 환경에서만 동작하고 PyQt의 QAxContainer를 통해 파이썬과 연동합니다. 해외주식을 포함한 폭넓은 TR을 지원하지만, OS 제약이 가장 큰 단점입니다. REST API는 2025년 3월 출시되어 플랫폼 독립적이나, 현재 국내 주식(KRX·NXT)과 ETF/ETN만 지원하며 해외주식 거래는 불가합니다. 따라서 해외주식 자동매매가 필요하면 한국투자증권(KIS) API를 대안으로 검토하거나, 키움 Open API+를 Windows 환경에서 병행 사용해야 합니다.
14. AI와 LLM 접목 방안
키움증권은 자체적으로 AI 코딩 어시스턴트 서비스를 제공하고 있습니다. 2025년 5월 출시된 이 서비스는 ChatGPT-4o-mini와 RAG 기술을 기반으로, 자연어로 원하는 기능을 설명하면 키움 REST API 호출 코드를 자동 생성해 줍니다. Python, Java, JavaScript 등을 지원하며 별도 설치 없이 openapi.kiwoom.com에서 바로 사용할 수 있습니다.
자체 AI/LLM을 접목하는 방법도 있습니다. 뉴스·공시·SNS 데이터를 GPT 계열 모델로 감성 분석하여 매수·매도 보조 신호로 활용하거나, 과거 체결 데이터를 학습시킨 시계열 예측 모델(LSTM, Transformer)로 단기 가격 방향을 예측하는 접근이 가능합니다. 다만, 어떤 AI 모델도 미래 주가를 확실히 예측할 수는 없으므로, AI 신호는 기존 기술적 분석의 보조 도구로만 사용하고 반드시 리스크 관리 계층을 거치도록 설계해야 합니다.
15. 운영 시 팁과 주의사항
모의투자를 충분히 거친 뒤 실전에 진입해야 합니다. 모의투자에서는 슬리피지(주문가와 실제 체결가의 차이)가 발생하지 않지만, 실전에서는 호가 스프레드와 거래량에 따라 의미 있는 차이가 생기므로, 전략의 기대 수익률에서 슬리피지 비용을 반드시 차감해야 합니다.
장 운영 시간 외에도 시스템이 오동작하지 않도록 KRX 영업일 캘린더를 관리하고, 반일장(설·추석 전날 등)에는 장 마감 시각이 달라지므로 이를 반영해야 합니다. 서버 시간대는 Asia/Seoul(KST)로 고정하고, 모든 타임스탬프를 KST 기준으로 기록하면 디버깅이 수월합니다.
거래 수수료는 국내 주식 기준 약 0.015%이며, 거래세가 별도로 부과됩니다. API 사용 자체에는 추가 비용이 없지만, 사용하는 AI 모델의 API 호출 비용은 별도입니다.
16. 모의투자로 시작하는 실전 연습
키움 REST API의 모의투자 환경은 실제 시장 데이터를 기반으로 동작하되, 가상의 자금으로 주문을 낼 수 있는 샌드박스입니다. 모의투자 도메인(mockapi.kiwoom.com)에서는 KRX 종목만 지원되고, NXT 종목은 조회되지 않습니다. 모의투자에서 충분히 전략을 검증한 뒤, 도메인만 api.kiwoom.com으로 바꾸고 IP를 등록하면 실전으로 전환됩니다.