본문으로 바로가기

백테스트 수익률이 과장되는 7가지 함정

결론부터 말하면, 백테스트 수익률은 전략이 미래를 잘 예측해서가 아니라 데이터에 미래가 섞였거나 실패 종목·비용·체결 불가능한 가격이 빠져서 높아질 수 있다.

검증 순서는 수익률 숫자를 보는 것보다 먼저 데이터 시점, 종목 모집단, 기업행동, 주문 시점과 비용을 확인하는 것이다. 그 뒤에 학습·선택에 쓴 구간과 한 번도 보지 않은 평가 구간을 분리한다.

2026-08-22에 일곱 함정을 작은 결정적 합성 데이터로 계산했다. 예를 들어 양의 수익률인 날만 미리 고르면 같은 일별 자료의 누적값이 2.32%에서 9.86%로 바뀌고, 살아남은 종목만 보면 평균 23.2%지만 상장폐지 -100% 종목을 포함하면 -38.4%가 된다. 이는 실제 시장 성과가 아니라 왜곡 원리를 드러내는 교육용 계산이다.

이 글로 해결할 수 있는 것

  • 높은 수익률보다 먼저 검사할 데이터 계약을 안다.
  • 일곱 함정이 결과를 어느 방향으로 왜곡하는지 숫자로 본다.
  • 재현 가능한 백테스트 보고서에 필요한 항목을 정리한다.

실행 환경과 계산 기준

Python 표준 라이브러리만 사용하는 content/evidence/backtest_traps_demo.py를 실행했다. 난수 예제는 seed 42로 고정했고 결과는 content/evidence/backtest_traps_20260822.json에 저장했다. 모든 값은 합성 데이터다.

1. 미래정보 사용

오늘 장이 끝난 뒤 알 수 있는 당일 수익률의 부호로 오늘 포지션을 정하면 미래를 미리 본 것이다. 같은 8일 자료를 그대로 보유하면 2.32%지만 양의 날만 골라 담는 불가능한 규칙은 9.86%로 계산됐다.

2. 생존편향

현재 남아 있는 종목 목록으로 과거를 시험하면 상장폐지·합병·거래정지 종목이 사라진다. 합성 예에서 살아남은 종목만 보면 23.2%였지만 -100% 종목을 같은 비중으로 포함하면 평균은 -38.4%였다.

3. 거래비용과 체결오차 누락

여섯 거래의 총수익이 2.20%여도 매번 20bp 비용을 차감하면 0.98%로 줄었다. 실제 계산에는 수수료, 세금, bid-ask spread, 시장 충격과 부분 체결을 전략의 회전율에 맞게 넣어야 한다.

4. 신호를 본 같은 종가에 체결

100원 종가를 보고 매수 신호를 만든 뒤 같은 100원에 체결했다고 가정해 다음 105원까지 5%를 기록하면 시간 순서가 맞지 않을 수 있다. 다음 거래 가능 시점의 103원에 체결하면 같은 청산가의 수익은 1.94%다.

5. 액면분할·배당 같은 기업행동

100원이 2대1 분할 뒤 50원으로 보인 것을 원시 가격으로 계산하면 -50%다. 보유 가치가 유지된 조정 가격에서는 0%다. 수정주가를 썼다는 이름만 믿지 말고 배당, 분할, 합병과 상장폐지 처리 방식을 확인한다.

6. 과최적화와 여러 번의 선택

평균이 0인 무작위 후보 100개 중 학습 구간 합이 가장 큰 93번을 선택하자 학습 합은 20.57%처럼 보였지만 같은 후보의 독립 평가 구간 합은 -7.17%였다. 후보를 많이 시험할수록 우연히 좋은 결과를 고를 가능성이 커진다.

7. 결측치와 거래 불가 구간 삭제

문제가 있는 -10% 구간을 결측으로 보고 삭제하면 누적값은 6.11%였고 해당 구간을 명시하면 -4.50%였다. 결측을 0으로 채우거나 행을 지우기 전에 왜 비었는지, 그 시점에 실제 거래가 가능했는지 확인해야 한다.

게시할 백테스트의 최소 체크리스트

  1. 각 필드가 실제로 알 수 있었던 시각
  2. 해당 날짜의 전체 종목 모집단과 상장폐지 처리
  3. 기업행동·배당·통화 조정 규칙
  4. 신호 계산과 주문 체결의 시간 순서
  5. 수수료·세금·spread·slippage 가정
  6. 학습·선택·최종 평가 구간 분리
  7. 결측·거래정지·가격제한 처리와 코드 버전

한계와 투자정보 고지

이 계산은 실제 종목이나 시장을 사용하지 않은 교육용 예제이며 어떤 전략의 예상 수익률도 아니다. 실전에서는 데이터 공급자별 수정 방식, 주문 유형, 유동성과 시장 제도를 추가로 반영해야 한다. 이 글은 특정 금융상품의 매수·매도를 권유하지 않는다.

출처와 변경 이력

  • 실행 코드: content/evidence/backtest_traps_demo.py
  • 실행 결과: content/evidence/backtest_traps_20260822.json
  • 최종 검토: 2026-08-22
  • 2026-08-22: 일곱 합성 계산과 한계 최초 기록