증권사 REST API 파이썬 자동매매 첫걸음 — 인증·토큰·잔고조회 개념
자동매매를 해보겠다고 마음먹은 사람 상당수가 전략 코드는커녕 첫 API 호출도 못 해보고 멈춘다. 전략이 어려워서가 아니라, 증권사 API의 "인증"이라는 첫 관문이 웹 로그인과 전혀 다르게 생겼기 때문이다. 그래서 이번 글은 그 관문 하나 — 토큰 발급과 잔고 조회 — 를 통과하는 데 집중한다.
이 글의 범위
증권사마다 REST API의 세부 스펙(엔드포인트 이름, 파라미터, 헤더 형식)은 조금씩 다르다. 이 글은 특정 증권사의 실제 엔드포인트나 계좌 정보를 다루지 않는다.
대신 국내 대부분의 증권사 REST API가 공통으로 따르는 일반적인 흐름—토큰 발급, 인증 헤더 구성, 잔고 조회—을 개념과 의사코드 위주로 정리한다. 실제 연동은 반드시 해당 증권사가 공개한 공식 API 문서를 기준으로 진행해야 한다.
증권사 API 인증 흐름 — App Key·Secret부터 접근토큰까지
시세를 보거나 주문을 넣기 전에, API 서버에 "나는 이 계좌의 소유자다"라는 걸 증명해야 한다. 낯설어 보이지만 뜯어보면 대부분 OAuth 2.0과 비슷한 패턴을 따른다.
일반적인 흐름은 이렇다.
- 증권사 개발자센터에서 앱을 등록하고 App Key / App Secret 같은 식별자 쌍을 발급받는다
- 이 식별자 쌍으로 접근 토큰(Access Token) 발급을 요청한다
- 발급받은 토큰을 이후 모든 요청의 헤더에 실어서 보낸다
- 토큰에는 유효기간이 있어서, 만료되면 재발급받아야 한다
여기서 App Key/Secret이나 토큰은 비밀번호와 동급으로 취급해야 한다. 코드에 하드코딩하거나 공개 저장소에 커밋하면 안 되고, 환경변수나 별도 설정 파일(그리고 그 파일을 .gitignore에 반드시 추가)로 분리해서 관리하는 게 표준적인 방식이다.
접근토큰 발급과 만료·재발급 자동화 — 의사코드
python 코드 보기
import os
class BrokerAuthClient:
def __init__(self, app_key: str, app_secret: str, base_url: str):
self.app_key = app_key
self.app_secret = app_secret
self.base_url = base_url
self._token = None
self._token_expires_at = None
def get_access_token(self) -> str:
"""토큰이 없거나 만료됐으면 재발급, 아니면 캐시된 토큰 반환"""
if self._token and not self._is_expired():
return self._token
response = self._request_new_token()
self._token = response["access_token"]
self._token_expires_at = response["expires_at"]
return self._token
def _request_new_token(self) -> dict:
"""실제로는 증권사 API 문서에 명시된 토큰 발급 엔드포인트에 POST"""
raise NotImplementedError
def _is_expired(self) -> bool:
raise NotImplementedError
# 사용 예 — 키는 반드시 환경변수 등 외부에서 주입
auth = BrokerAuthClient(
app_key=os.environ["BROKER_APP_KEY"],
app_secret=os.environ["BROKER_APP_SECRET"],
base_url="https://api.example-broker.com",
)os.environ["BROKER_APP_KEY"]처럼 환경변수에서 읽어오게 만들어두면, 코드 자체에는 어떤 민감정보도 남지 않는다. 이 패턴은 특정 증권사가 아니라 REST API 인증을 다루는 대부분의 서비스에 공통으로 적용된다. 실제 증권사(키움) 기준으로 이 절차를 그대로 구현한 기록은 키움 REST API 접근토큰 발급과 관리에 있다.
Bearer 인증 헤더로 잔고·예수금 조회하기 — 의사코드
토큰을 받았으면 이후 요청에는 그 토큰을 헤더에 실어 보낸다. 잔고 조회도 마찬가지다.
python 코드 보기
class AccountClient:
def __init__(self, auth_client: BrokerAuthClient):
self.auth_client = auth_client
def get_balance(self, account_no_masked: str) -> dict:
token = self.auth_client.get_access_token()
headers = {
"Authorization": f"Bearer {token}",
"appkey": self.auth_client.app_key,
}
# 실제로는 requests.get(url, headers=headers, params=...) 형태
response = self._call_balance_endpoint(headers, account_no_masked)
return {
"cash": response["cash"],
"holdings": response["holdings"],
}
def _call_balance_endpoint(self, headers, account_no_masked):
raise NotImplementedError잔고 조회 응답에는 보통 예수금(현금), 보유 종목별 수량과 평가금액이 담긴다. 이 데이터를 앞서 다룬 리스크 관리 로직(포지션 한도 계산 등)의 입력값으로 쓰는 게 자연스러운 다음 단계다. 실제 응답 필드를 파싱해 잔고를 읽어낸 과정은 키움 REST API로 잔고·계좌평가 조회하기에 정리했다.
증권사 API 처음 연동할 때 자주 하는 실수 4가지
- 키를 코드에 직접 적어 커밋하는 것: 한 번 공개 저장소에 올라가면 즉시 무효화하고 재발급해야 한다. 이력에서 지우는 것만으로는 부족하다.
- 토큰 만료를 고려하지 않는 것: 장시간 실행되는 자동매매 프로세스는 토큰이 중간에 만료될 수 있다는 걸 전제로, 재발급 로직을 반드시 넣어야 한다.
- 모의투자(페이퍼 트레이딩) 환경과 실전 환경의 엔드포인트를 혼동하는 것: 대부분의 증권사는 두 환경의 base URL이 다르다. 실전 URL로 잘못 요청을 보내는 실수는 생각보다 흔하다.
- 응답 에러 처리를 생략하는 것: 네트워크 오류, 토큰 만료, 요청 한도 초과 등 다양한 실패 케이스가 있는데 "성공"만 가정하고 코드를 짜면 조용히 잘못된 상태로 흘러갈 수 있다.
오늘의 정리
- 증권사 REST API 인증은 대체로 App Key/Secret으로 토큰을 발급받고, 이후 요청 헤더에 그 토큰을 싣는 공통 패턴을 따른다.
- 키와 토큰은 코드가 아니라 환경변수 등 외부에서 주입하는 구조로 처음부터 설계해야 한다.
- 잔고 조회는 인증만 되면 비교적 단순하지만, 그 결과값을 리스크 관리 로직에 연결하는 지점부터가 진짜 설계다.
다음 글에서는 이렇게 얻은 데이터와 전략을 실전에 투입하기 전, 반드시 거쳐야 하는 백테스팅이 무엇이고 왜 없으면 위험한지를 개념 위주로 다뤄본다.
이 글의 코드는 개념 설명을 위한 의사코드이며, 특정 증권사의 실제 엔드포인트·계좌·API 키를 담고 있지 않습니다. 실제 연동은 해당 증권사가 공개한 공식 API 문서를 기준으로 진행하시기 바랍니다. 이 글은 투자 조언이 아니며 특정 종목이나 매매기법을 추천하지 않습니다. 수익을 보장하지 않으며, 투자 손실에 대한 책임은 투자자 본인에게 있습니다.