작년 말부터 두 달 정도, kim-dongho/quant-platform 이라는 자가호스팅 퀀트 트레이딩 플랫폼을 만들어 v0.1.0까지 출시했다.
미국·국내 주식 10년치 데이터로 룰을 백테스트하고, Grid Search로 검증된 룰을 한국투자증권(KIS) API 위에서 cron 자동매매로 돌리는 한 흐름의 도구다. 이번 시리즈는 그 회고다.
1편은 “무엇을 / 왜 / 어떻게” 만들었는지의 overview.
왜 자가호스팅이었나
기존 한국 퀀트 도구들 (대부분 SaaS, 일부 데스크톱 클라이언트) 을 잠깐 써본 뒤 셋이 거슬렸다.
- 본인 룰을 직접 못 검증 — 룰을 쓰는 게 아니라 만들어진 룰을 고르는 인터페이스가 대부분이었다.
- 데이터·실행 환경이 블랙박스 — 어떤 종목 풀에서, 어떤 가격으로, 어떤 슬리피지로 backtest 했는지가 닫혀있었다.
- 한·미 통합이 약함 — 미국은 yfinance, 한국은 FinanceDataReader / KIS 라는 결을 한 파이프라인 안에서 처리하는 도구가 잘 없었다.
직접 만들면 셋 다 풀린다. 룰은 코드로 쓴다. 데이터·실행 환경은 본인 DB·본인 컨테이너 위에서 돈다. 한·미는 symbol 형식만 분기하면 한 파이프라인이 다 처리한다.
라이브 매매까지 같이 묶은 이유는 — backtest 가 아무리 정확해도 검증된 룰을 사람이 손으로 매매에 옮기는 단계에서 누수가 가장 크다는 걸 알았기 때문이다. 한 손가락 안에서 backtest → 검증 → 라이브 까지 끝나야 본질에 가깝다.
무엇을 만들었나
세 가지 작업을 한 환경에서 한다.
- 백테스트 — 룰(RSI / SMA / 거래량 배수 등) 에 누적 수익률·MDD·CAGR·승률을 즉시 시뮬레이션
- 전략 자동 탐색 — Grid Search 로 학습 7년 / 검증 3년 양쪽 모두에서 시장 초과한 룰만 추천 (과적합 1차 필터)
- 라이브 자동매매 — 활성화한 룰 1개가 cron 스케줄에 맞춰 KIS API 로 매도·매수 주문 발송
데이터 소스는 미국은 yfinance, 한국은 FinanceDataReader. 모든 시계열은 TimescaleDB hypertable 에 적재된다.
시스템 구조
세 개의 앱과 인프라 설정을 단일 Monorepo에서 관리한다.
| 컴포넌트 | 위치 | 역할 |
|---|---|---|
| Frontend | apps/web | Next.js 16 — 전략 빌더·라이브 모니터링·차트 |
| API | apps/server | Go Fiber — 게이트웨이. 거의 그대로 엔진에 프록시 |
| Engine | apps/engine | Python FastAPI — 시세 수집·백테스트·자동 탐색·라이브 매매 |
| DB | infra/postgres | TimescaleDB (PostgreSQL 14) |

세 가지 호출 패턴이 있다.
- 사용자 요청 — Browser → Next.js → Go API → Python Engine. Go 는 거의 모든 경로를 그대로 프록시. 예외: read-heavy 한 종목 검색·리스트는 Go 가 DB 직조회.
- 시세 수집 — Engine 이 외부 API 에서 OHLCV 를 받아 TimescaleDB 에 적재.
- 라이브 매매 — Engine 이 KIS API 로 주문·잔고 호출. 트리거는 cron 이 호출하는 1회 실행 워커.
Go 따로 + Python 따로? — 게이트웨이는 응답 시간이 일정하고 동시성 다루기 좋아야 해서 Go. 백테스트·시세 수집·KIS 호출은 pandas / yfinance / 한투 SDK 와 결이 맞는 Python. 둘을 합쳐야 할 이유가 없었다.
Docker Compose 단일 호스트
라이브 매매를 24/7 돌리려면 결국 어딘가의 서버에서 컨테이너가 돌아야 한다. 처음엔 k8s 를 잠깐 검토했지만 — 혼자 운영하는 도구에 control plane 은 필요 없었다.
대신 docker-compose.yml 한 파일로 DB·API·엔진 세 컨테이너를 띄운다. 단일 VPS 에서 git clone → docker-compose up -d. 라이브 매매 cron 한 줄. 끝.
# 평일 15:20 KST 라이브 매매
20 15 * * 1-5 cd ~/quant && ./scripts/run-live.sh
이게 “운영”이다.
이 단순함의 부산물 셋:
- 재현성 —
.env와docker-compose.yml만 있으면 다른 머신에서도 1분 안에 같은 환경 - 단일 책임 — DB 는 DB, 엔진은 엔진. 컨테이너 경계가 자연스러운 단위로 매핑됨
- 스케일링은 일단 무시 — 혼자 쓰는 도구는 그게 옳다. 필요해지면 그때 분리
회고
만들면서 절감한 한 가지.
작은 도구일수록 인프라가 단순할 때 더 멀리 간다.
처음엔 더 정교한 인프라 (separate DB · monitoring stack · CI/CD pipeline 분리) 를 그릴 뻔했지만, 그건 도구가 안 만들어지는 가장 빠른 길이었다. 단일 docker-compose, 단일 cron, 단일 .env 로 출발한 게 정답이었고, v0.1.0 까지 이 결정 덕에 도달했다고 본다.
다음 글부터는 컴포넌트별로 들어간다.
- 2편 — TimescaleDB + 팩터 precompute 로 백테스트 만들기
- 3편 — Grid Search 로 검증된 룰만 추천하는 자동 탐색
- 4편 — KIS Open API 로 라이브 자동매매 — 토큰·rate limit·동시호가의 함정
- 5편 — Hysteresis 청산 룰 자동 도출 + 자본 균등 분배