백테스트 과최적화 방지법

백테스트란 무엇인가?

퀀트 투자와 자동매매를 시작하면 가장 먼저 만나는 도구가 백테스트(Backtest)입니다. 과거 데이터를 기반으로 매매 전략의 수익률을 시뮬레이션하는 과정인데, 이 결과가 좋으면 실전에서도 통할 거라 믿게 됩니다. 하지만 현실은 다릅니다. 백테스트 수익률이 높을수록 오히려 실전에서 실패할 확률이 높아지는 경우가 많습니다.

과최적화(Overfitting)의 정의

과최적화란 전략의 파라미터를 과거 데이터에 지나치게 맞추는 현상입니다. 예를 들어, 이동평균선의 기간을 5일, 10일, 20일, 50일… 수백 가지 조합으로 테스트한 뒤 가장 수익률이 높은 조합을 선택하면, 그 조합은 과거에만 유효한 우연의 산물일 가능성이 큽니다.

과최적화된 전략의 특징은 다음과 같습니다:

  • 백테스트 수익률이 비현실적으로 높음 (연 100% 이상)
  • 파라미터를 조금만 바꿔도 성과가 급격히 변함
  • 특정 시장 구간에서만 성과가 집중됨
  • 거래 횟수가 극단적으로 적거나 많음

실전에서 백테스트가 무너지는 5가지 이유

1. 슬리피지와 수수료 미반영

백테스트에서 체결가를 종가 기준으로 계산하면, 실전에서는 슬리피지(slippage)로 인해 예상보다 불리한 가격에 체결됩니다. 특히 유동성이 낮은 종목이나 코인에서는 슬리피지가 수익의 상당 부분을 잠식합니다. 수수료 역시 고빈도 전략에서는 누적 비용이 막대합니다.

2. 생존 편향(Survivorship Bias)

과거 데이터에는 상장폐지된 종목이 빠져 있는 경우가 많습니다. 살아남은 종목만으로 백테스트하면 수익률이 부풀려집니다. 계좌 생존 규칙에서 강조한 것처럼, 생존 자체가 투자의 첫 번째 목표여야 합니다.

3. 미래 데이터 참조(Look-Ahead Bias)

백테스트 코드에서 실수로 미래 시점의 데이터를 참조하는 버그는 생각보다 흔합니다. 예를 들어, 당일 종가를 매수 판단에 사용하면서 시가에 매수한 것으로 처리하는 경우가 대표적입니다.

4. 시장 레짐 변화

2020년 코로나 급락장에서 통한 전략이 2021년 상승장에서도 통할까요? 시장의 변동성, 추세, 상관관계는 끊임없이 변합니다. 특정 레짐에 최적화된 전략은 레짐이 바뀌면 무력해집니다.

5. 데이터 스누핑(Data Snooping)

같은 데이터셋으로 수십 개의 전략을 테스트하면, 순전히 우연에 의해 좋은 성과를 보이는 전략이 반드시 나옵니다. 이를 다중 비교 문제라 하며, 통계적으로 보정하지 않으면 거짓 신호를 진짜로 착각하게 됩니다.

과최적화를 방지하는 실전 체크리스트

검증 항목 구체적 방법
Out-of-Sample 테스트 데이터를 70:30으로 분리, 30%는 전략 개발에 절대 사용하지 않음
Walk-Forward 분석 최적화 구간을 이동시키며 반복 검증, 일관된 성과 확인
파라미터 민감도 핵심 파라미터를 ±20% 변경해도 성과가 유지되는지 확인
몬테카를로 시뮬레이션 거래 순서를 랜덤으로 섞어 최대 낙폭(MDD) 분포 확인
다중 시장 검증 다른 종목·자산군에서도 유사한 성과가 나오는지 교차 검증

Python으로 Walk-Forward 테스트 구현하기

실제 퀀트 개발에서 가장 실용적인 검증 방법인 Walk-Forward 분석의 핵심 로직을 살펴보겠습니다.

import numpy as np

def walk_forward(data, train_pct=0.7, n_splits=5):
    """Walk-Forward 분석: 훈련/검증 구간을 이동하며 반복 검증"""
    split_size = len(data) // n_splits
    results = []

    for i in range(n_splits):
        start = i * split_size
        end = start + split_size
        segment = data[start:end]

        train_end = int(len(segment) * train_pct)
        train = segment[:train_end]
        test = segment[train_end:]

        # 훈련 구간에서 최적 파라미터 탐색
        best_param = optimize(train)
        # 검증 구간에서 성과 측정
        score = evaluate(test, best_param)
        results.append(score)

    return np.mean(results), np.std(results)

이 방식의 핵심은 미래 데이터를 절대 학습에 사용하지 않는 것입니다. 각 구간에서 독립적으로 최적화하고, 바로 다음 구간에서 검증합니다.

실전 적용 시 주의사항

백테스트 결과를 실전에 적용할 때는 다음 원칙을 지켜야 합니다:

  • 소액으로 시작: 최소 3개월간 실제 자금으로 소액 운용 후 성과 비교
  • 실시간 모니터링: 백테스트 대비 슬리피지·체결률을 지속 추적
  • 손실 한도 설정: 손실 한도 규칙을 자동매매에도 반드시 적용
  • 레짐 필터 추가: VIX, 변동성 지표 등으로 시장 환경 구분 로직 포함
  • 정기 리밸런싱: 분기마다 전략 성과를 재검토하고 파라미터 재조정

결론: 좋은 전략은 단순하다

퀀트 투자에서 살아남는 전략의 공통점은 단순함입니다. 파라미터가 3개 이하이고, 논리적으로 설명 가능하며, 다양한 시장 환경에서 일관된 성과를 보이는 전략이 장기적으로 생존합니다. 화려한 백테스트 곡선에 속지 말고, 검증 프로세스를 철저히 거치는 것이 진짜 퀀트의 시작입니다.

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux