본문으로 건너뛰기

사이드 프로젝트: 통과 기준을 먼저 적고 백테스트하기

· 약 2분
Seung hyo, Lee
Front End Engineer @ Assistfit

회사 밖에서 Python 사이드 프로젝트를 하나 시작했다. 가상자산 일봉 데이터로 매매 전략을 백테스트하고, 통과한 전략은 실제 돈 없이 모의거래로 매일 돌려 보는 도구다. 프론트엔드 밖의 코드를 오랜만에 처음부터 짰다.

처음 며칠​

첫날은 uv로 환경을 잡고 거래소 일봉을 Parquet로 쌓는 파이프라인과 무결성 검사를 만들었다. 그 위에 백테스트 엔진과 추세추종 전략을 올리고, 모의거래 봇은 macOS launchd로 매일 정해진 시각에 돌게 했다. 리포트에는 자산 곡선을 SVG로 그려 넣었다.

코드 식별자는 한글로 쓰기로 규칙을 정했다. 외부 SDK 필드명만 영어로 두고, 도메인 용어는 한글 그대로 쓴다. 혼자 읽는 코드에서 용어를 번역하는 비용을 없애고 싶었다.

둘째 날에는 전략을 여러 개 꽂을 수 있게 구조를 바꿨다. 전략은 마감된 봉만 받아 목표 비중을 돌려주는 순수 함수로 정의했다.

@runtime_checkable
class 전략(Protocol):
이름: str
타임프레임: str # "1d" | "60m" | "15m"
유니버스: list[str]
필요_히스토리_봉수: int

def 목표비중(self, 캔들: dict[str, DataFrame]) -> dict[str, float]:
"""마감봉 OHLCV → 심볼별 목표비중. IO 없는 순수 함수."""
...

전략, 슬리브 배분, 자본 상한을 층으로 나눠 곱하는 구조라 어느 값을 누가 책임지는지 문서에 박아 뒀다. 기존 봇의 계산을 새 구조로 옮긴 뒤에는 같은 입력에서 소수 여섯째 자리까지 같은지 테스트로 확인했다. 오늘 일반화한 워크포워드 엔진도 옛 백테스트 스크립트와 비교해 최대 오차 2.66e-15로 맞췄다.

관문을 먼저 정하기​

두 번째 전략으로 Donchian 채널과 ATR 트레일링 스탑을 쓰는 스윙 전략을 붙였다. 백테스트를 돌리기 전에 편입 기준 여섯 개를 문서에 먼저 적었다. 표본 외 Sharpe, 최대 낙폭, Profit Factor, 기존 전략과의 상관, Deflated Sharpe, 그리고 과적합 확률(PBO)이다.

결과는 다섯 개 통과, PBO 0.64로 한 개 미통과였다. 설정값을 고정해 쓰는 전략이라 PBO가 이 경우에 맞는 지표인지 따져 볼 여지는 있었다. 그래도 결과를 본 뒤에 기준을 바꾸지 않기로 했던 게 이 관문의 의미라서 편입하지 않았다. 다음에 시도할 변형 두 개도 미리 정해 두고, 그 안에서만 다시 검증한다.

계획은 TDD 태스크 단위로 쪼갠 문서로 쓰고, 구현은 Claude와 나눠서 했다. 실험 브랜치는 워크트리로 띄워 메인 작업 공간과 섞이지 않게 했다.