튜토리얼약 7분 읽기

백테스팅이 뭐고 왜 없으면 위험한가 — 초보자용 개념

백테스팅이란

백테스팅(Backtesting)은 어떤 매매 전략을 실제 돈으로 실행하기 전에, 과거 데이터에 그 전략을 적용했을 때 어떤 결과가 나왔을지 시뮬레이션해보는 과정이다. "이 전략이 지난 1년간의 데이터에 대해서는 어떻게 작동했는가"를 미리 확인하는 것이다.

말은 단순하지만, 이 단계를 건너뛰고 바로 실전에 전략을 투입하는 경우가 생각보다 많다. 특히 개인이 자동매매를 처음 만들 때 "일단 돌려보고 잘 되면 계속하지"라는 식으로 접근하기 쉬운데, 이건 사실상 실제 돈으로 백테스팅을 하는 것과 다름없다.

왜 백테스팅 없이 가면 위험한가

전략 로직에 버그가 있어도, 데이터 처리 방식이 잘못돼도, 코드만 보면 "그럴듯하게 돌아가는 것처럼" 보일 수 있다. 실제로 돈이 걸리기 전에 그 전략이 과거 데이터에서 어떤 손익 곡선을 그렸는지 확인하지 않으면, 문제를 발견하는 시점이 "손실이 이미 발생한 후"가 된다.

백테스팅의 핵심 가치는 두 가지다.

  1. 전략 자체의 논리적 결함을 조기에 발견한다 (예: 매수 신호와 매도 신호가 동시에 뜨는 조건이 있는지)
  2. 전략의 대략적인 특성(변동성이 큰 구간에서 어떻게 반응하는지, 손실이 이어지는 구간이 얼마나 긴지 등)을 미리 파악한다

단, 백테스팅 결과가 좋다고 해서 실전에서도 같은 결과가 나온다는 보장은 전혀 없다. 이 오해가 바로 다음에 다룰 함정들로 이어진다.

최소한의 백테스팅 구조 — 의사코드

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]처럼, 그 시점까지의 데이터만 전략에 넘겨야 한다는 점이다. 미래 데이터가 실수로 섞여 들어가면 결과가 실전과 완전히 다른 의미 없는 숫자가 된다(다음 항목에서 더 다룬다).

초보자가 자주 빠지는 함정 세 가지

1. 미래참조(Look-ahead Bias). 백테스팅 코드를 짜다 보면 무심코 "미래 시점의 데이터"를 신호 계산에 섞어 넣는 실수가 생긴다. 예를 들어 어떤 날의 신호를 계산하면서 그날 종가 이후에나 알 수 있는 정보를 써버리는 식이다. 이러면 백테스팅 결과가 비정상적으로 좋게 나오는데, 실전에서는 절대 재현되지 않는다. 신호 계산 시점에 "그 시점에 실제로 알 수 있었던 데이터"만 쓰고 있는지 항상 의심해야 한다.

2. 과최적화(Overfitting). 특정 기간의 과거 데이터에 딱 맞게 전략의 파라미터(이동평균 기간, 손절 기준 등)를 계속 조정하다 보면, 그 데이터에만 기가 막히게 잘 맞는 전략이 만들어진다. 문제는 이게 "그 전략이 좋아서"가 아니라 "그 데이터에만 우연히 맞춰졌기 때문"이라는 점이다. 다른 기간이나 실전에 적용하면 성과가 급격히 나빠지는 경우가 흔하다. 파라미터를 조정할 때는 반드시 학습에 쓴 기간과 검증에 쓴 기간을 분리해야 한다.

3. 생존편향(Survivorship Bias). 지금 시점에 존재하는 종목들의 데이터만으로 과거를 백테스트하면, 그 사이 상장폐지되거나 사라진 종목들은 애초에 데이터에서 빠져 있다. 즉 "살아남은 종목들"만으로 검증한 셈이라 성과가 실제보다 좋게 나오는 왜곡이 생긴다. 장기간 백테스팅을 할수록 이 편향을 더 주의해야 한다.

이 외에도 거래 수수료·슬리피지(주문가와 체결가의 차이)를 반영하지 않고 이론상 숫자만 계산하는 실수도 흔하다. 실전에서는 이 비용들이 누적되면 전략의 성과를 크게 갉아먹을 수 있다.

백테스팅이 끝이 아니라는 것

백테스팅을 통과했다고 해서 실전에서 그대로 재현된다는 보장은 없다. 시장 상황은 계속 바뀌고, 과거에 통했던 패턴이 미래에도 통한다는 근거는 어디에도 없다. 그래서 백테스팅 다음 단계로 모의투자(페이퍼 트레이딩) 기간을 반드시 거치는 게 안전하다. 백테스팅이 "과거로 검증"이라면, 모의투자는 "현재 실시간 환경에서 돈 없이 검증"하는 단계다. 이 두 단계를 모두 거치고 나서야 실전 투입을 고려하는 게 순서상 맞다.

오늘의 정리

  1. 백테스팅은 전략을 실거래에 넣기 전 과거 데이터로 미리 검증하는 과정이며, 이를 생략하는 건 사실상 실제 돈으로 검증하는 것과 같다.
  2. 미래참조·과최적화·생존편향은 초보자가 가장 흔히 빠지는 함정이며, 이 함정에 빠지면 백테스팅 결과가 실전과 무관한 숫자가 된다.
  3. 백테스팅을 통과했더라도 실전 성과를 보장하지 않으므로, 반드시 모의투자 단계를 거친 뒤 실전을 고려해야 한다.

이 시리즈는 안전장치 설계, API 인증, 백테스팅까지 자동매매 시스템을 만들 때 거쳐야 하는 단계들을 개념 위주로 다뤄왔다. 다음 글에서는 이 개념들을 실제로 어떻게 하나의 흐름으로 엮어 리스크 관리 규칙을 설계하는지 더 풀어볼 예정이다.


이 글의 코드는 개념 설명을 위한 의사코드이며 특정 실거래 시스템의 구현이 아닙니다. 이 글은 투자 조언이 아니며 특정 종목이나 매매기법을 추천하지 않습니다. 백테스팅 결과가 좋다고 해서 미래 수익을 보장하지 않으며, 투자 손실에 대한 책임은 투자자 본인에게 있습니다.

← 전체 글 목록