한국 중형주 저PBR 밸류 전략을 페이퍼로 굴리고 있었습니다. 백테스트는 꽤 좋았습니다 — OOS Sharpe 0.77, 초과수익 +51.3%, 종목 수를 10에서 30까지 흔들어도 견고. 그래서 사전등록 문서를 쓰고, 규칙을 잠그고, 월 1회 리밸런싱을 돌리기 시작했습니다.
한 달 뒤 원장을 열었습니다.
n=1 cum_excess=-3.43%p sharpe=4.82(벤치 4.81) mdd=5.6%
state=running decidable=false required_n=nullrequired_n이 null입니다.
당신 실험의 "필요 표본" 칸은 지금 채워져 있습니까? 저는 그 칸을 만들어 놓고 한 번도 안 채웠습니다.
null은 "아직 모른다"가 아니었다
코드를 보니 이유는 단순했습니다. 필요 표본을 포워드 월간 초과의 표준편차로 계산하는데, 관측이 1개라 표준편차가 안 나옵니다. 그래서 None.
기술적으로는 맞습니다. 그런데 이건 "데이터가 모자라서 못 구한다"가 아니라 "다른 데서 구할 생각을 안 했다" 입니다. 같은 전략의 백테스트가 8년치 있었으니까요.
사전등록한 전략 그대로(중형 저PBR 상위 20종목, 벤치는 전체 유동성 적격 동일가중) 월간 초과 시계열을 뽑아서 계산했습니다.
| 구간 | n(월) | 평균 초과/월 | sd/월 | 연환산 초과 | 필요 n |
|---|---|---|---|---|---|
| 전체 | 104 | 0.76% | 3.94% | +9.1% | 703개월 ≈ 59년 |
| IS 2018–2022 | 60 | 0.63% | 3.19% | +7.5% | 461개월 ≈ 38년 |
| OOS 2023–2026H1 | 42 | 0.80% | 4.37% | +9.6% | 863개월 ≈ 72년 |
사전등록한 최소효과(MDE)는 연 +5%p입니다. 월로 나누면 0.417%p. 그런데 월간 초과의 잡음은 약 4%p — 신호의 10배입니다.
관대하게 봐서, MDE 말고 백테스트에서 실제로 관측된 엣지(+9.6%/년)를 검출하는 것으로 낮춰도 235개월, 약 20년입니다.
옳은 수정이 실험을 죽였다
여기가 이 이야기에서 제일 불편한 부분입니다.
3주 전에 저는 이 게이트를 강화했습니다. 원래 PASS 조건은 "누적초과 > 0 그리고 Sharpe > 벤치 Sharpe"라는 부호 비교였습니다. 그 규칙은 표본이 몇 개든 항상 판정을 내놓습니다. 그게 우연과 구분되는지는 묻지 않고요.
계기가 있었습니다. 대시보드가 관측 1개짜리 연율화 Sharpe 27.84를 KPI로 띄우고 있었습니다. 읽는 사람이 "이기고 있다"로 오독하기 딱 좋았습니다. 그래서 PASS 조건에 하나를 더했습니다 — 월간 초과 평균의 부트스트랩 95% CI 하한 > 0.
조건을 더한 것이니 골포스트 이동이 아닙니다. 판단도 맞다고 지금도 생각합니다.
그런데 그 강화가 이 실험을 구조적으로 판정 불가로 만들었습니다. 이제 게이트가 낼 수 있는 결말은 둘뿐입니다.
- kill 발화(누적초과 ≤ −15%p 또는 MDD > 40%) → 중단
- 영원히 판정 불가 — PASS는 도달할 수 없음
kill이 발화할 확률도 낮습니다. 월간 sd가 4%p면 3개월 누적 초과의 sd는 약 6.9%p이고, kill 임계 −15%p는 영가설 아래 2.2σ쯤 됩니다.
즉 저는 끝나지 않는 실험을 돌리고 있었습니다. 매달 리밸런싱하고, 대시보드에 초록불이 켜지고, "검증 중"이라는 외양이 유지되는.
여기서 당신이라면?
세 갈래가 있었습니다.
- 게이트를 다시 느슨하게 — 부호 비교로 되돌린다.
- 백테스트를 최종 증거로 받아들이고 소액 실계좌로 넘어간다.
- 끈다.
1번은 못 합니다. 그건 결과를 보고 기준을 바꾸는 것이고, 애초에 그 부호 비교가 잡음을 승리로 읽던 그 규칙입니다.
2번은 진지한 선택지였습니다. 이 전략이 앞으로 가질 증거는 백테스트가 전부니까요 — 포워드 페이퍼는 여기에 통계적 증거를 추가할 수 없습니다. 그렇다면 페이퍼를 계속 돌리는 건 정보를 만들지 않으면서 시간만 씁니다.
저는 3번을 골랐습니다.
−3.43%p는 지고 있다는 뜻이 아니다
폐기하면서 한 가지는 분명히 해두고 싶습니다. 원장의 누적 초과 −3.43%p는 진 게 아닙니다. 월간 sd 4% 기준으로 0.85σ, 완전한 잡음입니다.
"판정 불가"와 "실패"는 다릅니다. 이 봇은 실패하지 않았습니다. 애초에 성공할 수도 실패할 수도 없는 설계였습니다.
이겨도 마찰이 다 먹는다는 게 확정돼서 봇을 껐습니다와는 다른 경우입니다. 그때는 엣지의 크기가 문제였습니다(이겨도 최소효과 미달). 이번엔 크기가 아니라 잡음 대비 신호비가 문제입니다. 어떤 현실적 기간에도 판정이 안 됩니다.
실험을 설계했더니 통계적으로 불가능했다와는 같은 계열인데, 그때는 착수 전에 잡았습니다. 이번엔 한 달 돌린 뒤에 잡았습니다. 차이는 그 계산을 언제 했느냐뿐입니다.
자가진단 3개
- 당신 실험의 필요 표본 칸이 채워져 있습니까? 비어 있다면, 못 구하는 겁니까 아니면 안 구한 겁니까?
- 포워드 데이터가 모자라 분산을 못 구한다면, 백테스트나 과거 로그로 추정할 수 있습니까? 대개 있습니다.
- 당신의 최소효과와 관측 단위당 잡음(sd)의 비는 얼마입니까? 그 비율 하나가 판정 기간을 정합니다 — 1:10이면 수백 관측이 필요합니다.
솔직한 부분
이 계산은 10분 걸렸습니다. 착수 전에 했으면 이 봇은 태어나지 않았거나, 다른 검정(순위상관·적중률처럼 관측이 훨씬 많은 통계량)으로 설계됐을 겁니다.
안 한 이유는 게을러서가 아니라 필요 표본 칸을 만들어 뒀기 때문입니다. 칸이 있으니 언젠가 채워질 거라고 믿었습니다. null은 "곧 채워짐"처럼 보이지, "아무도 안 물었음"처럼 보이지 않습니다.
그리고 일반화 하나. 월간 리밸런싱 주식 팩터 전략은 월간 초과 t검정으로는 개인의 시간 안에 검증되지 않습니다. 이건 이 전략의 특성이 아니라 그 검정 설계의 특성입니다. 백테스트가 아무리 좋아도, 포워드로 "증명"하겠다는 계획은 산수를 먼저 해봐야 합니다.
코드·백테스트·데이터·원장은 전부 남겼습니다. 지운 건 스케줄과 감시판 행뿐입니다.
지금 딱 하나만 해보세요. 지금 돌아가는 실험 하나를 골라 최소효과 ÷ 관측당 sd를 계산해 보시기 바랍니다. 그 비의 제곱의 약 8배가 필요 관측 수입니다.