시리즈: 토스증권 Open API로 나만의 포트폴리오 리포트 만들기
1편: 매일 쌓고, 과거는 복원하고 (이 글)
2편: Claude Code·Codex CLI로 종목 AI 분석 붙이기
토스증권 앱은 지금 상태를 보기엔 편하다. 그런데 "한 달 전 내 포트폴리오 수익률은 어땠지?", "이 종목 비중이 언제부터 이렇게 커졌지?" 같은 질문에는 답을 주지 않는다. 지나간 날의 계좌 상태가 남지 않기 때문이다.
토스증권이 Open API를 열었길래, 계좌와 보유종목을 매일 저장해 두는 개인용 리포트를 만들기로 했다. 목표는 단순하다.
개발은 거의 전부 Claude Code와 같이 했다. 계획 문서를 먼저 쓰게 하고, 확인한 다음 구현하는 식으로 진행했다.

혼자 쓰는 앱이라 운영할 게 많으면 금방 안 쓰게 된다. 그래서 처음부터 원칙을 정했다.
REAL이 아니라 API가 준 decimal 문자열을 TEXT로 저장하고 Decimal로 계산한다.배포는 Docker Compose로 web(gunicorn)과 batch(cron) 컨테이너 두 개만 띄운다. 웹은 배치가 채워 둔 SQLite를 읽기만 하고, 새로고침·호가창처럼 실시간이 필요한 것만 그때그때 토스 API를 부른다.

| 출처 | 가져오는 것 |
| 토스 Open API | 계좌, 보유종목, 시세, 일봉, 주문내역, 수급, 호가, 시장 캘린더, 랭킹 |
| pykrx | 국내 종목 PER/PBR 등 밸류에이션, 시가총액, ETF 정보, 지수 |
| DART | 종목별 최근 공시 |
| 토스 웹 화면 | 입출금, 배당금, 실현손익 (API에 없음) |
원칙은 "토스에서 얻을 수 있으면 토스 걸 쓴다"이다. pykrx는 토스에 없는 밸류에이션·ETF 정보만 보충한다.
배치는 각자 독립 실행되는 sync_*.py 스크립트로 나눴다. 시간대는 데이터가 실제로 준비되는 시점에 맞췄다.
| 시각(KST) | 작업 | 이유 |
| 08:00 | 계좌·보유종목 스냅샷 | 미장 마감 이후 |
| 08:15 | Trend Score 계산 | 국장·미장 당일 캔들이 다 반영된 뒤 |
| 08:25 | DART 공시 | 아침 배치 묶음에 같이 |
| 08:30 | SQLite 백업 | 앞 작업이 끝난 뒤 |
| 18:10 | pykrx 밸류에이션 | KRX가 장 마감 후에 공표 |
| 일 09:00 | 종목 검색 카탈로그 | 주 1회면 충분 |
실패하면 30분 뒤 한 번만 재시도하고, 그래도 실패하면 텔레그램으로 알림을 보낸다. 국장·미장이 둘 다 휴장인 날은 토스 시장 캘린더 API로 확인해서 건너뛴다.
여기서 한 번 막힌 게 있다. cron 작업은 컨테이너 환경변수를 물려받지 못한다. 그래서 컨테이너가 뜰 때 환경변수를 파일로 떠 두고, 각 작업 전에 source하도록 바꿨다.
매일 쌓기 시작하면 그날부터의 이력만 생긴다. 처음 차트를 띄웠을 때 점이 두 개뿐이었다. 사실상 빈 기능이었다.
그래서 과거를 재구성하는 backfill_history.py를 만들었다. 토스 주문내역 API는 커서로 끝까지 넘기면 2023-05-26까지 나온다. 이걸로 다음 순서를 밟는다.
실데이터로 돌려 보니 문제가 또 나왔다. 일부 종목은 체결가와 시세가 5~10배씩 차이가 났다. 종목코드 재사용이나 합병 때문으로 보인다. 그대로 두면 누적수익률이 하루 만에 몇백 %로 튀었다. 이런 종목은 자동으로 감지해서 가격 계산에서 빼도록 안전장치를 넣었다.
마지막 날 재구성한 보유수량을 실제 보유와 비교해 검증했다. 대부분 맞았고, 안 맞는 건 재구성 이후 기간의 실거래로 설명이 됐다.

입출금, 배당금, 실현손익은 Open API에 엔드포인트 자체가 없다. 토스증권 웹 화면에만 있다.
여기서는 Claude in Chrome을 썼다. 화면별 추출 스펙(필드, 형식)을 문서로 만들어 주고, 브라우저에서 화면을 읽어 JSON으로 뽑게 했다. 그 JSON을 앱의 "데이터 가져오기" 모달로 올리면 SQLite에 들어간다. 테이블의 기본키가 곧 중복 제거 키라서 같은 파일을 두 번 올려도 괜찮다.
그대로 믿지는 않았다. 뽑은 데이터의 내부 합계를 맞춰 봤더니 배당금·실현손익은 전부 맞았다. 그런데 거래내역의 "거래 후 잔액" 필드는 상당 부분이 틀어져 있었다. 같은 시각에 몰린 체결에서 잔액을 엉뚱한 행에 짝지은 것 같았다. 이 필드는 아예 저장하지 않기로 했다.
AI가 뽑은 데이터는 검증할 방법을 같이 만들어야 한다는 걸 다시 느꼈다.

지금은 이런 메뉴가 있다.
Trend Score는 20/60/120 거래일 추세를 수익률, 이동평균 기울기, 변동성으로 묶어 0~100점으로 만든 값이다. 1~120일 기간별로 상승·보합·하락 배지도 붙는다.
색은 국내 관행대로 상승은 빨강, 하락은 파랑이다. 앱 전체가 .gain/.loss 클래스로만 색을 쓰게 해 둬서 CSS 변수 두 개만 바꾸면 됐다. 캔들 차트는 스타일 시스템이 따로라 직접 지정해야 했다.



혼자 쓰는 도구라 "운영할 게 없게"를 최우선으로 뒀다. Flask와 SQLite 파일 하나, cron 배치 몇 개로도 꽤 많은 걸 할 수 있었다. 데이터가 없으면 쌓고, 쌓을 수 없는 과거는 주문내역으로 복원하고, API에 없는 건 브라우저에서 가져왔다.
다음 편에서는 이렇게 모은 데이터와 차트 이미지를 Claude Code·Codex CLI에 넘겨서 종목별 AI 분석을 붙인 과정을 정리한다. 웹에서 CLI 인증을 처리하는 부분과, 자동 배치를 만들었다가 결국 없앤 이야기가 들어간다.
이전 글: 없음
다음 글: 2편 — Claude Code·Codex CLI로 종목 AI 분석 붙이기
※ 이 글은 AI의 도움을 받아 작성했고, 작성자가 내용을 직접 검토한 뒤 올렸다.
| 토스증권 Open API로 나만의 포트폴리오 리포트 만들기 (2) — Claude Code·Codex CLI로 종목 AI 분석 붙이기 (0) | 2026.10.28 |
|---|---|
| 맥북 한 대로 AI 개발팀 굴리기 (3) — Agent Office와 삽질 모음 (0) | 2026.10.28 |
| 맥북 한 대로 AI 개발팀 굴리기 (2) — 사용량 관리와 모델 배치 (0) | 2026.10.28 |
| 맥북 한 대로 AI 개발팀 굴리기 (1) — 설계와 작업 흐름 (0) | 2026.10.28 |
댓글 영역