[토스 자동매매 개발기 시리즈] — 현재 글: 9번째 편 (전체 9편 중)
- Phase 0 — 기반 시스템 구축기 (#0)
- Phase 0-1 — 해외주식 통화 버그 수정기 (#0-1)
- Phase 1 — 설정 분리와 재시도 로직 (#3)
- Phase 1-2 — 설정/재시도 후속 정리 (#4)
- Phase 1-3 — pytest 단위 테스트 도입기 (#5)
- Phase 1-4 — 로그 파일 무한 증식 막기 (#6)
- Phase 2-1 — 전략 클래스 추상화 (#7)
- Phase 2-2 — 복수 종목 감시 지원 (#8)
- Phase 3-1 — 데이터 영속성 설계 (#9, 현재 글)
Phase 0부터 Phase 2까지 기반 시스템, 안정성 강화, 전략 모듈화를 순서대로 끝내고 나니 로드맵상 다음 순서는 데이터 영속성이었다. 그런데 이번 건 코드부터 짜지 않았다. 스코프가 이전 단계들보다 확실히 커서, 짜다가 갈아엎느니 설계부터 문서로 확정하고 넘어가기로 했다.
이번 세션에서 할 일을 먼저 잘라냈다
데이터 영속성 작업은 크게 5단계로 나뉜다. 스키마 설계 → db.py 구현 → auto_trader.py 연동 → toss_portfolio.py 연동 → 테스트 작성. 이번 세션에서는 1단계, 스키마 설계만 확정하기로 했다. 나머지는 다음 세션으로 넘겼다. 한 번에 다 밀어붙이면 중간에 뭐가 잘못됐는지 찾기 어려워지는 걸 이전 Phase들에서 이미 겪었다.
trades / alerts / price_snapshots 스키마
세 개의 테이블로 나눴다.
trades— 거래 이력. 종목·수량·가격 외에is_dry_run(시뮬레이션 여부),strategy_name(어떤 전략이 신호를 냈는지) 컬럼을 넣었다.alerts— 알림 이력. 메시지, 레벨, 관련 종목(nullable)을 기록한다.price_snapshots— 시세 스냅샷. 해외주식 소수점 대응을 위해 가격 컬럼을REAL타입으로 잡고, 통화(KRW/USD) 컬럼을 별도로 뒀다. 예전에 해외 보유자산이 합계에서 빠지던 통화 버그를 겪은 이후로, 이 원칙(KRW/USD 분리)을 데이터 계층에도 그대로 가져왔다.
시계열 조회가 잦을 걸 감안해서 CREATE INDEX idx_price_symbol_ts ON price_snapshots(symbol, timestamp) 형태로 종목+시각 복합 인덱스도 미리 계획해뒀다.
시뮬레이션(DRY_RUN) 거래도 trades 테이블에 기록하되, is_dry_run 컬럼으로 실전 거래와 명확히 구분하는 방식으로 설계했다. 시뮬레이션 이력 자체가 전략 튜닝에 쓸 데이터가 되고, 컬럼으로 분리돼 있어 실전/모의 혼동 위험도 없다.
가장 오래 고민한 결정 — 시뮬레이션 거래를 기록할 것인가
DRY_RUN 상태로 도는 시뮬레이션 매수를 거래 이력에 남길지 말지가 애매했다. 안 남기면 나중에 전략이 얼마나 자주 신호를 냈는지 알 수가 없고, 남기면 실전 거래와 헷갈릴 위험이 있었다. 결론은 “기록하되 is_dry_run으로 구분”이었다. 3중 안전장치 원칙과도 충돌하지 않는 선에서 정리됐다.
db.py 인터페이스도 이번에 같이 확정
스키마만 정하고 끝낸 게 아니라 db.py 모듈의 함수 시그니처까지 미리 잡아뒀다.
def get_connection():
...
def init_db():
...
def insert_trade(symbol, quantity, price, is_dry_run, strategy_name):
...
def insert_alert(message, level, symbol=None):
...
def insert_price_snapshot(symbol, price, currency, timestamp):
...
DB 기록이 실패해도 매매 루프 자체가 멈추면 안 되니까, 기존 텔레그램 알림 전송부와 똑같이 “최선 노력(best-effort)” 방식으로 처리하기로 했다. DB insert 실패는 로그만 남기고 넘어간다.
테스트는 실제 파일 대신 인메모리 DB로
테스트할 때마다 실제 sqlite 파일을 만들면 반복 실행할 때 파일이 오염될 수 있어서, sqlite3.connect(':memory:') 방식의 인메모리 DB로 검증하는 전략을 택했다. 다음 세션에서 pytest 테스트를 짤 때 이 방식을 그대로 쓸 예정이다.
다음 단계
이번 글은 설계까지만 다뤘다. 다음 세션에서는 이 설계 문서를 기준으로 db.py를 실제로 구현하고, auto_trader.py·toss_portfolio.py에 연동한 뒤 인메모리 DB로 테스트를 작성할 예정이다. 그 내용은 Phase 3-2로 따로 정리할 계획이다.
“SQLite 스키마 설계로 거래 기록 영속화하기 | 토스 개발기 #3-1”에 대한 5개의 생각