AlgoLab Blog · 완전 백과 · 2026 최신

자동매매 백테스트 완전 가이드 — 데이터 수집부터 워크포워드·몬테카를로까지

완전 백과 2026-06-04 · 약 25분 읽기 · 알고랩 AlgoLab
한 줄 정리 이 글은 자동매매 전략의 백테스트를 처음부터 끝까지 직접 구현하는 한국어 완전 가이드입니다. 데이터 수집 → 백테스트 엔진 작성 → 8가지 성과 지표 계산 → 워크포워드 분석 → 몬테카를로 시뮬레이션 → 슬리피지 모델링까지, 모든 단계를 Python 풀코드로 정리했습니다. "전략이 좋은가"가 아니라 "이 백테스트 결과를 얼마나 믿을 수 있는가"에 답하는 글입니다.

자동매매에서 가장 많이 들리는 말은 "백테스트가 좋게 나왔는데 실전에서 안 통한다"입니다. 거의 모든 경우 원인은 동일합니다 — 백테스트가 믿을 만하게 설계되지 않았기 때문입니다. 단순히 과거 데이터에 전략을 돌려보는 것과, 신뢰할 수 있는 백테스트를 구축하는 것은 완전히 다른 작업입니다.

이 글은 백테스트의 모든 단계를 다룹니다. 데이터를 어디서 어떻게 수집할지, 엔진을 어떻게 구현할지, 어떤 지표로 평가할지, 과적합을 어떻게 잡아낼지, 실전 괴리를 어떻게 줄일지 — Python 코드와 함께 정리했습니다. 30개 전략을 검증하든, 본인이 만든 1개 전략을 검증하든 동일하게 적용 가능한 프레임워크입니다.

이 글의 8부 구성

  1. Part 1 — 백테스트의 본질과 6가지 함정
  2. Part 2 — 데이터 수집과 정제 (yfinance · pyupbit · ccxt · KIS)
  3. Part 3 — 백테스트 엔진 직접 구현 (벡터화 + 이벤트 기반)
  4. Part 4 — 8가지 성과 지표 (Sharpe · Sortino · MDD · Calmar 등)
  5. Part 5 — 워크포워드 분석 (과적합 잡는 핵심 도구)
  6. Part 6 — 몬테카를로 시뮬레이션 (신뢰구간 추정)
  7. Part 7 — 실전 괴리 줄이기 (슬리피지·시장 충격 모델)
  8. Part 8 — 백테스트 워크플로 체크리스트

Part 1 — 백테스트의 본질과 6가지 함정

좋은 백테스트 = 좋은 전략을 찾는 도구가 아니라, 나쁜 전략을 걸러내는 도구.

백테스트가 측정하는 것

백테스트는 "이 전략이 과거 데이터에서 어떻게 행동했는지"를 시뮬레이션하는 작업입니다. 측정 대상은 크게 4가지입니다.

중요한 것은 백테스트가 "미래 수익을 예측하지 않는다"는 점입니다. 백테스트는 "이 전략은 명백히 작동하지 않는다"를 증명하는 데 가장 강력하고, "이 전략은 미래에도 작동할 것이다"를 증명하는 데는 매우 약합니다.

백테스트의 6가지 함정

다음 6가지를 점검하지 않은 백테스트는 신뢰할 수 없습니다.

① Look-ahead Bias (미래 정보 사용)

가장 흔하면서 가장 치명적인 실수. 진입 시점에 알 수 없는 정보를 사용하는 경우입니다. 예: "당일 종가 기준 매수"는 종가가 확정되는 장 마감 시점에서야 가능한 결정인데, 백테스트에서는 장중 매수로 시뮬레이션하는 경우. 또는 미래 캔들의 값을 이동평균에 포함시키는 경우.

# 잘못된 예 - 미래 정보 사용
df["ma20"] = df["close"].rolling(20).mean()
df["signal"] = (df["close"] > df["ma20"]).astype(int)
# 이 행의 close가 ma20에 포함되어 있음 → look-ahead

# 올바른 예 - shift로 미래 정보 차단
df["ma20"] = df["close"].rolling(20).mean().shift(1)
df["signal"] = (df["close"] > df["ma20"]).astype(int)

② Survivorship Bias (생존 편향)

지금 상장되어 있는 종목만으로 백테스트하면, 과거에 상장폐지·합병된 실패 종목은 빠집니다. KOSPI 200으로 5년 백테스트하면 "5년 전부터 지금까지 살아남은 종목"만 분석하는 셈입니다. 실제 수익률보다 과대평가됩니다.

③ Overfitting (과적합)

특정 기간 데이터에 맞춰 파라미터를 튜닝하면 그 기간에서는 화려한 결과가 나오지만 다른 기간에서는 실패합니다. RSI 기간을 14에서 13.7로 바꿔 수익률이 5% 늘었다면, 그건 발견이 아니라 노이즈에 맞춘 것입니다.

④ Selection Bias (선택 편향)

여러 전략·여러 파라미터를 시도해서 가장 좋은 것만 보고하는 경우. 100개 조합 중 1등을 골랐다면, 그 1등은 운이 좋았을 가능성이 큽니다.

⑤ 슬리피지·수수료 무시

"이론상 매수가에 정확히 체결" 가정. 실전에서는 호가 스프레드, 시장 충격, 체결 지연으로 인해 의도한 가격보다 0.05~0.5% 불리하게 체결됩니다. 매매 빈도가 높을수록 누적 영향이 큽니다.

⑥ 심리적 압박 무시

백테스트는 -30% 드로다운을 무덤덤하게 통과하지만, 실제 운영자는 그 시점에 봇을 멈추거나 파라미터를 바꿉니다. 백테스트 결과는 "감정 없는 로봇이 운영한 가정의 시뮬레이션"입니다.

⚠️ 자주 보는 패턴: "백테스트 수익률 +800% 전략" 광고. 거의 100% 과적합 또는 look-ahead bias입니다. 실제로 그런 전략이 있다면 본인이 운용하지 광고하지 않습니다.

Part 2 — 데이터 수집과 정제

백테스트 품질의 80%는 데이터 품질에서 결정됩니다.

필요한 데이터 종류

데이터용도최소 기간
OHLCV (시·고·저·종·거래량)모든 전략의 기본5년+
거래량 가중 평균가 (VWAP)슬리피지 모델링분봉 데이터 필요 시
호가창 (Level 2)스캘핑·시장 만들기실시간 또는 틱 데이터
펀더멘털 (PER·PBR·배당)가치·퀀트 팩터분기 데이터
분할·배당 조정주식 수익률 정확도전체 기간

주요 데이터 소스 (무료 또는 저비용)

해외 주식 — yfinance

import yfinance as yf
df = yf.download("AAPL", start="2020-01-01", end="2026-01-01", auto_adjust=True)
# auto_adjust=True 가 분할·배당 자동 조정

한국 코인 — pyupbit / python-bithumb

import pyupbit
df = pyupbit.get_ohlcv("KRW-BTC", interval="day", count=2000)
# 약 5년 5개월치 일봉

글로벌 코인 (다거래소) — ccxt

import ccxt
exchange = ccxt.binance()
since = exchange.parse8601("2020-01-01T00:00:00Z")
ohlcv = exchange.fetch_ohlcv("BTC/USDT", "1d", since, limit=2000)

한국 주식 — KIS API + pykrx

# 한국 주식 일봉 (pykrx - 한국 거래소 공식 데이터)
from pykrx import stock
df = stock.get_market_ohlcv("20200101", "20260101", "005930")   # 삼성전자
# 실시간이 필요하면 KIS API 사용 → /blog/kis-api-key-guide-30min 참고

데이터 정제 5단계

  1. 결측치 처리 — 거래 정지일·휴장일 분리, NaN을 단순히 ffill로 채우지 말 것
  2. 이상치 검출 — 하루 ±50% 같은 비정상 캔들은 데이터 오류 가능성
  3. 시간대 통일 — 한국 시장은 KST, 코인은 UTC. 백테스트 전 통일
  4. 분할·배당 조정 — 미조정 가격은 수익률 왜곡
  5. 중복 제거 + 정렬 — 거래소 API는 가끔 중복·역순 반환
def clean_ohlcv(df):
    df = df.drop_duplicates(subset="time").sort_values("time").reset_index(drop=True)
    df = df.dropna(subset=["open", "high", "low", "close"])
    # 이상치 검출: 일일 변동률 50% 이상이면 검토
    df["change"] = df["close"].pct_change().abs()
    suspicious = df[df["change"] > 0.5]
    if len(suspicious):
        print(f"⚠️ 이상치 {len(suspicious)}건 검토 필요")
    return df

Part 3 — 백테스트 엔진 직접 구현

라이브러리 의존 없이 60줄로 만드는 백테스트 엔진. 원리를 이해해야 라이브러리도 제대로 씁니다.

벡터화 vs 이벤트 기반

방식장점단점적합 전략
벡터화 (Vectorized)속도 매우 빠름 (pandas/numpy)복잡한 진입 조건 표현 어려움이동평균·RSI 등 단순 신호
이벤트 기반 (Event-driven)실거래와 거의 동일한 흐름속도 느림주문 큐, 포지션 관리, 다종목

벡터화 백테스트 — 60줄 풀코드

import pandas as pd
import numpy as np

class VectorBacktest:
    def __init__(self, df, initial_capital=10_000_000, fee=0.0005, slippage=0.001):
        self.df = df.copy()
        self.capital = initial_capital
        self.fee = fee
        self.slippage = slippage

    def run(self, signal_col="signal"):
        """signal_col: 1 = 매수 보유, 0 = 현금. 다음 봉 시가에 체결 가정."""
        df = self.df.copy()
        df["position"] = df[signal_col].shift(1).fillna(0)   # 신호는 다음 봉부터
        df["trade"] = df["position"].diff().abs()             # 매매 발생
        # 수익률: 시가→종가 보유 가정 (단순화), 매매 발생 시 슬리피지+수수료 차감
        df["ret_gross"] = df["close"].pct_change()
        df["cost"] = df["trade"] * (self.fee + self.slippage)
        df["ret_net"] = df["position"] * df["ret_gross"] - df["cost"]
        df["equity"] = (1 + df["ret_net"]).cumprod() * self.capital
        self.result = df
        return df

    def summary(self):
        df = self.result
        total_return = df["equity"].iloc[-1] / self.capital - 1
        days = len(df)
        cagr = (1 + total_return) ** (252 / days) - 1
        daily_ret = df["ret_net"].dropna()
        sharpe = daily_ret.mean() / daily_ret.std() * np.sqrt(252)
        # MDD
        cummax = df["equity"].cummax()
        drawdown = (df["equity"] - cummax) / cummax
        mdd = drawdown.min()
        # 매매 횟수
        n_trades = int(df["trade"].sum() / 2)
        win_trades = ((df["position"] == 1) & (df["ret_gross"] > 0)).sum()
        loss_trades = ((df["position"] == 1) & (df["ret_gross"] < 0)).sum()
        win_rate = win_trades / (win_trades + loss_trades) if (win_trades + loss_trades) else 0
        return {
            "total_return": f"{total_return:.2%}",
            "CAGR": f"{cagr:.2%}",
            "Sharpe": f"{sharpe:.2f}",
            "MDD": f"{mdd:.2%}",
            "trades": n_trades,
            "win_rate": f"{win_rate:.2%}"
        }

사용 예 — EMA 크로스 전략 백테스트

df = yf.download("AAPL", start="2018-01-01")
df["ema9"] = df["Close"].ewm(span=9).mean()
df["ema21"] = df["Close"].ewm(span=21).mean()
df["signal"] = (df["ema9"] > df["ema21"]).astype(int)
df = df.rename(columns={"Close": "close"})

bt = VectorBacktest(df.dropna(), initial_capital=10_000_000)
bt.run()
print(bt.summary())
# {'total_return': '85.32%', 'CAGR': '11.42%', 'Sharpe': '0.78', 'MDD': '-23.50%', 'trades': 47, 'win_rate': '38.30%'}

💡 위 결과 해석: CAGR 11.4%는 시장 평균과 비슷한 수준. Sharpe 0.78은 보통 이하. MDD -23.5%는 견딜 만하지만 좋지 않음. 승률 38%인데도 수익이 나는 이유는 큰 추세에서 큰 수익을 잡았기 때문. 승률보다 손익비가 중요하다는 추세 추종의 전형적 특성.

Part 4 — 8가지 성과 지표

수익률 하나만 보지 마라. 8가지 지표를 종합해야 진짜 성과가 보입니다.

지표 1. CAGR (Compound Annual Growth Rate)

연복리 수익률. 백테스트 기간에 무관하게 비교 가능. CAGR > 10%가 시장 평균(S&P 500 장기 수익률) 수준의 기준선.

cagr = (final_equity / initial_capital) ** (252 / days) - 1

지표 2. Sharpe Ratio

리스크 1단위당 초과 수익. 가장 표준적인 리스크 조정 지표. 1.0 이상 쓸 만함, 2.0 이상 우수, 3.0+ 의심.

sharpe = (daily_ret.mean() - rf_daily) / daily_ret.std() * np.sqrt(252)
# rf_daily: 무위험 수익률 (한국 기준 약 0.000095 = 연 2.4%)

지표 3. Sortino Ratio

Sharpe와 비슷하지만 분모에 하방 변동성만 사용. 큰 수익으로 인한 변동성을 페널티하지 않음. 실제 투자자가 신경 쓰는 것은 하방 변동성이라 Sharpe보다 더 의미 있을 때 많음.

downside = daily_ret[daily_ret < 0].std()
sortino = daily_ret.mean() / downside * np.sqrt(252)

지표 4. MDD (Maximum Drawdown)

고점 대비 최대 하락폭. 심리적 한계를 결정. MDD -50%면 자본이 반토막 났다가 회복했다는 뜻. 대부분 운영자는 -30% 이상에서 봇을 멈춥니다.

cummax = equity.cummax()
drawdown = (equity - cummax) / cummax
mdd = drawdown.min()

지표 5. Calmar Ratio

CAGR ÷ |MDD|. "고통 1단위당 수익". 1.0 이상이면 우수.

지표 6. 승률 (Win Rate)

전체 거래 중 수익 거래 비율. 높을수록 좋은 게 아님. 추세 추종은 30~40%, 평균회귀는 60~70%. 카테고리에 따라 정상 범위가 다름.

지표 7. 손익비 (Profit Factor)

총 수익 ÷ 총 손실 절대값. 1.5 이상 권장, 2.0 이상 우수. 승률이 낮은 추세 추종 전략에서 핵심.

profit_factor = gains.sum() / abs(losses.sum())

지표 8. 회복 기간 (Recovery Time)

MDD 발생 후 원래 고점을 회복할 때까지의 기간. 1년 이상 걸리면 실전 운영 거의 불가. 종이로는 손실이 회복되어도 그동안 운영자 의지가 무너집니다.

지표 종합 리포트 코드

def full_report(equity, daily_ret, trades_df):
    days = len(equity)
    total_ret = equity.iloc[-1] / equity.iloc[0] - 1
    cagr = (1 + total_ret) ** (252 / days) - 1

    sharpe = daily_ret.mean() / daily_ret.std() * np.sqrt(252)
    downside = daily_ret[daily_ret < 0].std()
    sortino = daily_ret.mean() / downside * np.sqrt(252) if downside else 0

    cummax = equity.cummax()
    dd = (equity - cummax) / cummax
    mdd = dd.min()
    calmar = cagr / abs(mdd) if mdd != 0 else 0

    gains = trades_df.loc[trades_df["pnl"] > 0, "pnl"]
    losses = trades_df.loc[trades_df["pnl"] < 0, "pnl"]
    win_rate = len(gains) / len(trades_df) if len(trades_df) else 0
    profit_factor = gains.sum() / abs(losses.sum()) if len(losses) else float('inf')

    # 회복기간 (최대 drawdown 발생 후 신고가까지)
    mdd_idx = dd.idxmin()
    after = equity.loc[mdd_idx:]
    pre_peak = cummax.loc[mdd_idx]
    recovery = after[after >= pre_peak]
    recovery_days = (recovery.index[0] - mdd_idx).days if len(recovery) else None

    return {
        "CAGR": f"{cagr:.2%}",
        "Sharpe": f"{sharpe:.2f}",
        "Sortino": f"{sortino:.2f}",
        "MDD": f"{mdd:.2%}",
        "Calmar": f"{calmar:.2f}",
        "Win Rate": f"{win_rate:.2%}",
        "Profit Factor": f"{profit_factor:.2f}",
        "Recovery Days": recovery_days
    }

각 지표를 어떻게 읽어야 하는지 깊이: → 자동매매 백테스트 리포트 읽는 법

Part 5 — 워크포워드 분석 (Walk-Forward Analysis)

과적합을 잡아내는 가장 강력한 도구. 백테스트 결과가 진짜인지 가짜인지 판별.

원리

전체 기간을 In-Sample (IS)Out-of-Sample (OOS)로 나눕니다. IS에서 최적 파라미터를 찾고, OOS에서 그 파라미터로 성과를 측정합니다. 이 윈도우를 시간 축으로 옮겨가며 반복합니다.

전체 데이터: 2018-01 ~ 2025-12 (8년)

윈도우 1: IS=2018-2020 (학습) → OOS=2021 (검증)
윈도우 2: IS=2019-2021 (학습) → OOS=2022 (검증)
윈도우 3: IS=2020-2022 (학습) → OOS=2023 (검증)
윈도우 4: IS=2021-2023 (학습) → OOS=2024 (검증)
윈도우 5: IS=2022-2024 (학습) → OOS=2025 (검증)

→ OOS 5개 구간의 평균 성과 = 진짜 성과

구현 코드

def walk_forward_analysis(df, param_grid, is_years=3, oos_years=1):
    """파라미터 그리드를 IS에서 최적화, OOS에서 검증"""
    results = []
    start = df.index[0]
    end = df.index[-1]
    is_delta = pd.DateOffset(years=is_years)
    oos_delta = pd.DateOffset(years=oos_years)

    window_start = start
    while window_start + is_delta + oos_delta <= end:
        is_end = window_start + is_delta
        oos_end = is_end + oos_delta
        is_df = df.loc[window_start:is_end]
        oos_df = df.loc[is_end:oos_end]

        # IS에서 최적 파라미터 탐색
        best_params, best_sharpe = None, -np.inf
        for params in param_grid:
            sharpe = backtest_with_params(is_df, params)["sharpe"]
            if sharpe > best_sharpe:
                best_sharpe = sharpe
                best_params = params

        # OOS에서 그 파라미터로 검증
        oos_result = backtest_with_params(oos_df, best_params)
        results.append({
            "IS": (window_start, is_end),
            "OOS": (is_end, oos_end),
            "best_params": best_params,
            "IS_sharpe": best_sharpe,
            "OOS_sharpe": oos_result["sharpe"]
        })
        window_start = window_start + oos_delta   # 1년씩 이동

    return pd.DataFrame(results)

결과 해석

패턴의미판단
IS Sharpe ≫ OOS Sharpe과적합❌ 전략 폐기 또는 단순화
IS Sharpe ≈ OOS Sharpe일관성✅ 신뢰 가능
OOS Sharpe 음수 빈번시장 의존⚠️ 시장 국면 필터 필요
최적 파라미터 매번 다름안정성 부족⚠️ 파라미터 윈도우 확대

✅ Walk-Forward Efficiency: OOS Sharpe 합계 / IS Sharpe 합계. 0.5 이상이면 전략이 시장 변화에 안정적이라는 신호. 0.3 미만이면 과적합 의심.

Part 6 — 몬테카를로 시뮬레이션

"이 백테스트 결과는 운이었나, 실력이었나?" 의 정량적 답.

원리

실제 백테스트에서 발생한 거래 결과(pnl)들의 순서를 무작위로 섞어 수천 번 시뮬레이션합니다. 그 결과의 분포를 보면 "내가 본 백테스트 결과가 분포 안에서 얼마나 좋은 편인지"를 알 수 있습니다.

def monte_carlo_simulation(trade_pnls, n_simulations=10000):
    """거래 순서를 섞어 자본 곡선 분포 생성"""
    results = {"final_equity": [], "mdd": []}

    for _ in range(n_simulations):
        shuffled = np.random.permutation(trade_pnls)
        equity = (1 + pd.Series(shuffled)).cumprod()
        cummax = equity.cummax()
        mdd = ((equity - cummax) / cummax).min()
        results["final_equity"].append(equity.iloc[-1])
        results["mdd"].append(mdd)

    final = pd.Series(results["final_equity"])
    mdd = pd.Series(results["mdd"])

    return {
        "median_final": final.median(),
        "5pct_final": final.quantile(0.05),   # 하위 5% 최악 시나리오
        "95pct_final": final.quantile(0.95),  # 상위 5% 최선 시나리오
        "median_mdd": mdd.median(),
        "worst_5pct_mdd": mdd.quantile(0.05)   # 하위 5% MDD
    }

해석 예시

{
  "median_final": 1.85,    # 중앙값 수익 85%
  "5pct_final": 1.12,      # 운이 나빠도 12% 수익 (안정적)
  "95pct_final": 2.74,     # 운이 좋으면 174% 수익
  "median_mdd": -0.18,     # 중앙값 MDD -18%
  "worst_5pct_mdd": -0.35  # 최악 5% MDD -35%
}

해석: "이 전략은 운이 평균이면 85% 수익, 하위 5% 운이라도 12% 수익을 기대할 수 있다. 최악의 경우 -35% MDD를 견뎌야 한다." 백테스트 단일 결과보다 훨씬 강한 통계적 진술입니다.

Part 7 — 실전 괴리 줄이기

백테스트와 실거래 사이의 격차를 좁히는 4가지 모델링.

1. 슬리피지 모델

가장 단순한 가정: 매매 가격에 일정 비율(0.05~0.5%)을 불리하게 적용. 거래량 큰 자산은 0.05%, 변동성 큰 알트코인은 0.5%까지.

def apply_slippage(price, side, slippage_pct=0.001):
    if side == "buy":
        return price * (1 + slippage_pct)
    else:
        return price * (1 - slippage_pct)

2. 시장 충격 모델 (Market Impact)

큰 주문은 자체적으로 가격을 움직입니다. 주문 크기가 평균 거래량의 0.1% 이상이면 무시할 수 없음.

def market_impact(order_size, avg_volume, k=0.1):
    """주문 크기가 평균 거래량 대비 클수록 충격 큼"""
    participation = order_size / avg_volume
    return k * np.sqrt(participation)

3. 체결 지연

신호 발생 시점과 실제 체결 시점 사이 1~5초 지연. 분봉 전략은 영향 적지만 초봉·틱 전략은 치명적. 백테스트에서는 신호 다음 캔들 시가에 체결로 가정.

4. 부분 체결 (Partial Fill)

대량 주문은 한 번에 다 체결 안 됨. 호가창 깊이를 고려한 시뮬레이션 필요. 단순 백테스트에서는 무시 가능하지만 자본 큰 운영자는 모델링 필수.

실전 괴리를 다양한 각도로: → 백테스트와 실전의 괴리 줄이기

Part 8 — 백테스트 워크플로 체크리스트

새 전략 백테스트할 때마다 따라가는 16단계 체크리스트.

데이터 단계

구현 단계

평가 단계

검증 단계

💡 마지막 단계 — 페이퍼 트레이딩: 백테스트 8단계를 모두 통과해도 실거래 전 최소 2주 페이퍼 트레이딩은 필수입니다. 라이브 데이터에서 코드가 의도대로 작동하는지, 실전 슬리피지가 백테스트 가정과 일치하는지 확인.

🔗 동반 GitHub 저장소 (준비 중)

이 글의 모든 코드를 정리한 algolab-backtesting-toolkit 저장소를 준비 중입니다. VectorBacktest 클래스, 8지표 리포트, 워크포워드·몬테카를로 함수를 바로 import해서 쓸 수 있는 형태로 공개 예정입니다. 공개 시점에 이 글이 업데이트됩니다.

자주 묻는 질문

Q. 백테스트는 왜 필요한가요?

전략이 과거 시장에서 어떻게 행동했는지 객관적으로 검증하기 위해서입니다. 백테스트 없이 실전 투입은 도박과 같습니다. 다만 백테스트 결과가 미래 수익을 보장하지는 않습니다.

Q. 백테스트 결과를 어디까지 믿을 수 있나요?

슬리피지·수수료·look-ahead bias·과적합을 통제한 경우에만 일정 부분 신뢰 가능. 일반적으로 실전은 백테스트보다 10~30% 나쁘다고 가정하는 것이 안전합니다.

Q. 어떤 라이브러리가 좋나요?

입문은 pandas 직접 구현. 본격 검증은 backtrader(이벤트 기반), vectorbt(고속 벡터화), zipline-reloaded(미국 주식 표준). 한국 시장은 pandas 또는 vectorbt가 가장 유연.

Q. 워크포워드 분석이 무엇인가요?

학습 구간(IS)과 검증 구간(OOS)으로 나눠 반복 검증하는 기법. 과적합 회피의 가장 강력한 도구.

Q. Sharpe Ratio는 얼마면 좋나요?

1.0 이상 쓸 만함, 2.0 이상 우수, 3.0 이상은 과적합 의심. Sharpe만 보지 말고 MDD·Sortino·Calmar 함께 봐야 함.

Q. 백테스트는 좋은데 실전에서 안 통하는 이유는?

6가지 함정 — 과적합, look-ahead, 생존편향, 슬리피지 무시, 시장 충격, 심리적 압박. 모두 백테스트 설계에서 통제 가능합니다.

마무리

백테스트는 "이 전략은 안 통한다"를 증명하는 부정 검증 도구입니다. "이 전략은 통할 것이다"는 백테스트가 답해주지 않습니다. 그래서 좋은 백테스트는 화려한 수익률이 나오는 것이 아니라, 의심스러운 신호가 명백히 드러나는 것입니다.

이 가이드의 8부 워크플로를 따라가면, 본인이 만든 전략이 "진짜 검증된 것"인지 "운 좋았던 것"인지 구분할 수 있습니다. 검증 없이 실전 투입된 봇은 100% 사고가 납니다. 검증 단계가 봇 만드는 시간보다 더 길어야 정상입니다.

본인 전략을 검증된 봇으로

전략 아이디어는 있지만 백테스트·워크포워드·실전 전환을 모두 직접 하기 부담스럽다면, 알고랩이 8부 워크플로를 적용해 검증된 봇을 1~3주 안에 맞춤 제작해드립니다.
24시간 빠른 답변 가능합니다.

무료 상담 시작하기