백테스트 가격 데이터 품질 — 결측봉·이상치·거래소 차이가 성적을 바꾼다
백테스트 결과가 이상하면 대개 규칙부터 다시 봅니다. 그런데 숫자를 틀어 놓는 쪽은 규칙이 아니라 규칙에 먹인 데이터인 경우가 많습니다. 같은 코드에 같은 기간을 넣어도, 데이터를 어디서 어떻게 받았느냐에 따라 성적표가 달라집니다.
먼저 봉의 개수를 센다
데이터를 받으면 차트부터 그려 보게 됩니다. 눈으로 보면 대개 멀쩡해 보입니다. 1분봉 몇십만 개 중에 몇천 개가 빠져 있어도 화면에서는 티가 나지 않기 때문입니다. 그래서 첫 점검은 그림이 아니라 개수여야 합니다.
1분봉 1년치 기대 개수
60 × 24 × 365 = 525,600봉
실제 수집된 행 수
519,000봉
빠진 봉
525,600 − 519,000 = 6,600봉
비율 = 6,600 ÷ 525,600 = 1.26%
하루로 환산하면
6,600 ÷ 1,440 = 4.6일치
─────────────
1.26%가 4.6일치다
1.26%라고 하면 작아 보이지만, 그 구멍이 고르게 흩어져 있는 경우는 드뭅니다. 대개는 거래소 점검 시간이나 급등락 구간처럼 특정한 상황에 몰려 있습니다. 하필 변동성이 가장 컸던 날들이 통째로 빠져 있으면, 그 데이터로 잰 최대 낙폭은 실제보다 작게 나옵니다.
그래서 결측은 총 개수만 세고 끝내면 안 되고 어디에 몰려 있는지까지 봐야 합니다. 일자별로 봉 개수를 세어 1,440개가 아닌 날을 목록으로 뽑는 것이 가장 빠릅니다. 1,440개에서 크게 모자란 날이 몇 개 나오면 그 날짜가 무슨 날이었는지 확인해 보는 편이 좋습니다.
구멍을 어떻게 메우느냐가 신호 수를 바꾼다
빠진 봉을 처리하는 방법은 크게 셋입니다. 그냥 건너뛰기, 직전 종가로 채우기, 그 구간을 통째로 빼기입니다. 셋 다 틀린 방법은 아니지만 결과가 다르게 나옵니다.
가장 위험한 것은 직전 종가로 채우기입니다. 시가·고가·저가·종가가 전부 같은 값인 봉이 생기는데, 이것은 "그 1분 동안 가격이 전혀 움직이지 않았다"는 뜻입니다. 실제로는 데이터가 없었을 뿐입니다. 이런 봉이 많아지면 변동성 지표가 실제보다 낮게 나오고, 변동성을 기준으로 진입을 거르는 전략은 걸러야 할 구간을 통과시킵니다.
정상 1분봉 평균 절대수익률
0.09%
1,440봉 중 60봉이 채워진 날
채운 봉의 수익률 = 0%
그 날 평균
(1,380 × 0.09 + 60 × 0) ÷ 1,440
= 0.0863%
→ 실제보다 4.2% 낮게 측정
변동성 하한 0.087% 필터라면
정상 데이터 통과
채운 데이터 탈락
─────────────
같은 날이 필터에서 갈린다
반대로 건너뛰기는 시간 간격이 일정하지 않게 됩니다. 20봉 이동평균이 어떤 구간에서는 20분치고 어떤 구간에서는 80분치가 됩니다. 지표를 봉 개수로 계산하는 전략이라면 이쪽이 더 문제입니다. 지표가 구간마다 다른 의미를 갖게 되는 문제는 지표 리페인팅에서 다루는 것과 뿌리가 비슷합니다.
현실적인 기본값은 이렇습니다. 연속 결측이 3봉 이하면 건너뛰고, 그보다 길면 그 구간 전체를 백테스트에서 제외합니다. 제외한 구간은 따로 기록해 두고 성적을 보고할 때 "며칠을 뺐다"를 같이 적습니다. 빼고 잰 성적을 빼지 않은 성적처럼 말하면 그 자체가 생존 편향이 됩니다.
한 틱짜리 심지가 손절을 건다
두 번째 문제는 이상치입니다. 어느 1분봉의 저가가 직전 종가보다 12% 아래인데, 종가는 멀쩡한 자리로 돌아와 있는 경우가 있습니다. 호가창이 잠깐 비었을 때 시장가 주문 하나가 체결된 흔적입니다. 실제로 거래된 수량은 몇 계약뿐입니다.
문제는 백테스트가 이 봉을 정상으로 읽는다는 점입니다. 저가가 손절 가격을 지났으니 체결됐다고 판정합니다. 실전이었다면 그 가격에 내 물량이 다 나갔을 리가 없는데, 기록에는 −1R짜리 패배가 하나 더 찍힙니다.
진입가 $100.00
손절가 $98.00 (−2%)
문제의 1분봉
시가 $99.90 · 고가 $99.95
저가 $88.00 · 종가 $99.88
거래량 3계약
(직전 60봉 중앙값 1,200계약)
백테스트 판정
저가 $88 < 손절 $98 → 손절 체결
1년에 이런 봉이 8번 걸리면
−1R × 8 = −8R
1R이 계좌 0.5%면 −4%
─────────────
없던 손실 4%가 생긴다
반대 방향도 있습니다. 위로 튄 심지가 목표가를 찍어서 없던 승리가 생기기도 합니다. 이쪽이 더 위험합니다. 성적이 좋아지는 오류는 의심하지 않고 넘어가기 쉽기 때문입니다.
거르는 기준은 가격만으로 잡으면 안 되고 거래량을 같이 봐야 합니다. 진짜 급락은 거래량이 같이 터집니다. 직전 종가 대비 심지가 ±5% 이상 벌어졌는데 그 봉의 거래량이 직전 60봉 중앙값의 10% 미만이면 의심 봉으로 표시합니다. 자동으로 지우지 말고 목록으로 뽑아 눈으로 한 번 보는 편이 안전합니다. 실제 급락 구간을 이상치로 지워 버리면 그때부터는 손실이 없는 데이터로 백테스트를 하게 됩니다.
거래소마다 같은 분의 종가가 다르다
세 번째는 출처입니다. 같은 종목, 같은 1분이어도 거래소마다 종가가 다릅니다. 체결이 각자 다른 호가창에서 일어나기 때문입니다. 평소에는 차이가 작지만 변동성이 큰 순간에는 벌어집니다.
같은 1분 종가
거래소 A $100.00
거래소 B $100.08 (+0.08%)
전략 조건: 4시간 전 대비 −6% 하락
4시간 전 가격 $106.40 기준
A (100.00 ÷ 106.40) − 1 = −6.02% → 신호
B (100.08 ÷ 106.40) − 1 = −5.94% → 없음
임계 근처 신호가 전체의 12%라면
연 300건 중 약 36건이 갈린다
─────────────
데이터 출처를 바꾸면 성적도 바뀐다
여기서 얻을 교훈은 "어느 거래소 데이터가 정확한가"가 아닙니다. 둘 다 그 거래소에서는 사실입니다. 중요한 것은 백테스트에 쓴 데이터와 실제로 주문을 넣을 거래소가 같아야 한다는 점입니다. A 거래소 데이터로 검증하고 B 거래소에서 돌리면, 신호가 갈리는 만큼 성적이 달라집니다.
선물이라면 한 가지가 더 있습니다. 거래소가 청산과 손절 판정에 쓰는 가격은 마지막 체결가가 아니라 지수 기반의 마크가격인 경우가 많습니다. 체결가 기준으로 백테스트해 놓고 마크가격으로 청산되는 계좌에서 돌리면 또 어긋납니다. 주문이 실제로 어떤 단위로 들어가는지는 틱사이즈와 최소 주문수량 쪽에 정리돼 있습니다.
시간 축이 틀리면 전부 무의미해진다
마지막이 가장 조용하게 성적을 부풀립니다. 봉에 붙은 시각이 그 봉의 시작 시각인지 끝 시각인지는 데이터 제공처마다 다릅니다. 시작 시각으로 라벨된 데이터를 끝 시각이라고 읽으면, 09:00 라벨의 봉을 09:00에 이미 다 본 것처럼 쓰게 됩니다. 실제로 그 봉이 끝나는 시각은 09:01입니다.
1분이 뭐 대수냐 싶지만, 이것이 바로 미래참조입니다. 진입 판단에 그 시점에는 아직 확정되지 않은 값을 쓰는 것이기 때문입니다. 자세한 구조는 룩어헤드 편향과 봉 마감 확정 쪽에 있습니다.
원본 데이터 UTC 기준
내 코드 KST로 가정
차이 = 9시간
결과
09:00 신호로 기록된 거래가
실제로는 18:00 데이터
검증 방법
알려진 급등일의 분봉을 찾아
고점 시각이 맞는지 대조
─────────────
9시간이면 하루 성격이 통째로 바뀐다
확인 방법은 단순합니다. 뉴스로 시각이 알려진 급등락 하나를 골라 데이터에서 그 시각의 봉을 찾아봅니다. 고점이 기대한 시각에 있으면 시간 축이 맞는 것이고, 9시간이나 그 밖의 일정한 간격만큼 밀려 있으면 시간대 변환이 잘못된 것입니다. 이 대조는 데이터를 새로 받을 때마다 한 번씩 해 두면 좋습니다.
받자마자 돌리는 점검 절차
① 봉 개수 기대치와 대조
일자별 1,440개 아닌 날 목록
② 중복 같은 타임스탬프 2행 이상
있으면 수집 스크립트 문제
③ 정합성 고가 ≥ 시가·종가 ≥ 저가
깨지면 그 행은 폐기
④ 이상치 심지 ±5% + 거래량 하위
목록으로 뽑아 눈으로 확인
⑤ 시간 축 알려진 사건과 대조
라벨이 시작인지 끝인지 확정
⑥ 출처 실거래 예정 거래소와 일치
다르면 성적 비교 금지
─────────────
여섯 개 다 통과해야 백테스트를 돌린다
①~③은 코드로 자동화할 수 있고, 통과 여부만 로그에 남기면 됩니다. ④는 자동으로 지우지 말고 사람이 보고, ⑤와 ⑥은 데이터를 새로 받을 때 한 번씩 확인합니다. 이 여섯 개를 통과하지 않은 데이터로 나온 성적은 규칙의 성적이 아니라 데이터의 성적입니다.
그리고 점검을 통과했다고 해서 백테스트 결과가 믿을 만해지는 것은 아닙니다. 데이터가 깨끗해도 조건을 여러 번 바꿔 가며 제일 좋은 것을 고르면 다시 처음으로 돌아갑니다. 그쪽 문제는 다중검정의 함정과 백테스팅 하는 법에 따로 정리돼 있습니다. 데이터 점검은 필요 조건이지 충분 조건이 아닙니다.
정리
② 1분봉 1년치 기대값은 525,600봉이다
③ 519,000봉이면 6,600봉(1.26%)이 비어 있다
④ 결측은 총량보다 어디에 몰렸는지가 중요하다
⑤ 직전가로 채우면 변동성 0인 가짜 봉이 생긴다
⑥ 그 날 평균 변동성이 0.09%에서 0.0863%로 낮아진다
⑦ 그 차이로 변동성 필터의 통과 여부가 갈린다
⑧ 3봉 초과 결측 구간은 빼고, 뺀 사실을 같이 적는다
⑨ 거래량 없는 심지가 손절을 걸어 −1R을 만든다
⑩ 연 8번이면 1R 0.5% 기준 −4%가 없던 손실로 생긴다
⑪ 위로 튄 심지가 만드는 가짜 승리가 더 위험하다
⑫ 이상치 기준은 가격 ±5% + 거래량 하위를 같이 본다
⑬ 같은 분 종가가 거래소마다 0.08% 다를 수 있다
⑭ 백테스트 데이터와 실거래 거래소는 같아야 한다
⑮ 봉 라벨이 시작인지 끝인지 모르면 미래참조가 된다
한 줄로 줄이면 이렇습니다. 백테스트는 데이터를 검증하는 도구가 아니라, 검증된 데이터를 전제로 규칙을 재는 도구입니다. 순서를 바꾸면 규칙이 아니라 수집 스크립트의 버그를 최적화하게 됩니다.
주의
본문의 기대 봉 개수 525,600개와 실제 519,000개, 결측 6,600봉과 1.26%·4.6일치, 평균 절대수익률 0.09%와 채운 뒤의 0.0863%, 변동성 하한 0.087%, 진입가 $100·손절가 $98과 저가 $88·거래량 3계약·중앙값 1,200계약, 연 8회에서 나온 −8R과 −4%, 거래소 A·B의 $100.00과 $100.08, 4시간 전 $106.40 기준 −6.02%와 −5.94%, 임계 근처 비율 12%와 연 300건 중 36건, 시간대 차이 9시간 같은 수치는 점검 방법의 계산 구조를 보여주기 위한 가정 예시이며 특정 거래소·특정 종목·특정 기간의 실제 측정값이 아닙니다. 결측 허용 기준 3봉, 이상치 기준 ±5%와 거래량 10%는 예시일 뿐 보편적인 기준이 아니며, 종목의 유동성과 봉 주기에 따라 달라져야 합니다. 이상치 필터를 세게 걸면 실제 급락 구간까지 지워져 손실이 과소평가될 수 있으므로 자동 삭제는 권하지 않습니다. 이 글은 데이터 점검 절차에 대한 설명이며 특정 종목·방향이나 진입·청산 시점을 권유하지 않습니다. 데이터를 깨끗하게 만든다고 해서 수익이 생기지는 않으며, 점검을 통과한 데이터에서 나온 백테스트 성적도 실전 성과를 보장하지 않습니다. 암호화폐 거래는 원금 전액을 잃을 수 있고 레버리지를 쓰면 손실이 증거금을 넘을 수도 있습니다. 투자 판단과 그 결과는 본인 책임입니다.
NOONOO TRADING 무료 채팅방에서 실시간 트레이딩을 같이 보세요.
봇에서 시작하기📈 OKX 신규 가입 시 거래 수수료 할인
OKX 수수료 할인 가입 →