623개의 테스트로 파이썬 백테스팅 엔진을 만든 방법
Source: Dev.to
지난 1년 동안 파이썬으로 백테스팅 및 실시간 트레이딩 엔진을 만들었습니다. 처음엔 개인용 도구였어요—전략을 테스트할 때마다 같은 파이프라인을 다시 짜는 것이 지겨웠거든요. 어떻게 실제 제품으로 성장했는지 이야기해볼게요.
전략을 백테스트할 때마다 나는 항상 같은 보일러플레이트 코드를 작성했습니다:
- 어디선가 OHLCV 데이터를 가져오기
- 인디케이터 연결하기
- 진입·청산 로직 작성하기
- 포지션, 손익, 드로우다운 추적하기
- 일종의 리포트 만들기
- 하나라도 바꾸면 깨지지 않길 바라기
기존 도구들을 써보았지만,
- 일부는 방치돼 있었고,
- 일부는 강제적인 API 패턴을 요구했으며,
- 일부는 노트북 전용이라 실시간 실행 경로가 없었습니다.
어떤 도구도 “아이디어가 생겼다” → “실시간으로 돌린다” 로 가는 과정을 코드 절반을 다시 짜지 않고는 할 수 없었죠.
그래서 직접 만들었습니다.
AlgoDeploy는 파이썬 엔진으로 전체 흐름을 커버합니다:
전략 정의 → 백테스트 → 리스크 관리 → 실시간 실행
핵심 설계 결정은 전략을 선언형으로 만들었다는 점입니다. 대부분의 전략은 커스텀 파이썬 코드가 필요 없고, 단순히 인디케이터 조건, 진입·청산 규칙, 포지션 사이징만 있거든요. 그래서 YAML 설정 레이어를 만들었습니다:
symbol: SPY
start: 2020-01-01
end: 2025-01-01
capital: 100000
entry:
- close sma(20)
실제 내부에서는 각 바마다 평가되는 비교 연산 체인으로 파싱됩니다.
- 하드 스톱, 트레일링 스톱, 테이크프로핏 목표, 시간 기반 청산, 스케일아웃 등
- 각 청산 규칙은 독립적이며, 여러 개를 겹쳐 놓을 수 있고, 가장 먼저 트리거된 것이 적용됩니다.
청산 로직은 대부분의 백테스팅 프레임워크가 복잡해지는 부분이기 때문에 이 설계가 중요했습니다.
리스크 레이어는 전략 로직과 별도로 동작합니다. 드로우다운 제한, 일일 손실 한도, 포지션 수준 리스크 한도, 노출 제약, “스톱 필요” 규칙(스톱 가격 없는 주문을 거부) 등을 포함합니다. 리스크 레이어는 전략이 시도하는 어떤 거래든 거부할 수 있습니다.
리스크를 전략과 분리하면 전략을 교체해도 리스크 검증을 다시 구현할 필요가 없고, 리스크 규칙을 강화해도 전략 코드를 건드릴 필요가 없습니다.
- 켈리 기준, 변동성 스케일(거래당 달러 리스크 목표), 고정 비율(자산의 X%를 거래당 리스크) 등
- 각 사이저는 현재 포트폴리오 상태를 받아 포지션 사이즈를 반환합니다. 역시 다른 요소와 독립적입니다.
프로젝트에는 623개의 자동화 테스트가 있습니다. 이것은 허세가 아니라 생존 메커니즘이죠.
금융 계산을 다루다 보면 포지션 사이징이나 청산 로직의 사소한 버그가 결과를 조용히 왜곡합니다. 스택 트레이스에서는 보이지 않지만, 백테스트 수익률이 실제와 맞지 않을 때 드러납니다.
그래서 저는 공격적으로 테스트합니다:
- 모든 인디케이터, 비교 연산자, 청산 규칙, 포지션 사이저, 리스크 체크에 대한 단위 테스트
- 백테스트 엔진에 대한 통합 테스트(입력 → 검증된 출력)
- 전체 파이프라인에 대한 엔드‑투‑엔드 테스트: 설정 → 데이터 → 백테스트 → 리포트
- 엣지 케이스: 거래량 0 바, 갭, 주식 분할, 단일 바 전략, 빈 유니버스
테스트 스위트는 CI에서 매 커밋마다 실행됩니다. 트레일링 스톱 계산 방식을 바꾸면, 몇 초 안에 다른 부분이 깨졌는지 알 수 있죠.
엔진 위에 웹 UI를 만들었습니다. 모든 작업을 코드로 할 필요는 없으니까요. 대시보드를 통해 할 수 있는 일:
- 드롭다운과 폼 필드로 전략을 설정 (YAML이나 파이썬 필요 없음)
- 백테스트를 실행하고 WebSocket 업데이트로 실시간 결과 확인
- 메트릭 보기: 총 수익률, CAGR, 샤프, 소르티노, 최대 드로우다운, 승률, 프로핏 팩터
- 벤치마크와 비교(SPY, QQQ 등)
- 전략 설정 저장·불러오기
대시보드는 로컬 웹 앱이며, 동일한 파이썬 엔진과 통신합니다. 클라우드로 데이터가 나가지 않아요.
백테스트 결과는 자체 포함 HTML 파일로 내보낼 수 있습니다. 파일 하나면 서버 없이도 이메일이나 아카이브에 바로 넣을 수 있죠. 여기엔 equity curve, 드로우다운 차트, 트레이드 로그, 모든 요약 메트릭이 포함됩니다.
엔진은 Alpaca와 연동해 실시간 실행도 지원합니다. 백테스트에서 사용한 전략을 설정 하나만 바꾸면 실시간으로도 돌릴 수 있습니다. 실시간 러너는 상태 머신을 따라 움직입니다: 유니버스 스캔 → 진입 규칙 평가 → 리스크 체크 → 포지션 사이즈 결정 → 실행. 모든 결정은 감사 로그에 남깁니다.
또한 주문을 실제로 넣지 않고 로그만 남기는 페이퍼 트레이딩 모드도 있어, 실제 돈을 걸기 전에 검증할 수 있습니다.
선언형 우선, 필요하면 코드로 탈출. 대부분 사용자는 단순 이동 평균 교차 같은 전략에 파이썬을 쓰고 싶어 하지 않지만, 일부는 커스텀 로직이 필요합니다. 같은 엔진에서 두 가지를 모두 지원한 것이 올바른 선택이었습니다.
리스크는 전략의 일부가 아닙니다. 이것이 가장 큰 아키텍처적 승리였어요. 리스크 체크가 독립적이면 각각을 따로 생각할 수 있습니다. “전략이 좋은 신호를 만들고 있나?”와 “내가 너무 많이 위험을 감수하고 있나?”는 별개의 질문이니까요.
금융 코드는 돈이 걸려 있기 때문에 테스트해야 합니다. 결국 그렇습니다. 포지션 사이징에서 0.1% 라운딩 오류가 금방 복리로 커집니다.
리포트는 휴대성이 필요합니다. 백테스트 결과를 공유하려고 Jupyter 서버를 띄우고 싶어 하는 사람은 없습니다. 자체 포함 HTML 파일이 이 문제를 완전히 해결했습니다.
엔진은 기능적으로 완전하며, 공개 출시 전 베타 테스터를 모집하고 있습니다. 알고리즘 트레이딩에 관심 있고 직접 써보고 싶다면 algo-deploy.com을 방문해 주세요.
아키텍처, 테스트 접근법, 혹은 다른 궁금한 점이 있으면 댓글로 질문해 주세요.