좋은 백테스트는 무엇이 다른가? 수익률보다 먼저 검증 절차를 설계하는 법
근거와 검증 범위 — 인공 시계열·검증 절차 예제
문헌과 고정 시드의 인공 시계열 예제로 시간 분할·평가 절차를 설명합니다. 실제 종목 성과를 입증하는 실험이 아니며, 비용·위험 평가는 이번 예제의 범위에 포함하지 않습니다.
가설 선기록, 기준 전략, 시간 순서 분할, walk-forward validation과 테스트 구간 보호를 작은 실험으로 이해한다
처음에는 여러 전략을 실행한 뒤 가장 높은 누적수익률 그래프를 고르는 것이 백테스트의 목표라고 생각했다. 그래프가 매끄럽고 최종 수익률이 높으면 좋은 전략을 발견한 것처럼 느껴졌다.
하지만 백테스트 수익률은 실제 운용성과가 아니라 과거 데이터로 계산한 가상 성과다.[S2] 비교 대상을 바꾸거나 유리한 기간만 고르는 것만으로도 결과의 의미는 달라질 수 있다.[S2] 더구나 전략·특징·기간·파라미터를 충분히 많이 시험하면 실질적으로 우월해서가 아니라 운이 좋아서 돋보인 후보를 선택할 수 있다.[S9][S10][S11]
그래서 질문을 바꾸게 됐다.
결과가 얼마나 높았는가보다 먼저, 그 결과를 만드는 과정에서 미래 정보와 사람의 사후 선택이 얼마나 차단됐는가?
좋은 백테스트는 최고 수익률을 고르는 절차가 아니다. 미리 정한 질문을 미래 정보 없이 공정하게 반증하려는 절차다.
이 글의 표와 코드는 백테스트 검증 절차를 설명하기 위한 교육·연구용 예제다. 특정 종목 추천이나 실제 매매 지시가 아니며 수익을 보장하지 않는다. 예제에서 관찰한 점수 차이를 실제 자산, 시장, 기간 또는 투자전략의 우월성으로 일반화해서는 안 된다.[S2][S8]
데이터의 시계 다음에는 실험의 시계를 맞춘다
3편에서는 다음 질문을 중심에 놓았다.
그 값은 거래 결정을 내리던 순간에도 실제로 관측 가능했는가?
이번 편에서는 데이터의 생성 시점과 관측 시점이 올바르게 정렬됐다고 가정한다. 이제 그 데이터를 어떤 순서로 나누고, 어떤 구간에서 선택하며, 어떤 구간을 마지막까지 보지 않을 것인지 정할 차례다.
특징 자체에 미래값이 없더라도 전체 기간으로 스케일러나 결측 대체 규칙을 계산하고 특징을 선택한 다음 데이터를 나누면 테스트 구간의 정보가 학습 과정에 들어갈 수 있다.[S4] 반대로 시간 순서대로 나눴더라도 특징의 관측 시점이 잘못됐다면 3편에서 다룬 누수는 그대로 남는다.
시간 분할은 중요한 방어선이지만 모든 누수를 자동으로 없애는 버튼은 아니다.[S4][S5]
좋은 백테스트는 결과보다 질문을 먼저 기록한다
연구 질문과 분석 계획을 결과보다 먼저 정하면 원래의 예측과 결과를 확인한 뒤 만든 설명을 구분하기 쉬워진다.[S1] 금융 백테스트에서도 이 원칙을 연구 일지에 적용할 수 있다.
개인 연구자가 모든 실험을 공개적으로 사전등록해야 한다는 뜻은 아니다. 타임스탬프가 남는 노트나 Git 커밋, 실험 추적 도구 등으로 계획과 변경 이력을 보존할 수 있다. 다만 어떤 기록 방식이 가장 신뢰성이 높은지는 현재 근거만으로 비교할 수 없다.
| 선기록 항목 | 적어야 할 질문 |
|---|---|
| 가설 | 어떤 정보가 왜 다음 기간의 목표와 연결될 것이라고 예상하는가? |
| 반증 조건 | 어떤 결과가 나오면 가설을 지지하지 않는다고 판단할 것인가? |
| 데이터 시점 | 각 특징은 의사결정 전에 이용 가능했는가? |
| 기준선 | 무엇과 비교해야 추가적인 개선을 주장할 수 있는가? |
| 분할 규칙 | 학습·검증·최종 테스트의 날짜와 순서는 무엇인가? |
| 평가 기준 | 어떤 지표와 집계 규칙으로 후보를 선택할 것인가? |
| 탐색 예산 | 전략·특징·기간·파라미터 조합을 최대 몇 개 시험할 것인가? |
| 최종 테스트 | 언제 열며, 결과를 본 뒤 무엇을 수정하지 않을 것인가? |
선기록의 목적은 탐색을 금지하는 것이 아니다. 결과를 보고 새로운 아이디어를 얻는 탐색적 분석도 유용하다. 다만 그것을 처음부터 정한 확증 가설처럼 제시하지 않고 사전 계획과 사후 탐색을 구분해야 한다.[S1]
선기록이 잘못된 가설을 옳게 만들지는 않는다.[S1] 대신 결과에 맞춰 질문을 바꾸고도 처음부터 그 질문을 검증한 것처럼 기억하는 일을 어렵게 만든다.
복잡한 모델보다 기준 전략을 먼저 정한다
복잡한 모델을 만들기 전에 연구 대상과 비교 가능한 기준 전략을 정한다. 백테스트 성과를 비교할 때 전략과 다른 시장이나 투자유형을 대표하는 벤치마크를 사용하면 비교의 의미가 훼손될 수 있다.[S2]
매수 후 보유가 모든 연구의 유일한 기준은 아니다. 연구 질문에 따라 비교 가능한 기준이 달라진다.
| 연구 질문 | 가능한 기준 전략 |
|---|---|
| 자산을 단순히 보유하는 것보다 나은가? | 같은 자산과 기간의 매수 후 보유 |
| 예측 모델이 필요한가? | 전일 값 유지, 장기 평균, 항상 같은 예측 |
| 복잡한 모델을 비교하려는가? | 같은 목표를 다루는 단순 규칙이나 축약 모델 |
예를 들어 상승·하락 분류 모델을 평가한다면 같은 표본과 목표를 사용하는 단순 예측 규칙이 비교 대상이 될 수 있다. 복잡한 신호를 자산 보유와 비교하려면 같은 자산과 같은 기간을 사용하는 벤치마크가 필요하다.
기준선도 결과를 본 뒤 유리한 것으로 교체하면 선택 과정의 일부가 된다. 따라서 무엇과 비교할지는 연구 질문과 함께 미리 기록한다.[S1][S2][S9]
학습·검증·테스트: 공부, 모의고사, 봉인된 기말시험
세 구간은 이름보다 역할로 구분해야 한다.
학습 구간모델 계수와 전처리 통계를 적합한다.검증 구간특징·규칙·파라미터·창 길이와 후보를 선택한다.최종 테스트 구간선택을 모두 끝낸 뒤 최종 결과를 확인한다.학습 데이터는 모델을 적합하는 데 사용한다. 검증 데이터는 여러 후보 가운데 무엇을 채택할지 결정하는 데 사용한다. 테스트 데이터는 선택을 모두 끝낸 뒤 최종 일반화 결과를 확인하는 데 사용한다.[S3]
이를 공부, 모의고사, 봉인된 기말시험에 비유할 수 있다. 모의고사 결과를 보고 공부 방법을 고치는 것은 정상이다. 그러나 기말시험 문제와 점수를 본 뒤 답안을 수정하고 같은 시험을 다시 치르면 그 시험은 더 이상 독립적인 최종 평가가 아니다.
금융 시계열에서는 역할뿐 아니라 순서도 중요하다.
과거 미래|--------- 학습 ---------|---- 검증 ----|-- 최종 테스트 --|스케일러의 평균과 표준편차, 결측 대체값, 특징 선택 기준과 모델 계수는 해당 학습 구간 안에서만 추정해야 한다. 전체 데이터로 전처리를 먼저 적합하면 테스트 정보가 학습 파이프라인에 들어가 평가가 지나치게 낙관적으로 편향될 수 있다.[S4]
학습·검증·테스트의 예시 비율을 보편적인 최적값으로 받아들여서는 안 된다.[S3] 각 구간의 구체적인 길이는 개별 실험에서 별도로 설계하고 검증해야 한다.
테스트 결과를 본 순간, 사람도 학습 과정에 들어간다
다음 과정은 흔히 일어난다.
최종 테스트 확인→ 결과가 마음에 들지 않음→ 파라미터·특징·규칙 수정→ 같은 테스트 재확인코드가 테스트 행에 직접 fit되지 않았더라도 사람은 첫 번째 테스트 결과에서 정보를 얻었다. 그 정보를 바탕으로 특징이나 파라미터를 바꾸면 테스트 데이터가 모델 선택에 간접적으로 영향을 준다.[S3][S4]
따라서 그 시점부터 해당 구간은 독립적인 최종 테스트라기보다 사실상 검증 데이터가 된다. 이 경우에는 다음 중 하나가 필요하다.
- 아직 사용하지 않은 더 나중 기간을 새 테스트 구간으로 지정한다.
- 실제 시간이 흐른 뒤 새로 관측된 자료로 전진 검증한다.
- 새 데이터가 없다면 결과를 “최종 검증 완료”가 아니라 “기존 테스트에 적응한 탐색 결과”로 표시한다.
새 미사용 구간에 필요한 보편적인 길이는 현재 근거에서 확인되지 않았다. 따라서 구체적인 길이는 검증된 공통 기준이 아니라 개별 연구에서 명시해야 할 미확인 설계 판단으로 남는다.
테스트를 다시 봤다고 연구 전체가 무효가 되는 것은 아니다. 다만 이미 확인한 구간의 지위를 솔직하게 바꿔야 한다. 테스트라는 이름은 파일명이나 날짜가 아니라 그 데이터가 선택 과정에서 실제로 사용됐는지에 의해 결정된다.
금융 시계열에서 랜덤 분할이 질문을 바꾸는 이유
일반적인 머신러닝 예제에서는 데이터를 섞은 뒤 일부를 학습용, 나머지를 평가용으로 나누기도 한다. scikit-learn의 train_test_split도 기본적으로 데이터를 섞는다.[S6]
시간 인덱스가 있는 자료에 이 기본 설정을 그대로 적용하면 다음과 같은 구조가 생길 수 있다.
랜덤 분할학습: 1, 3, 4, 7, 9평가: 2, 5, 6, 8, 10시간 순서 분할학습: 1, 2, 3, 4, 5, 6, 7평가: 8, 9, 10랜덤 분할에서는 2번 시점을 평가하면서 그보다 뒤인 3·4·7·9번 시점으로 모델을 학습할 수 있다. 일반적인 교차검증도 시계열에 그대로 적용하면 미래 관측으로 학습하고 과거 관측을 평가하는 fold를 만들 수 있다.[S5]
하지만 실전의 예측 질문은 대체로 다음과 같다.
과거까지 알고 있었을 때, 그다음 기간을 어떻게 예측했는가?
이 질문을 재현하려면 평가 시점보다 뒤의 관측을 학습에 넣지 않아야 한다.[S5][S7] 개별 특징에 미래값이 직접 포함되지 않았더라도 랜덤 학습 집합에는 미래 국면에서 관찰된 분포나 변수 관계가 들어갈 수 있다. 이는 모델이 실제 예측 시점에는 이용할 수 없었던 후기 자료에 노출될 가능성이 있다는 해석이다.
그렇다고 랜덤 분할이 모든 분석에서 잘못이라는 뜻은 아니다. 독립·동일분포에 가까운 횡단면 문제 등에서는 연구 목적에 따라 적절할 수 있다.[S6] 문제는 과거에서 미래를 예측하는 상황을 재현해야 할 때 무비판적으로 섞는 것이다.
랜덤 분할이 언제나 더 높은 점수를 만든다는 법칙도 없다. 공식 지연 특징 예제에서는 랜덤 분할이 시간 기반 평가보다 낙관적인 오차를 보였지만, 이는 자전거 수요 데이터에서 관찰된 사례다.[S8] 금융 데이터에서 차이의 방향과 크기를 일반화할 수 없다.
한 번 나누기와 Walk-Forward Validation은 무엇이 다른가
가장 단순한 시간 분할은 과거 구간에서 한 번 학습하고 그 뒤의 구간에서 한 번 평가하는 방식이다.
고정 분할[──────── 학습 ────────][──── 평가 ────]Walk-forward validation은 예측 기준점을 앞으로 이동시키며 각 평가 구간보다 앞선 자료로 학습하고 그다음 구간을 평가하는 과정을 반복한다.[S5][S7][S13]
Fold 1 [학습────][평가]Fold 2 [학습────────][평가]Fold 3 [학습────────────][평가]여러 예측 시점의 오차를 모아 평가할 수 있다는 것이 이 절차의 핵심 구조다.[S7] 창을 구성하는 대표적인 방법에는 expanding window와 rolling window가 있다.
| 방식 | 시간적 구조 | 조건부 해석과 설계상 확인점 |
|---|---|---|
| 고정 분할 | 한 번의 과거 학습 뒤 한 번의 미래 평가 | 단일 평가기간의 결과만 관찰한다. 그 기간의 대표성은 별도로 확인해야 한다. |
| Walk-forward | 기준점을 이동하며 과거 학습과 다음 구간 평가를 반복 | 여러 시점의 결과를 관찰한다. 계산 부담과 fold 간 관계에 관한 평가는 구현과 자료에 따라 달라질 수 있다. |
| Expanding window | 학습 시작점은 고정하고 종료점을 앞으로 이동해 과거 표본을 누적 | 이전 관측을 계속 포함한다. 오래된 자료를 유지하는 영향은 구조 변화가 있는 자료에서 별도로 검증해야 한다. |
| Rolling window | 고정 길이의 최근 구간을 이동하며 다음 구간을 평가 | 오래된 관측을 제외한다. 최근 변화에 대한 민감도와 적절한 창 길이는 실증적으로 확인해야 한다. |
표의 셋째 열은 각 출처가 특정 방식의 성능 우위를 입증했다는 뜻이 아니다. 분할의 시간적 구조와 금융 자료에서 구조 변화가 존재할 수 있다는 점을 바탕으로 한 조건부 설계 해석이다.[S5][S7][S13]
TimeSeriesSplit의 기본 구조에서는 뒤의 학습 세트가 앞선 학습 세트의 상위집합이 되므로 expanding window와 유사하게 관측을 누적한다.[S5] Rolling window는 이동하는 일정 길이의 과거 구간에서 적합하고 이후 기간을 평가하는 구조로 사용할 수 있다.[S13]
금융 자료에는 구조 변화가 있을 수 있지만, 이것이 expanding 또는 rolling 방식 중 하나가 항상 우월하다는 뜻은 아니다.[S13] 여러 창 길이를 시험했다면 각 길이도 탐색한 후보 수에 포함해야 한다.[S9][S10]
다음과 같은 설계를 고려할 수 있다.
개발 구간 안에서는 walk-forward로 후보를 비교하고, 가장 뒤의 미사용 기간은 별도의 최종 테스트로 남긴다.
이는 자료를 종합한 연구 설계 권고이며 모든 백테스트의 유일한 정답은 아니다.[S3][S5][S7][S13]
많이 찾아볼수록 우연히 좋아 보이는 전략을 만난다
아무 실력 없는 후보라도 충분히 많이 시험하면 일부는 우연히 좋아 보일 수 있다. 백테스트에서는 다음 항목을 바꿀 때마다 새로운 후보를 하나 더 확인한 셈이 된다.
- 전략 규칙과 입력 특징
- 데이터 시작일과 종료일
- 보유기간과 진입·청산 기준
- 모델과 파라미터
- 창 방식과 창 길이
- 후보 선택 지표
같은 데이터를 반복해서 추론과 모델 선택에 사용하면 만족스러운 결과가 방법의 실질적인 우월성보다 우연 때문에 나타날 수 있다. 이를 데이터 스누핑 문제라고 부른다.[S9]
시험한 전략 설정이 많아질수록 뛰어난 모의 성과를 우연히 발견하고 백테스트에 과적합할 가능성도 커진다.[S10][S11] 시도한 설정 수가 공개되지 않으면 독자는 최종 결과가 처음 시험한 하나인지, 수백 개 가운데 가장 좋은 하나인지 알 수 없다.[S10]
다중 검정은 이 문제를 통계적 관점에서 보여 준다. 많은 금융 요인을 검정하면 단일 가설에 사용하던 판단 기준만으로 거짓 발견 위험을 충분히 반영하지 못할 수 있으며, 검정 사이의 상관도 고려해야 한다.[S12]
개인 백테스트에서 정식 p-value를 계산하지 않더라도 선택 문제는 사라지지 않는다. 다만 탐색 결과가 모두 거짓인 것도 아니고, 탐색 횟수만으로 거짓 발견 확률을 자동 계산할 수도 없다. 후보 사이의 관계와 표본, 성과 분포, 선택 규칙도 함께 고려해야 한다.[S10][S12]
성공한 전략보다 탐색의 전체 경로를 기록한다
연구 일지에는 최종 승자의 설정값뿐 아니라 다음 항목을 함께 기록한다.
- 사전에 계획한 후보 수와 실제 실행 수
- 특징·기간·파라미터와 창 길이의 탐색 범위
- 중간에 버린 후보와 실패한 실험
- 수동으로 확인한 그래프와 결과 수
- 후보 선택 기준
- 탐색을 멈춘 시점과 이유
- 테스트 구간을 처음 확인한 시점
- 테스트 확인 뒤 발생한 코드·특징·규칙 변경
- 사전 가설과 사후 탐색의 구분
실패한 실험은 최종 결과가 어떤 선택 경로를 거쳐 살아남았는지 보여 주는 기록이다.[S9][S10][S11] 탐색 예산을 넘겨야 한다면 기존 계획을 지우지 말고 변경 시점과 이유를 추가한다.[S1]
기록만으로 과적합이 사라지는 것은 아니다. 그러나 전체 경로가 있어야 결과의 선택 과정을 평가할 수 있다.[S1][S10][S11]
작은 재현 실험: 같은 모델, 다른 분할
이 실험의 목적은 높은 점수를 내는 모델을 찾는 것이 아니다. 같은 시계열 특징과 같은 모델을 유지한 채 분할 방식만 바꾸고 두 평가가 어떤 질문을 하는지 확인한다.
실제 종목 가격 대신 고정 시드의 인공 시계열을 사용한다. 앞 구간과 뒤 구간에서 lag1과 목표값의 관계가 달라지도록 구성한다. 전처리는 각 학습 집합 안에서만 적합되도록 Pipeline에 넣는다.[S4]
import numpy as npimport pandas as pdfrom sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import accuracy_scorefrom sklearn.pipeline import make_pipelinefrom sklearn.preprocessing import StandardScalerrng = np.random.default_rng(42)n = 600# 교육용 인공 시계열x = rng.normal(size=n)noise = rng.normal(scale=0.8, size=n)# 중간 이후 lag1과 목표의 관계가 달라지도록 구성score = np.empty(n)score[:400] = 0.9 * np.roll(x, 1)[:400] + noise[:400]score[400:] = -0.4 * np.roll(x, 1)[400:] + noise[400:]df = pd.DataFrame({"x": x})df["lag1"] = df["x"].shift(1)df["target"] = (score > 0).astype(int)df["regime"] = np.where(df.index < 400, "early", "late")df = df.dropna().reset_index(drop=True)X = df[["lag1"]]y = df["target"]def make_model(): return make_pipeline( StandardScaler(), LogisticRegression(), )# 1) 랜덤 분할idx = rng.permutation(len(df))cut = int(len(df) * 0.8)random_train = idx[:cut]random_test = idx[cut:]random_model = make_model()random_model.fit(X.iloc[random_train], y.iloc[random_train])random_accuracy = accuracy_score( y.iloc[random_test], random_model.predict(X.iloc[random_test]),)# 2) 시간 순서 분할time_cut = int(len(df) * 0.8)time_train = np.arange(time_cut)time_test = np.arange(time_cut, len(df))time_model = make_model()time_model.fit(X.iloc[time_train], y.iloc[time_train])time_accuracy = accuracy_score( y.iloc[time_test], time_model.predict(X.iloc[time_test]),)print({ "random_split_accuracy": random_accuracy, "time_split_accuracy": time_accuracy, "random_test_index_range": ( int(random_test.min()), int(random_test.max()), ), "time_test_index_range": ( int(time_test.min()), int(time_test.max()), ),})for name, rows in { "random_train": random_train, "random_test": random_test, "time_train": time_train, "time_test": time_test,}.items(): print(f"\n{name}") print(df.iloc[rows]["regime"].value_counts())scikit-learn의 기본 랜덤 분할은 여러 시점을 두 집합에 섞을 수 있고, 시간 순서 분할은 이전 구간에서 학습한 뒤 다음 구간을 평가하도록 구성할 수 있다.[S5][S6] 공식 지연 특징 예제에서도 같은 특징과 모델을 사용해 두 분할이 다른 일반화 오차를 만드는 사례가 제시돼 있다.[S8]
코드를 실행한 뒤 숫자보다 먼저 다음 표를 채워 본다.
| 확인 항목 | 랜덤 분할 | 시간 순서 분할 |
|---|---|---|
| 학습 인덱스 | 전체 기간에 흩어짐 | 앞 구간에 집중 |
| 평가 인덱스 | 전체 기간에 흩어짐 | 마지막 구간에 집중 |
| 후기 국면의 학습 포함 | 포함될 수 있음 | 분할 시점 이전까지만 포함 |
| 평가 질문 | 섞인 표본에서의 일반화 | 과거 학습 후 미래 기간 예측 |
| 정확도 | 실행값 기록 | 실행값 기록 |
데이터 시점과 국면 구성을 확인한다
랜덤 평가 집합의 인덱스는 전체 기간에 흩어지고 랜덤 학습 집합에도 후기 국면의 행이 들어갈 수 있다. 모델이 미래의 정확한 순서를 배우는 것은 아니지만, 실제 예측 시점에는 아직 관측하지 못했을 후기 국면의 표본에 노출된다.
시간 평가 집합은 마지막 20%에 놓이고, 학습에는 그보다 앞선 자료만 사용된다. 이는 과거를 학습한 뒤 아직 보지 못한 다음 기간을 평가하는 질문에 더 가깝다.[S5]
두 정확도가 다르더라도 모델이나 특징의 우월성을 뜻하지 않는다. 달라진 것은 학습·평가 데이터의 시점과 국면 구성이다. 랜덤 점수가 더 높다면 후기 국면 일부가 학습 집합에 들어간 점과 두 집합의 국면 구성이 달라진 점을 함께 살펴봐야 한다. 이 실험만으로 각 원인의 기여도를 분리할 수는 없다.
랜덤 점수가 더 높지 않아도 실험은 실패가 아니다. 공식 사례의 차이를 금융시장에 일반화할 수 없으며, 핵심은 어느 분할이 “과거까지만 알고 미래를 예측한다”는 질문을 재현하는가에 있다.[S8]
시간 순서로 나눈 뒤에도 전체 기간으로 전처리나 특징 선택을 수행하면 누수가 남는다.[S4] 레이블이 여러 기간에 걸쳐 겹칠 때 필요한 분할 간 간격의 보편값 역시 현재 근거만으로 정할 수 없다.[S5]
나의 판단 변화: 최고 수익률에서 반증 가능한 절차로
| 단계 | 지금의 기록 |
|---|---|
| 이전 생각 | 가장 높은 누적수익률 그래프를 찾는 것이 백테스트의 목표라고 생각했다. 그러나 백테스트는 실제 운용성과가 아닌 가상 성과다.[S2] |
| 이번에 확인한 것 | 후보를 많이 시험할수록 운 좋은 결과를 선택할 수 있고, 같은 테스트를 반복해서 보면 그 테스트도 선택 과정에 들어간다.[S3][S4][S9][S10][S11][S12] |
| 현재 판단 | 가설·기준선·분할·평가 기준·탐색 예산·최종 테스트 규칙을 먼저 고정해야 결과의 의미를 설명할 수 있다.[S1][S2][S3][S9][S10] |
| 아직 모르는 것 | 어떤 창 길이와 시장 국면이 앞으로 유효할지, 한 역사 표본이 미래를 얼마나 대표할지는 알 수 없다.[S8][S13] |
내 판단은 “더 좋은 모델을 찾자”에서 “모델이 틀릴 기회를 보호하자”로 바뀌었다. 어떤 창 방식과 길이가 앞으로 적절할지, 새 테스트 구간에 얼마의 기간이 필요한지에 대한 보편적인 답은 확인되지 않았다.[S13]
이 불확실성을 숨기지 않는 것 역시 검증의 일부다.
다음 백테스트 전에 작성할 한 페이지 연구 일지
아래 템플릿은 결과가 나온 뒤 작성하는 보고서가 아니라 첫 번째 백테스트 전에 작성하는 설계 문서다.
내 가설:반증으로 받아들일 결과:데이터와 각 특징의 이용 가능 시점:기준 전략:학습 기간:검증 기간과 walk-forward 규칙:Expanding 또는 rolling window 선택과 이유:최종 테스트 기간:평가 지표와 후보 선택 기준:탐색할 전략·특징·기간·파라미터:최대 탐색 횟수:실패한 실험을 기록할 위치:최종 테스트를 처음 열 조건:테스트를 본 뒤 수정하지 않을 항목:수정이 필요할 때 확보할 새 미사용 구간:사전 가설과 사후 탐색의 표시 방법:사용할 때는 계획 변경 전의 기록을 지우지 않고 변경 시점과 이유를 남긴다. 코드로 실행한 후보뿐 아니라 결과를 보고 수행한 수동 변경도 탐색 횟수에 포함한다. 테스트를 확인한 뒤 전략을 변경했다면 해당 구간을 검증 데이터로 재분류하고, 새 미사용 기간을 확보하지 못했다면 그 한계를 명시한다.[S3][S4]
수수료·스프레드·시장충격과 위험 지표는 실제 성과 해석에 중요하지만 다음 5편에서 다룬다. 이번 편의 범위는 평가할 미래를 어떻게 보호할 것인지 정하는 데 있다.
결론: 좋은 백테스트는 틀릴 기회를 보호한다
다음 백테스트를 시작하기 전에는 다섯 가지를 먼저 기록하려 한다.
- 가설과 반증 조건.[S1]
- 연구 대상과 비교 가능한 기준 전략.[S2]
- 학습·검증·최종 테스트의 역할과 시간 순서.[S3][S4][S5]
- 실패한 실험을 포함한 전체 탐색 횟수.[S9][S10][S11][S12]
- 최종 테스트를 열 조건과, 확인 후 수정했을 때의 처리 규칙.[S3][S4]
처음에는 가장 높은 그래프를 찾는 것이 목표라고 생각했다. 지금은 가설·기준선·시간 분할·탐색 횟수와 최종 테스트 규칙을 결과보다 먼저 고정했을 때만 그 그래프가 무엇을 의미하는지 설명할 수 있다고 판단한다.
좋은 백테스트는 최고 수익률을 고르는 절차가 아니라, 미리 정한 질문을 미래 정보 없이 공정하게 반증하려는 절차다. [S1][S3][S4][S5]
Sources
- [S1] The preregistration revolution | Proceedings of the National Academy of Sciences / Brian A. Nosek 외 | 2018 | https://doi.org/10.1073/pnas.1708274114 ↩
- [S2] Investor Bulletin: Performance Claims | U.S. Securities and Exchange Commission, Office of Investor Education and Advocacy | 2022-02-17 | https://www.investor.gov/introduction-investing/general-resources/news-alerts/alerts-bulletins/investor-bulletins-47 ↩
- [S3] Datasets: Dividing the original dataset | Google for Developers | 2025 | https://developers.google.com/machine-learning/crash-course/overfitting/dividing-datasets ↩
- [S4] Common pitfalls and recommended practices | scikit-learn developers | 게시·수정일 미표기; 조사 시점 안정판 1.9.0 문서 | https://scikit-learn.org/stable/common_pitfalls.html ↩
- [S5] TimeSeriesSplit | scikit-learn developers | 게시·수정일 미표기; 조사 시점 안정판 1.9.0 문서 | https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.TimeSeriesSplit.html ↩
- [S6] train_test_split | scikit-learn developers | 게시·수정일 미표기; 조사 시점 안정판 1.9.0 문서 | https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html ↩
- [S7] Time series cross-validation | Rob J. Hyndman, George Athanasopoulos / OTexts | 제3판 2021; 온라인판은 지속 갱신 | https://otexts.com/fpp3/tscv.html ↩
- [S8] Lagged features for time series forecasting | scikit-learn developers | 게시·수정일 미표기; 조사 시점 안정판 1.9.0 예제 | https://scikit-learn.org/stable/auto_examples/applications/plot_time_series_lagged_features.html ↩
- [S9] A Reality Check for Data Snooping | Econometrica / Halbert White | 2000-09 | https://doi.org/10.1111/1468-0262.00152 ↩
- [S10] Pseudo-Mathematics and Financial Charlatanism: The Effects of Backtest Overfitting on Out-of-Sample Performance | Notices of the American Mathematical Society / David H. Bailey, Jonathan M. Borwein, Marcos López de Prado, Qiji Jim Zhu | 2014-05; SSRN 최종 수정 2014-04-14 | https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2308659 ↩
- [S11] The probability of backtest overfitting | The Journal of Computational Finance / David H. Bailey, Jonathan M. Borwein, Marcos López de Prado, Qiji Jim Zhu | 2017 | https://escholarship.org/uc/item/4w1110bb ↩
- [S12] … and the Cross-Section of Expected Returns | Campbell R. Harvey, Yan Liu, Heqing Zhu / National Bureau of Economic Research | NBER Working Paper 20592, 2014-10; 동료평가판 2016 | https://www.nber.org/papers/w20592 ↩
- [S13] Backtesting & Simulation | CFA Institute | 2026 | https://www.cfainstitute.org/insights/professional-learning/refresher-readings/2026/backtesting-and-simulation ↩
오류 제보·의견 보내기
글 제목과 주소가 포함된 메일 초안을 엽니다. 내용과 받는 사람을 확인한 뒤 보내주세요.
받는 사람: [email protected]
메일 앱에서 작성메일 앱이 열리지 않으면 아래 내용을 복사해 평소 쓰는 이메일에 붙여 넣으세요.
관련 글
퀀트·데이터 연구 로지스틱 회귀는 기준선을 넘을까? 공정한 모델 비교의 조건
로지스틱 회귀와 기준 전략을 공정하게 비교하기 위한 시간축, 데이터 분리, 재학습과 비용 계산 규칙을 정리합니다. 실제 성과 검증에 앞서 고정할 실험 설계입니다.
퀀트·데이터 연구 거래비용을 넣어도 결론은 같을까: 합성 포트폴리오의 회계와 위험경로 검사
합성 포트폴리오에 거래비용을 적용해 매수대금과 현금 장부를 점검합니다. 종료수익, 회전율, 최대낙폭이 각각 무엇을 보여주는지 구분합니다.