백테스트 +50%인데 실거래 -10% — 80%가 떨어지는 7가지 진짜 이유
자동매매 의뢰의 60% 이상이 "백테스트 결과는 좋은데 실거래 결과는 다르다"는 시점에 시작됩니다. 백테스트에서 연 +50% 찍은 봇이 실거래에서 -10% 손실이면, 60%pt 격차가 발생한 셈입니다. 문제는 이게 예외 사례가 아니라 거의 기본값이라는 점입니다.
이 글은 알고랩이 자동매매 봇 제작·운영 의뢰를 받으며 본 백테스트와 실거래 격차의 7가지 핵심 원인과, 본인 백테스트가 함정에 빠졌는지 진단하는 체크리스트를 정리합니다. 백테스트 결과가 너무 좋게 나오신다면 이 글의 7가지 중 몇 개에 해당하는지부터 점검해보세요.
왜 백테스트 +50%가 실거래 -10%가 되는가
학계 연구·업계 데이터 모두 일관되게 다음을 보여줍니다.
- 아마추어 트레이더의 자동매매 봇 80%는 실거래에서 백테스트의 절반 이하 수익률로 떨어진다
- 그중 절반은 실거래에서 손실로 전환된다
- 가장 흔한 원인 7가지가 전체 격차의 90%를 차지한다
아래 7가지가 그것입니다. 하나씩 보면서 본인 봇이 해당되는지 점검해보세요.
이유 1. 슬리피지를 0으로 가정함
호가창에서 실제로 체결되는 가격은 백테스트 가격과 다르다
백테스트 라이브러리 대부분은 봉의 종가나 시가로 정확히 체결됐다고 가정합니다. 그러나 실거래에서 시장가 주문은 호가창의 매도호가를 잡아먹으며 평균 단가가 올라갑니다.
예시: BTC 현재가 $60,000. 시장가 매수 1 BTC 주문.
- 호가창 1단계 $60,000 - 0.3 BTC 매도
- 호가창 2단계 $60,100 - 0.5 BTC 매도
- 호가창 3단계 $60,250 - 0.2 BTC 매도
실제 평균 체결가 = (60,000 × 0.3 + 60,100 × 0.5 + 60,250 × 0.2) / 1 = $60,100. 0.17% 슬리피지. 진입+청산 합치면 0.3~0.5%, 빈번한 매매(스캘핑·그리드)에선 연 누적 10~30%까지 갉아먹습니다.
알트코인이나 한국주식 비유동 종목에서는 슬리피지가 1~5%까지 갈 수 있습니다.
해법
- 백테스트에 슬리피지 가정 추가 — 메이저 코인 0.1%, 알트 0.3~1%
- 호가창 데이터 보유 시 → 호가창 깊이 가중 평균 가격으로 시뮬레이션
- 실거래에선 시장가 대신 호가 1~2단계 이내 지정가 사용으로 슬리피지 통제
이유 2. 수수료·세금이 누락되거나 부정확함
거래 빈도가 높을수록 수수료가 수익을 모두 갉아먹는다
흔히 빠뜨리는 비용 4가지:
- 메이커 vs 테이커 — 메이커 0.02%, 테이커 0.075% 같은 차이를 평균값으로 처리하면 부정확
- 거래세·증권거래세 — 한국주식 매도 시 0.18% (KOSPI/KOSDAQ)
- 출금 수수료 — 거래소 간 자금 이동 시 BTC 0.0005 등 누적
- 환전 비용 — KRW ↔ USDT P2P 거래 시 0.5~1% 스프레드
매일 5번 매매하는 봇이라면 연 1,825번 거래. 한 번당 수수료 0.1% 가정해도 누적 182.5% — 즉 자본금 전부를 수수료로 낼 정도의 거래량입니다. 백테스트는 정확한 거래소별 수수료 + 세금 모두 차감해야 합니다.
해법
- 거래소별 메이커/테이커 정확한 수수료표 적용
- 한국주식 백테스트는 매도 시 거래세 0.18% 차감
- 해외주식은 매매 차익 양도세(연 250만원 공제 후 22%) 별도 시뮬레이션
- 실현 수익 = (총 수익 - 수수료 - 세금 - 슬리피지) 기준으로만 평가
이유 3. 룩어헤드 바이어스 (Look-ahead Bias)
"미래의 정보로 과거를 매매"하는 백테스트의 가장 흔한 함정
가장 자주 발생하는 버그입니다. 봉이 확정되기 전에 그 봉의 정보를 사용하는 패턴.
예시: 일봉 RSI(14) ≤ 30 진입 전략.
- 일봉의 RSI는 그 날의 종가가 확정되어야 계산 가능 (KOSPI는 15:30)
- 그런데 백테스트에서 같은 일봉의 종가로 매수했다고 가정하면, 종가가 정해진 시점(15:30)에 매수한 것 → 실거래에서는 불가능
- 실거래 가능 시점: 다음 날 09:00 시가
- 이 하루 갭으로 인한 가격 차이가 백테스트 수익률을 인위적으로 부풀림
흔한 실수 코드
# X 룩어헤드 함정
for i in range(len(df)):
if df["rsi"][i] <= 30: # 같은 시점의 RSI
df["entry"][i] = df["close"][i] # 같은 시점의 종가로 매수
# → 종가 확정 시점 = RSI 확정 시점 = 매수 시점이 모두 같음
# O 안전한 패턴
for i in range(len(df) - 1):
if df["rsi"][i] <= 30: # i 봉의 RSI 신호
df["entry"][i+1] = df["open"][i+1] # i+1 봉의 시가로 매수
Pine Script도 마찬가지. strategy.entry()는 다음 봉 시가에 체결되도록 기본 설정되어 있지만,
plot()으로 신호를 시각화할 때는 같은 봉에 그려져서 시각적 착시가 발생합니다.
해법
- 신호 발생 시점과 매매 시점을 다른 봉(다음 봉 시가)으로 분리
- 백테스트 결과 시각화 시 매수 표시는 다음 봉 위치에
- vectorbt·Backtrader 등 라이브러리 사용 시
execute_on_close=False등 명시
이유 4. 생존자 편향 (Survivorship Bias)
"오늘 상장된 종목"만으로 과거를 백테스트하면 결과가 인위적으로 좋아진다
현재 상장 종목 리스트로 5년 전부터 백테스트했다면, 그 5년 사이에 상장폐지된 종목은 이미 빠진 상태입니다. 실제 5년 전에 매매하던 사람은 그 종목들도 보유했고, 그중 상당수가 0원이 되었습니다.
- KOSDAQ에서 연 50~100개 종목 상장폐지 — 5년이면 250~500개
- 코인은 더 심함 — 50% 이상 코인이 1년 안에 거래량 0 또는 상장폐지
- 2017~2018 ICO 코인 99%가 사라짐
"오래된 코인만으로 백테스트하면 수익률 +500%"라는 결과는 거의 대부분 생존자 편향입니다. 실제로 그 시기에 운용했다면 상장폐지된 코인들에 자금이 묶여 큰 손실을 봤을 가능성이 큽니다.
해법
- 과거 시점의 실제 상장 리스트로 백테스트 (어렵지만 정확)
- 상장폐지된 종목 데이터셋(예: 한국 KOSDAQ 상폐 종목 리스트) 별도 확보
- 차선: 백테스트 결과를 20~30% 할인해서 해석 (생존자 편향 보정)
이유 5. 과최적화 (Overfitting)
파라미터를 과거 데이터에 맞춰 조정하다가 미래에는 망하는 패턴
"RSI 14가 좀 약한데... 12로 바꾸니 백테스트 +20%! 손절 2%도 1.5%로 줄이니 +30%! ..." 이런 식으로 파라미터를 계속 조정하다 보면 과거 데이터의 노이즈에만 맞춰진 봇이 됩니다. 미래 데이터에서는 작동하지 않습니다.
과최적화의 신호:
- 백테스트 연 수익률 +100% 이상 (대부분 과최적화)
- 드로다운(MDD)이 비현실적으로 작음 (-5% 이하)
- 승률 80%+ — 시장은 그렇게 친절하지 않다
- 파라미터를 1만 바꿔도 결과가 크게 변함 (파라미터 안정성 부족)
해법
- Train/Test split — 전체 데이터의 70%로 파라미터 정하고, 나머지 30%로 검증
- Walk-forward Analysis — 1년 데이터로 학습 → 다음 3개월 검증 → 윈도우 이동 반복
- 파라미터 그리드 분석 — RSI 12·13·14·15·16 모두 양호한 결과가 나와야 robust
- Out-of-sample 테스트 — 모르는 기간(예: 가장 최근 6개월)에서 검증
경험칙: 백테스트 결과가 "너무 좋게" 나오면 99% 과최적화입니다. 실거래에서 백테스트의 30~50%만 나와도 성공적인 결과로 봐야 합니다.
이유 6. 시장 체제 변화 (Regime Change)
과거 시장 환경이 미래에도 반복된다는 가정의 함정
2020~2021 코인 강세장에서 "BTC 사서 보유" 봇이 +500% 찍었다고 합시다. 같은 봇을 2022 약세장에 돌리면 -65%. 같은 코드, 다른 시장 → 정반대 결과.
시장 체제 변화의 예시:
- 변동성 변화 — 2020 코로나 시기 일일 변동성 ↑ vs 2024 비교적 안정
- 유동성 변화 — 강세장 거래량 ↑ vs 약세장 거래량 -70%
- 상관관계 변화 — 평소엔 BTC ↔ 알트 동조, 위기엔 모두 하락
- 규제 변화 — 트래블룰, 거래소 폐쇄, 세금 등
- 시장 참여자 변화 — 기관 진입, 옵션 시장 확대
해법
- 다양한 시장 환경(강세 1년 + 약세 1년 + 횡보 1년) 백테스트
- 변동성·거래량 등 시장 체제 지표를 백테스트 결과에 분리 분석
- 실거래 중 시장 체제 감지 → 변화 시 자동 정지·전략 전환
- "모든 시장에서 작동"은 환상 — 본인 봇의 작동 조건을 명시화
이유 7. 실거래 실행 실패 (Execution Gap)
백테스트는 매번 완벽히 매매한다고 가정하지만 실거래는 그렇지 않다
실거래에서만 발생하는 격차:
- 부분 체결 — 100주 매수 주문 중 30주만 체결 → 봇이 100주 보유로 인식하면 오류
- 주문 거부 — Rate limit, 잔고 부족, 시간외 등 다양한 이유
- API 장애 — 거래소 점검, 네트워크 끊김 시 신호 무시
- 인간 개입 — 손실 누적 시 봇 중단, 파라미터 즉흥 변경
- 호가창 변화 — 백테스트의 정적 가격 vs 실시간 변동
- 시간 지연 — 신호 발생 → 주문 전송 → 체결까지 100ms~수초
해법
- 백테스트에 부분 체결·주문 거부·재시도 시뮬레이션 포함
- API 장애 시 자동 대응 로직(재연결, 신호 큐잉)
- 인간이 개입하지 않도록 시스템 신뢰 구축 (작은 자본부터 시작)
- 주문 실행 latency 측정 + 백테스트에 반영
본인 백테스트 자가 진단 체크리스트
본인 백테스트가 7가지 함정에 빠졌는지 점검:
BACKTEST QUALITY CHECK
- 슬리피지 0.1~0.5% 가정했는가
- 수수료 메이커/테이커 정확히 적용했는가
- 세금 (한국주식 거래세, 해외 양도세 등) 포함했는가
- 봉 확정 시점과 매매 시점을 다른 봉으로 분리했는가
- 백테스트 종목이 당시 실제 상장된 리스트인가
- Train/Test split 또는 Walk-forward 적용했는가
- 파라미터 ±10% 변경해도 결과가 안정적인가
- 다양한 시장 환경(강세·약세·횡보) 모두 테스트했는가
- 부분 체결·API 장애 시뮬레이션 포함했는가
- 백테스트 결과가 너무 좋게 나오지 않는가 (연 +100% 이상 → 의심)
10개 중 6개 이상 체크되지 않는다면, 백테스트 결과를 액면 그대로 믿지 마세요. 실거래는 백테스트의 30~50% 수준으로 떨어질 가능성이 큽니다.
알고랩 표준 — 백테스트와 실거래 차이 줄이는 방법
알고랩이 의뢰받은 봇 제작 시 표준으로 적용하는 패턴:
1. 호가창 시뮬레이션
가능한 거래소(바이낸스·바이비트 등 L2 호가창 제공)에서 호가창 데이터로 슬리피지 시뮬레이션. 백테스트 가격 = 호가창 깊이 가중 평균.
2. 정확한 거래소별 수수료표
의뢰자 등급별 메이커/테이커 수수료 + 한국주식 거래세 + 해외 양도세까지 모두 차감.
3. 안전한 신호 사용 시점
봉 확정 시점 = 시그널 사용 시점이 아닌, 다음 봉 시가에서 체결되도록 표준 설계.
4. Walk-forward Analysis 기본
1년 학습 → 3개월 검증 → 윈도우 이동. 파라미터 안정성도 함께 확인.
5. 부분 체결·재시도 시뮬레이션
주문 100% 즉시 체결이 아닌, 호가창 깊이 기반 부분 체결 + 재시도 로직 백테스트 포함.
6. 시장 체제 감지
변동성·거래량 등 지표로 시장 체제 감지. 봇이 작동하지 않는 체제(예: 극단적 변동성)에서는 자동 정지.
7. 실거래 초기 1~2주 데이터로 백테스트 vs 실거래 비교
실거래 후 백테스트와 실거래의 거래별 비교 리포트 자동 생성. 격차 5% 이상 시 알림.
마무리 — 백테스트는 "필요조건"이지 "충분조건"이 아니다
잘 만든 백테스트는 "이 전략이 실거래에서 성공할 가능성이 있다"는 신호일 뿐, 보장이 아닙니다. 백테스트 +50%가 실거래 +20%로 나오면 매우 성공적이고, +10%면 평균, 0%~음수면 흔한 결과입니다.
이 글의 7가지 원인을 모두 점검하고 백테스트를 다시 돌렸을 때 결과가 절반으로 줄었다면, 그게 진짜에 가까운 수치입니다. 그 수치로 실거래 의사결정을 하시면 손실 확률이 크게 낮아집니다.
알고랩 무료 백테스트 검토: 본인 백테스트 코드나 결과 리포트가 있으시면 알고랩이 무료로 검토해드립니다. 위 7가지 함정 중 어디에 해당하는지 짚어드리고, 실거래 전환 가능성을 함께 판단합니다.