백테스팅이란 무엇인가 — 개념과 초보자가 빠지는 함정 3가지
전략을 만들어서 검증 없이 바로 실전에 돌리면, 그 검증은 결국 실제 돈으로 하게 된다. 버그를 발견하는 시점이 손실이 난 다음이 된다는 뜻이다. 이 순서를 뒤집는 도구가 백테스팅이다. 이번 글에서는 백테스팅의 개념과 함께, 백테스팅을 하고도 결과가 의미 없어지는 세 가지 함정을 정리한다.
백테스팅이란
백테스팅(Backtesting)은 어떤 매매 전략을 실제 돈으로 실행하기 전에, 과거 데이터에 그 전략을 적용했을 때 어떤 결과가 나왔을지 시뮬레이션해보는 과정이다. "이 전략이 지난 1년간의 데이터에 대해서는 어떻게 작동했는가"를 미리 확인하는 것이다.
말은 단순하지만, 이 단계를 건너뛰고 바로 실전에 전략을 투입하는 경우가 생각보다 많다. 특히 개인이 자동매매를 처음 만들 때 "일단 돌려보고 잘 되면 계속하지"라는 식으로 접근하기 쉬운데, 이건 사실상 실제 돈으로 백테스팅을 하는 것과 다름없다.
왜 백테스팅 없이 가면 위험한가
전략 로직에 버그가 있어도, 데이터 처리 방식이 잘못돼도, 코드만 보면 "그럴듯하게 돌아가는 것처럼" 보일 수 있다. 실제로 돈이 걸리기 전에 그 전략이 과거 데이터에서 어떤 손익 곡선을 그렸는지 확인하지 않으면, 문제를 발견하는 시점이 "손실이 이미 발생한 후"가 된다.
백테스팅의 핵심 가치는 두 가지다.
- 전략 자체의 논리적 결함을 조기에 발견한다 (예: 매수 신호와 매도 신호가 동시에 뜨는 조건이 있는지)
- 전략의 대략적인 특성(변동성이 큰 구간에서 어떻게 반응하는지, 손실이 이어지는 구간이 얼마나 긴지 등)을 미리 파악한다
단, 백테스팅 결과가 좋다고 해서 실전에서도 같은 결과가 나온다는 보장은 전혀 없다. 이 오해가 바로 다음에 다룰 함정들로 이어진다.
최소한의 백테스팅 코드 구조 — 파이썬 의사코드
python 코드 보기
def backtest(prices: list[float], strategy_fn, initial_cash: float) -> dict:
cash = initial_cash
position = 0
equity_curve = []
for i in range(len(prices)):
window = prices[: i + 1]
signal = strategy_fn(window)
if signal == "BUY" and position == 0:
position = cash / prices[i]
cash = 0
elif signal == "SELL" and position > 0:
cash = position * prices[i]
position = 0
equity = cash + position * prices[i]
equity_curve.append(equity)
return {
"final_equity": equity_curve[-1],
"equity_curve": equity_curve,
"max_drawdown": _max_drawdown(equity_curve),
}
def _max_drawdown(equity_curve: list[float]) -> float:
peak = equity_curve[0]
worst = 0.0
for value in equity_curve:
peak = max(peak, value)
drawdown = (peak - value) / peak
worst = max(worst, drawdown)
return worst여기서 strategy_fn은 앞선 글에서 다룬 신호 생성 함수를 그대로 재사용할 수 있다. 중요한 건 window = prices[: i + 1]처럼, 그 시점까지의 데이터만 전략에 넘겨야 한다는 점이다. 미래 데이터가 실수로 섞여 들어가면 결과가 실전과 완전히 다른 의미 없는 숫자가 된다(다음 항목에서 더 다룬다).
초보자가 빠지는 함정 3가지 — 미래참조·과최적화·생존편향
1. 미래참조(Look-ahead Bias). 백테스팅 코드를 짜다 보면 무심코 "미래 시점의 데이터"를 신호 계산에 섞어 넣는 실수가 생긴다. 예를 들어 어떤 날의 신호를 계산하면서 그날 종가 이후에나 알 수 있는 정보를 써버리는 식이다. 이러면 백테스팅 결과가 비정상적으로 좋게 나오는데, 실전에서는 절대 재현되지 않는다. 신호 계산 시점에 "그 시점에 실제로 알 수 있었던 데이터"만 쓰고 있는지 항상 의심해야 한다.
2. 과최적화(Overfitting). 특정 기간의 과거 데이터에 딱 맞게 전략의 파라미터(이동평균 기간, 손절 기준 등)를 계속 조정하다 보면, 그 데이터에만 기가 막히게 잘 맞는 전략이 만들어진다. 문제는 이게 "그 전략이 좋아서"가 아니라 "그 데이터에만 우연히 맞춰졌기 때문"이라는 점이다. 다른 기간이나 실전에 적용하면 성과가 급격히 나빠지는 경우가 흔하다. 파라미터를 조정할 때는 반드시 학습에 쓴 기간과 검증에 쓴 기간을 분리해야 한다.
3. 생존편향(Survivorship Bias). 지금 시점에 존재하는 종목들의 데이터만으로 과거를 백테스트하면, 그 사이 상장폐지되거나 사라진 종목들은 애초에 데이터에서 빠져 있다. 즉 "살아남은 종목들"만으로 검증한 셈이라 성과가 실제보다 좋게 나오는 왜곡이 생긴다. 장기간 백테스팅을 할수록 이 편향을 더 주의해야 한다.
이 외에도 거래 수수료·슬리피지(주문가와 체결가의 차이)를 반영하지 않고 이론상 숫자만 계산하는 실수도 흔하다. 실전에서는 이 비용들이 누적되면 전략의 성과를 크게 갉아먹을 수 있다.
백테스팅 다음 단계 — 모의투자(페이퍼 트레이딩) 검증
백테스팅을 통과했다고 해서 실전에서 그대로 재현된다는 보장은 없다. 시장 상황은 계속 바뀌고, 과거에 통했던 패턴이 미래에도 통한다는 근거는 어디에도 없다.
그래서 백테스팅 다음 단계로 모의투자(페이퍼 트레이딩) 기간을 반드시 거치는 게 안전하다. 백테스팅이 "과거로 검증"이라면, 모의투자는 "현재 실시간 환경에서 돈 없이 검증"하는 단계다. 이 두 단계를 모두 거치고 나서야 실전 투입을 고려하는 게 순서상 맞다. 모의투자 환경을 직접 어떻게 꾸리는지는 페이퍼 트레이딩 환경 만들기에서 자세히 다룬다.
오늘의 정리
- 백테스팅은 전략을 실거래에 넣기 전 과거 데이터로 미리 검증하는 과정이며, 이를 생략하는 건 사실상 실제 돈으로 검증하는 것과 같다.
- 미래참조·과최적화·생존편향은 초보자가 가장 흔히 빠지는 함정이며, 이 함정에 빠지면 백테스팅 결과가 실전과 무관한 숫자가 된다.
- 백테스팅을 통과했더라도 실전 성과를 보장하지 않으므로, 반드시 모의투자 단계를 거친 뒤 실전을 고려해야 한다.
이 시리즈는 안전장치 설계, API 인증, 백테스팅까지 자동매매 시스템을 만들 때 거쳐야 하는 단계들을 개념 위주로 다뤄왔다. 다음 글 자동매매 리스크 관리 규칙 설계에서는 이 개념들을 실제로 하나의 흐름으로 엮어 규칙을 설계하는 과정을 다룬다.
이 글의 코드는 개념 설명을 위한 의사코드이며 특정 실거래 시스템의 구현이 아닙니다. 이 글은 투자 조언이 아니며 특정 종목이나 매매기법을 추천하지 않습니다. 백테스팅 결과가 좋다고 해서 미래 수익을 보장하지 않으며, 투자 손실에 대한 책임은 투자자 본인에게 있습니다.