[튜토리얼] 키움 REST API로 잔고·계좌평가 조회하기
이 글의 범위
이 시리즈는 개발자 등록·앱 키 발급과 접근토큰 발급·관리를 거쳐 이제 마지막 단계인 잔고·계좌평가 조회를 다룬다. 실제 계좌번호, 실제 응답 데이터, 정확한 필드명은 담지 않는다. 이 글은 "잔고 조회 API가 대체로 어떤 구조로 동작하는가"라는 개념을 공개 문서 수준에서 정리한 것이며, 정확한 요청 파라미터와 필드명은 키움증권 공식 API 문서에서 확인해야 한다.
잔고 조회가 자동매매에서 왜 중요한가
시세를 보고 전략을 판단하는 것과, 실제로 "지금 내가 얼마를 갖고 있고 무엇을 보유하고 있는지" 아는 것은 다른 문제다. 자동매매 시스템이 신뢰할 수 있는 매매 판단을 하려면, 매 사이클마다 최신 잔고와 보유 종목 상태를 확인하고 그 값을 근거로 다음 행동(추가 매수 가능 금액, 손절 대상 여부 등)을 계산해야 한다. 잔고 조회는 이 파이프라인의 입력값을 만드는 지점이다.
일반적인 요청 구조
앞서 발급받은 접근토큰을 인증 헤더에 실어, 잔고 조회 엔드포인트에 요청을 보내는 게 공통 패턴이다. 대체로 아래와 같은 정보가 요청에 포함된다.
- 인증 헤더 (
Authorization: Bearer {토큰}등) - 조회 대상 계좌 구분 (모의투자/실전, 계좌번호 — 여기서는 마스킹된 형태로만 다룬다)
- 조회 옵션 (예수금만 조회할지, 보유 종목 평가까지 포함할지 등 세부 파라미터)
python 코드 보기
class AccountClient:
def __init__(self, auth_client, base_url: str):
self.auth_client = auth_client
self.base_url = base_url
def get_balance(self, account_no_masked: str) -> dict:
headers = {
"Authorization": f"Bearer {self.auth_client.get_access_token()}",
"appkey": self.auth_client.app_key,
}
params = {"account_no": account_no_masked}
# 실제로는 requests.get(url, headers=headers, params=params) 형태
raw = self._call_balance_endpoint(headers, params)
return self._normalize(raw)
def _call_balance_endpoint(self, headers, params) -> dict:
raise NotImplementedError
def _normalize(self, raw: dict) -> dict:
"""증권사마다 조금씩 다른 응답 필드를 우리 시스템 내부 표준 형태로 변환."""
return {
"cash": raw.get("cash", 0),
"holdings": raw.get("holdings", []),
"total_eval_amount": raw.get("total_eval_amount", 0),
}응답에 보통 담기는 개념적 필드
정확한 필드명은 문서마다 다르지만, 국내 증권사 REST API의 잔고 조회 응답은 대체로 아래 범주의 정보를 담는다.
- 예수금(현금): 매수에 바로 쓸 수 있는 현금성 자산
- 보유 종목 목록: 종목코드, 보유 수량, 평균 매입 단가 등
- 종목별 평가금액/평가손익: 현재가 기준으로 계산된 평가금액과 매입가 대비 손익
- 계좌 전체 평가금액: 예수금과 보유 종목 평가액을 합산한 총 자산
이 필드들의 정확한 이름과 단위(원 단위인지, 소수점 처리 방식인지 등)는 반드시 공식 문서로 확인해야 한다. 여기서 임의로 필드명을 지어내지 않는 이유는, 실제로 다른 이름이나 단위를 쓰는 증권사가 존재하고, 잘못된 가정으로 코드를 짜면 조용히 틀린 계산을 하게 되기 때문이다.
조회 결과를 리스크 관리에 연결하기
잔고 조회 자체는 단순한 GET 요청이지만, 진짜 설계는 그 결과를 어떻게 쓰느냐에 있다. 예를 들어 아래와 같은 로직이 잔고 조회 결과 위에 얹힌다.
python 코드 보기
def check_position_limit(balance: dict, max_position_ratio: float) -> bool:
"""단일 종목 평가금액이 전체 자산 대비 한도를 넘지 않는지 확인."""
total = balance["total_eval_amount"]
if total <= 0:
return True
for h in balance["holdings"]:
if h["eval_amount"] / total > max_position_ratio:
return False
return True이런 식으로 잔고 조회 결과를 매매 실행 전 사전 점검 단계의 입력으로 쓰면, "이번 주문이 리스크 한도를 넘는지"를 주문을 넣기 전에 걸러낼 수 있다.
잔고 조회에서 자주 하는 실수
- 조회 빈도를 과도하게 높이는 것: 매 초마다 잔고를 조회하면 API 호출 한도(rate limit)에 걸리기 쉽다. 매매 판단 주기에 맞춰 적절한 간격으로 조회하는 게 안전하다.
- 응답 지연이나 실패를 고려하지 않는 것: 네트워크 문제로 잔고 조회가 실패했는데, 이전에 캐시해둔 값을 그대로 최신값처럼 쓰면 위험한 판단으로 이어질 수 있다. 조회 실패 시에는 "판단을 보류"하는 편이 조회 실패를 무시하는 것보다 안전하다.
- 모의투자 잔고와 실전 잔고를 같은 변수/로그에 뒤섞는 것: 테스트 중 모의투자 잔고 값을 실전 잔고인 것처럼 로그에 남기면, 나중에 디버깅할 때 두 환경을 혼동하기 쉽다. 로그에 항상 환경 구분(paper/live)을 같이 남기는 습관이 필요하다.
- 평가금액을 실시간 시세와 동기화하지 않고 오래된 값으로 판단하는 것: 잔고 조회 응답의 평가금액은 조회 시점 기준이라는 걸 항상 인지하고, 그 사이의 시세 변동 가능성을 계산에 반영해야 한다.
오늘의 정리
- 잔고 조회는 접근토큰을 헤더에 실어 보내는 인증된 GET 요청이며, 응답에는 예수금·보유 종목·평가금액 등의 정보가 담긴다.
- 정확한 필드명과 단위는 증권사마다 다르므로 반드시 공식 문서로 확인하고, 임의로 가정하지 않는다.
- 잔고 조회의 진짜 가치는 그 결과를 리스크 관리 로직(포지션 한도 점검 등)의 입력으로 연결하는 지점에서 나온다.
키움 REST API 시리즈의 개발자 등록부터 인증, 잔고 조회까지 세 편을 통해 기본 흐름을 정리했다. 이후 시세조회나 주문 실행 같은 다음 단계는 별도 시리즈로 다룰 예정이다.
이 글은 키움증권이 공개한 개발자 문서 수준의 일반적인 잔고 조회 절차를 정리한 것이며, 실제 계좌번호·API 응답·평가금액 등을 담고 있지 않습니다. 실제 연동은 반드시 키움증권 공식 API 문서를 기준으로 진행하시기 바랍니다. 이 글은 투자 조언이 아니며 특정 종목이나 매매기법을 추천하지 않습니다. 수익을 보장하지 않으며, 투자 손실에 대한 책임은 투자자 본인에게 있습니다.