Claude AI로 주식 자동매매 프로그램을
기획한 이야기
코드 한 줄 없이 대화만으로 명세서 완성 — TWAP 분할 주문부터 TWR 수익률까지
들어가며 — 5년 만에 다시 만드는 자동매매
5년 전, 저는 C#으로 키움증권 OpenAPI 기반 자동 주식매매 프로그램을 만들어 설치 파일로 배포한 경험이 있습니다. 당시에는 기능이 너무 많아 복잡했고, 유지보수도 힘들었습니다.
이번에는 달랐습니다. 정말 필요한 기능만 담아, Python 웹 기반으로 새로 만들어보기로 했습니다. 그리고 코드를 짜기 전에 먼저 Claude AI와 대화하며 요구사항을 정리하고 명세서를 완성하는 과정을 거쳤습니다. 이 협업 과정이 생각보다 훨씬 유익했습니다.
1편(현재): Claude AI와 기획 단계 — 요구사항 정리 & 명세서 완성
2~5편: Claude Code와 실제 구현 — 백엔드부터 보안까지
왜 Python 웹 버전인가?
C# 버전은 Windows 설치 파일로 배포하는 방식이었습니다. 사용자마다 직접 설치해야 했고, 회사에서 모바일로 모니터링하는 것이 불편했습니다.
이번 목표는 단순했습니다.
- 어디서든 접속 가능 → 웹 기반
- 모바일에서도 실행 가능 → 반응형 UI
- 필요한 기능만 → 계좌 리밸런싱에 집중
키움증권 OpenAPI는 Windows COM 방식이라 백엔드는 여전히 Windows PC에서 실행해야 하지만, 프론트엔드는 브라우저로 어디서든 접근할 수 있게 설계했습니다. PC에서 서버를 켜두고 스마트폰에서 접속하는 방식입니다.
핵심 기능: 균등 리밸런싱
이번 프로그램의 핵심은 계좌 균등 리밸런싱입니다. 로직은 단순합니다.
평균금액 = (전체 종목 평가금액 합계 + 예수금) / 보유 종목 수 매도수량 = floor((평가금액 - 평균금액) / 현재가) ← 평균 초과 종목 매수수량 = floor((평균금액 - 평가금액) / 현재가) ← 평균 미달 종목
모든 종목이 동일한 금액이 되도록 맞추는 것입니다. 예수금도 포함해서 계산하기 때문에 현금도 자동으로 종목에 배분됩니다. 예를 들어 5개 종목과 현금이 있다면, 현금도 균등 배분 대상이 됩니다.
ETF로 구성된 배당 연금 계좌를 운용할 때, 어느 종목이 오를지 예측하기 어렵습니다. 균등 배분은 특정 종목에 베팅하지 않고 자동으로 고점 매도, 저점 매수를 반복하는 효과가 있습니다.
대화를 통해 다듬어진 설계들
1. 매도/매수 시간 분리
처음에는 단순히 리밸런싱 실행 버튼 하나로 생각했지만, Claude가 중요한 질문을 던졌습니다.
"매도 체결 전에 매수 주문이 나가면 예수금 부족 문제가 생길 수 있어요. 매도 완료 후 매수를 시작하는 구조로 바꾸시겠어요?"
그래서 매도 시작 시간과 매수 시작 시간을 각각 설정하는 방식으로 바꿨습니다. 매수 시작 시간이 되어도 미체결 매도 주문이 남아있으면 대기하도록 설계했습니다.
2. 평균금액 이중 계산
매도 시점과 매수 시점 사이에 현재가가 변하기 때문에, 평균금액을 두 번 계산하도록 했습니다.
- 매도 시작 시점 → 평균금액 계산 → 매도 수량 결정
- 매수 시작 시점 → 평균금액 재계산 → 매수 수량 결정
매수 시점에는 매도 체결로 예수금도 늘어나 있기 때문에 재계산이 필수입니다.
3. TWAP 분할 주문
하루 중 가격 변동을 활용해 평균 단가를 개선하는 TWAP(Time-Weighted Average Price) 방식을 도입했습니다. 예를 들어 9시 30분~11시 사이 10분할이면 9분 간격으로 10번 나눠서 주문합니다.
매도와 매수의 수량/금액 계산 방식이 다릅니다.
매도: 시작 시점에 총 매도수량 고정 → 매 회차 현재가만 갱신
총 매도수량 = floor((평가금액 - 평균금액) / 현재가) ← 시작 시점 고정 회차별 매도수량 = floor(총 매도수량 / 분할횟수) ← 전 회차 동일
매수: 목표금액 고정 → 매 회차 현재가로 수량 재계산 (예수금 초과 방지)
회차별 매수목표금액 = 총 매수목표금액 / 분할횟수 ← 고정 회차별 매수수량 = floor(회차별 매수목표금액 / 현재가) ← 매 회차 재계산
4. 10초 간격 순차 주문
키움 API에 주문을 한꺼번에 보내면 에러가 발생합니다. 주문 큐(Queue)를 만들어 10초 간격으로 1종목씩 순차적으로 주문을 넣도록 설계했습니다.
5. 미체결 폴링 방식
체결 이벤트 기반으로 미체결을 감지하면 종목이 많을 경우 이벤트가 너무 많이 발생합니다. 대신 3분(사용자 설정 가능)마다 미체결 주문을 조회하는 폴링 방식을 채택했습니다. 10분이 지나도 미체결이면 현재가로 주문 정정을 보냅니다.
추가된 편의 기능들
기본 리밸런싱 외에 실무에서 필요한 기능들도 추가했습니다.
안전장치
- 주문 전 최종 확인 화면 (어떤 종목을 얼마나 사고팔지 미리 표시)
- 실행 시점 유효성 검증 (매도/매수 시작 시간이 이미 지났으면 알림)
- 매도/매수 각각 ON/OFF 토글 (매수만 하는 날도 있으므로)
종목 관리
- 특정 종목 제외 기능 (장기 보유 종목 건드리지 않기)
- 신규 종목 편입 (보유수량 0으로 리밸런싱 대상에 추가)
- 종목별 비중 커스터마이징 (균등 대신 가중치 설정)
알림
- 텔레그램 알림 (리밸런싱 시작/완료, 체결, 실패, 배당금 수령)
- 장 시작 전 08:50 포트폴리오 현황 알림 (ON/OFF)
수익률 Dashboard — TWR로 정확하게
ETF 배당 연금계좌 특성에 맞게 Dashboard를 설계했습니다. 단순 손익이 아닌 TWR(Time-Weighted Return, 시간가중수익률)을 사용합니다.
연금계좌는 매달 추가 납입을 합니다. 단순 수익률은 입금 직후 크게 떨어져 보이는 착시가 생깁니다. TWR은 입출금 효과를 제거한 순수 운용 성과를 측정합니다.
구간수익률 = 구간말 평가금액 / (구간초 평가금액 + 입금액 - 출금액) - 1 TWR 누적수익률 = (1+구간1) × (1+구간2) × ... - 1 연환산 TWR = (1 + TWR 누적수익률) ^ (1 / 운용연수) - 1
배당금도 별도로 추적합니다. 키움 API로 배당금 수령 내역을 조회해 월별 배당금 바차트로 시각화합니다.
Claude AI와의 협업 소감
이번 기획 과정에서 Claude가 특히 도움이 됐던 순간들이 있었습니다.
예외 케이스를 먼저 짚어줬습니다
매수 주문 전 매도 체결 확인, 실행 버튼 클릭 시점의 시간 유효성 검증, 매수 시점 현재가 변동에 따른 평균금액 재계산 등 제가 미처 생각하지 못했던 예외 상황들을 먼저 제안해줬습니다.
전문 용어와 개념을 연결해줬습니다
분할 주문 방식을 설명했을 때 "TWAP 전략이네요"라고 연결해주고, 추가 입금이 있을 때 수익률 왜곡 문제를 TWR로 해결하는 방법을 제안해줬습니다.
기능 추천도 실용적이었습니다
단순 자동매매를 넘어 텔레그램 알림, 배당금 추이, TWR 수익률 등 실제로 쓸만한 기능들을 추천해줬고, 불필요한 기능은 과감히 제외하는 판단도 함께 해줬습니다.
뒤늦게 알게 된 게임 체인저: 키움 REST API
명세서를 거의 다 완성했을 때, 기존 OpenAPI+가 아닌 새로운 방식이 있다는 것을 알게 됐습니다. 2025년 3월 24일 정식 출시된 키움 REST API였습니다.
| 기존 OpenAPI+ | 키움 REST API | |
|---|---|---|
| 설치 | Windows + 32bit Python 필수 | 설치 불필요 |
| OS | Windows만 | Windows/Mac/Linux |
| 로그인 | 영웅문 자동로그인 설정 필요 | App Key + Secret Key |
| 아키텍처 | COM 방식 (PyQt5 필수) | 순수 HTTP REST |
| Python | 32bit 강제 | 64bit 자유롭게 |
아키텍처도 훨씬 단순해졌습니다.
[브라우저] ↕ HTTP/WebSocket
[FastAPI 별도 스레드]
[PyQt5 메인 스레드] ↕ COM (32bit)
[키움 OpenAPI+]
변경 후 (REST API)
[브라우저] ↕ HTTP/WebSocket
[FastAPI asyncio]
↕ HTTP REST
[키움 REST API 서버]
이벤트 기반 체결 감지(OnReceiveChejanData)도 사라지고, 처음부터 설계했던 폴링 방식과 자연스럽게 맞아떨어졌습니다. PyQt5 이벤트 루프와 FastAPI 충돌 문제도 한 번에 해결됐습니다.
최종 기술 스택
| 항목 | 내용 |
|---|---|
| 백엔드 | Python 3.x (64bit), FastAPI |
| API 연동 | 키움 REST API + httpx (async) |
| 실시간 통신 | WebSocket (FastAPI 내장) |
| 프론트엔드 | HTML + CSS + Vanilla JS (모바일 반응형) |
| DB | SQLite + aiosqlite |
| 알림 | 텔레그램 Bot API |
| 실행 환경 | Windows PC |
✔ 균등 리밸런싱 로직 (평균금액 계산)
✔ TWAP 분할 주문 (매도/매수 별도 시간 설정)
✔ 10초 간격 순차 주문 큐
✔ 미체결 폴링 & 주문 정정
✔ 종목 제외/편입/비중 관리
✔ TWR 수익률 & 배당금 추이
✔ 텔레그램 알림
✔ 키움 REST API 적용 (32bit 탈피)
처음에는 단순한 리밸런싱 프로그램으로 시작했는데, 대화를 거듭하면서 TWAP 분할 주문, TWR 수익률, 배당금 추이, 입출금 자동 감지까지 갖춘 꽤 완성도 높은 자산관리 툴이 됐습니다. 다음 편부터는 이 명세서를 Claude Code에 넘겨 실제로 구현하는 과정을 다룹니다.
1편 ✅ Claude AI로 주식 자동매매 프로그램 기획한 이야기 (현재 글)
2편 → Claude Code로 키움 REST API 클라이언트 구현하기
3편 → TWAP 분할 주문 & 자동 정정 주문 시스템 구현기
4편 → WebSocket + Vanilla JS로 실시간 자동매매 UI 만들기
5편 → 실제 운용하며 만난 버그들과 보안 강화 후기
6편 → 실제 구동 화면 전체 공개 — 로그인부터 대시보드까지
댓글 없음:
댓글 쓰기