stockauto 백테스트 기준을 다듬은 과정
시작
스톡오토에서 백테스트를 수행하는 일은 처음에는 단순히 Optuna를 많이 돌려 좋은 파라미터를 찾는 문제처럼 보였다. 하지만 여러 연도를 반복해서 다루면서 작업의 중심은 점점 달라졌다. 중요한 것은 trial 하나의 최고 수익률이 아니라, 한 해의 시장 상황 안에서 어떤 후보를 믿을 수 있고 어떤 후보를 버려야 하는지 판단하는 기준을 세우는 일이었다.
사용자는 Optuna 실행 자체는 직접 맡고, 실행이 끝난 뒤 결과 폴더를 알려주는 방식으로 흐름을 바꿨다. Codex는 그 결과를 해석하고, 다음 search space를 제안하거나 최종 후보를 기록하는 분석가 역할로 정리됐다. 이 변화 덕분에 백테스트는 자동 실행 루프가 아니라 사람이 중간중간 확인하고 판단을 교정할 수 있는 실험 과정이 되었다.
처음 보였던 문제
처음에는 수익률과 MDD, Calmar만 보면 충분해 보였다. 하지만 실제 결과를 보니 몇 가지 왜곡이 생겼다.
첫째, 거래 횟수가 너무 적은 후보가 높은 성과처럼 보일 수 있었다. 1년에 10번도 거래하지 않은 후보가 좋은 Calmar를 보이면 숫자는 좋아도 실전 후보로 믿기 어려웠다. 그래서 total_trades < 10은 제외하고, 10~19회는 낮은 신뢰도로 표시하며, 가능하면 20회 이상 후보를 우선하는 기준이 생겼다.
둘째, 단일 최고 수익률 후보는 위험했다. 어떤 후보는 수익률이 높았지만 MDD가 지수보다 훨씬 컸다. 이런 후보는 상승장에서 보기에는 매력적이지만, 실제 운용에서는 자본 훼손을 크게 만들 수 있었다.
셋째, 좋은 후보가 경계값에 몰릴 때 판단이 어려웠다. 경계값에 후보가 몰리면 그 값을 고정할 것이 아니라, 그 방향으로 search space를 한 번 더 열어 현재 범위가 부족했던 것인지 확인해야 했다.
질문이 바꾼 판단
가장 큰 전환점은 “수익률을 좀 내줘도 MDD가 지수보다 낮은 편이 더 낫겠지?”라는 질문이었다.
이 질문 전에는 KOSPI 수익률, MDD, Calmar를 모두 넘지 못하면 no-go에 가깝게 판단했다. 하지만 사용자의 운용 기준은 단순 초과수익이 아니었다. 수익률이 지수보다 낮더라도 MDD가 지수보다 낮고, 충분한 거래 횟수와 양의 수익을 만든다면 방어형 후보로 보관할 가치가 있었다.
1
2
3
채택 후보 = 수익률도 지수 이상이고 MDD도 지수 이하인 후보
방어형 후보 = 수익률은 지수보다 낮지만 MDD도 지수보다 낮은 후보
탈락 후보 = 수익률이 높아도 MDD가 지수보다 큰 후보
이 기준은 2023년 결론을 바꿨다. 처음에는 2023년을 no-go로 정리했지만, 이후 trial 639를 방어형 최선 후보로 보관하도록 결론을 수정했다. 이 후보는 KOSPI 수익률과 Calmar를 이기지는 못했지만, KOSPI보다 낮은 MDD를 유지했고 거래 횟수도 충분했다.
핵심 인사이트
이번 작업에서 가장 선명해진 것은 백테스트 결과를 해석하는 순서다.
1
2
3
4
5
1. 거래 횟수 유효성 확인
2. KOSPI 수익률, MDD, Calmar 기준선 확인
3. Pareto 후보와 plateau 확인
4. 경계값 쏠림 여부 확인
5. 다음 config를 넓힐지, 좁힐지, 최종화할지 결정
Calmar는 중요하지만, Calmar 하나만 보면 안 된다. MDD가 낮아도 수익률이 너무 낮으면 전략이 의미 없고, 수익률이 높아도 MDD가 지수보다 크면 사용자의 운용 기준과 맞지 않는다. 결국 좋은 후보는 숫자 하나가 아니라, 수익률, MDD, Calmar, 거래 횟수, 파라미터 안정성이 함께 맞아야 했다.
또 하나의 중요한 구분은 “연도별 최적화”와 “일반화”를 분리하는 것이다. 지금의 목표는 여러 연도에 동시에 잘 맞는 만능 파라미터가 아니라, 개별 연도 하나에서 최선의 후보군을 찾는 것이다. 따라서 2022년에 잘 나온 깊은 하락 대기형 파라미터를 다른 연도에 바로 일반화하면 안 된다.
수행한 일
백테스트 워크플로우는 다음 구조로 정리됐다.
1
2
3
4
5
6
사용자가 Optuna 실행
-> 완료 결과 폴더 전달
-> KB와 직전 decision log 복기
-> KOSPI 기준선 비교
-> 결과 CSV 해석
-> 다음 config 생성 또는 최종 결론 작성
결과 파일은 주로 src/backtest/artifacts/results/optuna/<year>/... 아래에 쌓이고, 다음 실행용 config는 src/backtest/artifacts/params/agent-configs/<year>/batch_<NNN>.json에 저장한다. 판단 이유는 src/backtest/artifacts/results/agentic_backtest_kb/<year>/decision_log.csv에 누적한다. 최종 단계에서는 결과 폴더 안에 final_conclusion.md를 남긴다.
결론
스톡오토 백테스트에서 중요한 것은 Optuna를 많이 돌리는 것만이 아니었다. 오히려 더 중요한 일은 결과를 읽는 기준을 세우는 것이었다.
1
2
3
4
5
6
최고 수익률 하나를 믿지 않는다.
거래 횟수가 부족한 후보는 믿지 않는다.
MDD가 지수보다 큰 고수익 후보는 신중하게 본다.
수익률을 일부 양보하더라도 지수보다 낮은 MDD를 확보한 후보는 방어형으로 보관한다.
경계값에 몰린 후보는 고정하기 전에 한 번 더 확장 검증한다.
최종 후보는 decision log와 final_conclusion.md에 판단 이유까지 남긴다.
이제 stockauto의 백테스트는 단순한 숫자 뽑기가 아니라, 사용자가 자신의 운용 기준을 점점 선명하게 만드는 도구에 가까워졌다. 좋은 전략을 찾는 과정은 결국 좋은 질문을 남기는 과정이기도 했다.