sgkstudio.
엔지니어링

백테스트 레짐 필터 — 약세장 손실을 줄이고도 탈락시킨 이유

백테스트 레짐 필터는 약세장 손실을 -30.98%에서 -10.66%로 줄였지만, 우리는 이 전략을 실전에 넣지 않기로 했습니다. 약세장 표본이 단 한 번뿐이라, 그 한 번을 흑자로 맞추는 튜닝은 과적합밖에 남기지 않기 때문입니다. 이 글은 숫자가 좋아 보이는데도 탈락시킨 과정과, 그 판정마저 나중에 평가 틀 문제로 정정한 사실까지 순서대로 적습니다.

2026-10-07처음 잰 숫자 — 필터 없는 전략: 약세 구간(2024년 하반기) -30.98%, 같은 구간 코스피 -14.44%, 강세 구간(2025~2026년 상반기) +115.23%측정 방법 — 필터 3방식(off·hard·soft) × 시장 구간 2개 스윕, 왕복 비용 0.43%, 유닛 테스트 14/14, 시간 손절 25분 추가필터 효과 — 약세 구간 hard -10.66%(+20.3pp 복구, 코스피 대비 -16.5pp→+3.78pp), 강세 구간 +114.09%, 거래 1,308→939건(-28%), equity Sharpe 1.80→2.29가설 기각 — 사전에 정한 기준(약세장 수익률 0 초과) 미달, 약세 구간 3방식 모두 p_ttest>0.6·부트스트랩 신뢰구간이 0을 걸침. 강세 구간은 3방식 모두 p 0.008~0.013로 유의진짜 원인 — 분봉 데이터가 2024-04-18부터라 약세장 표본이 단 1개, 그 표본에 맞춘 파라미터 탐색은 n=1 과적합부수 발견 — 코스피 지수 파일 끝 값 파손(close=7648.1, 실제 약 2600)으로 강세 구간 코스피 대비 열이 -118pp로 뒤집힘(실제 코스피 +6%), top10 기여도 100.0 고정한계 — 이 보류 판정은 이후 평가 틀 오류로 정정됨

무엇이 문제였나 — 약세장에서만 크게 잃는 전략

백테스트 레짐 필터는 약세장 손실을 3분의 1 수준으로 줄였지만, 우리는 이 결과를 실전 투입 근거로 쓰지 않았습니다. 약세장 성적이 여전히 손실이었고, 그 손실이 줄어든 것조차 통계적으로 우연과 구분하지 못했으며, 무엇보다 시험해 볼 약세장이 단 한 번뿐이었기 때문입니다. 아래에서 그 결론에 이른 순서를 숫자와 함께 적습니다.

우리 주식 자동매매 시스템에는 분봉 데이터로 진입 시점과 청산 시점을 정하는 단기 매매 전략 후보가 하나 있었습니다. 이 후보는 앞선 검토에서 진입 규칙과 청산 규칙 각각에 쓸 만한 강점이 있다는 판정을 받았습니다. 진입 규칙은 시장이 오르든 내리든 성질이 크게 변하지 않았고, 청산 규칙은 차트 모양이 달라도 규율이 유지됐습니다.

문제는 수익의 출처였습니다. 강세장에서는 큰 수익을 냈지만, 시장 전체가 내리는 구간에서는 지수보다도 더 크게 잃었습니다. 개별 매매 규칙이 멀쩡해도 시장 전체가 흘러내리는 날에는 진입 자체가 손실로 이어지기 쉽습니다. 실전에 넣을 전략이라면 다음 약세장에서 계좌가 얼마나 줄어드는지를 먼저 알아야 했습니다.

강세장에서만 버는 전략이 위험한 이유는 수익률 계산의 비대칭 때문입니다. 계좌가 30% 줄면 원금으로 돌아오는 데 30%가 아니라 그보다 큰 상승이 필요합니다. 게다가 실전에서는 다음 국면이 강세일지 약세일지 미리 알 수 없으니, 약세장 손실이 큰 전략은 시작 시점을 잘못 고르는 순간 회복할 시간이 모자랄 수 있습니다.

그래서 전략을 세 겹으로 정리했습니다. 첫째 층은 시장 국면과 무관하게 쓰는 진입 규칙, 둘째 층은 차트 모양과 무관하게 지키는 청산 규칙, 셋째 층이 이번 글의 주인공인 레짐 필터입니다. 레짐 필터는 코스피의 최근 20일 흐름을 매일 계산해, 그 값이 기준을 넘지 못하면 그날 신규 진입을 막는 장치입니다.

처음 잰 숫자 — 필터 없이 약세장 -30.98%

측정은 같은 전략을 두 시장 구간에 각각 돌리는 방식으로 했습니다. 약세 구간은 2024년 하반기, 강세 구간은 2025년부터 2026년 상반기까지입니다. 매매 한 번을 사고팔 때마다 왕복 비용 0.43%를 빼고 계산했고, 시뮬레이션 코드의 유닛 테스트 14개를 모두 통과한 상태에서 돌렸습니다.

필터를 끄고(off) 돌린 결과가 출발점입니다. 약세 구간 수익률은 -30.98%였습니다. 같은 기간 코스피는 -14.44%였으니, 전략이 지수보다 16.5pp 더 잃은 셈입니다. 반대로 강세 구간에서는 +115.23%를 냈습니다. 강세장에서 번 돈을 약세장에서 크게 토해 내는 전형적인 모양이었습니다.

통계 카드. 필터 없는 전략의 약세 구간 수익률 -30.98%, 같은 구간 코스피 -14.44%, 강세 구간 수익률 +115.23%
처음 잰 숫자 — 필터 없는 전략의 두 얼굴

이 단계에서 전략 쪽 코드도 손봤습니다. 기존 청산 시뮬레이터를 그대로 재사용하되, 진입 뒤 25분이 지나도 움직임이 없으면 정리하는 시간 손절을 추가했습니다. 그리고 원래는 매매가 끝난 뒤 그날이 어떤 국면이었는지 사후에 분류하던 코스피 20일 지표를, 매매 시점에 바로 쓰는 진입 차단 장치로 끌어올렸습니다. 사후 진단은 결과를 해석하는 데만 쓰이지만, 실시간 차단은 결과 자체를 바꿉니다.

이 전환에는 조건이 하나 붙습니다. 매매 시점에 쓰는 지표는 그 시점까지의 데이터만 봐야 합니다. 사후 분류에서는 구간 전체를 보고 '이 6개월은 약세장'이라고 이름을 붙여도 문제가 없지만, 진입 차단 장치가 미래 데이터를 한 줄이라도 보면 백테스트 성적이 실제보다 좋아집니다. 그래서 지표를 매일 그날까지의 최근 20일로만 계산하는 롤링 방식으로 두었습니다.

어떤 가설을 세웠나?

가설은 단순했습니다. 지수가 내리는 국면에서 신규 진입만 막으면 약세장 손실 대부분이 사라지고, 강세장 수익은 거의 그대로 남는다는 생각이었습니다. 개별 규칙의 강점은 이미 확인했으니, 시장이 나쁠 때 싸움을 피하기만 하면 된다고 봤습니다.

검증 전에 합격선을 먼저 적어 두었습니다. 약세 구간에서 수익률이 0을 넘어야, 즉 손실이 아니라 최소한 본전 이상이어야 실전 후보로 올린다는 기준입니다. 결과를 본 뒤 기준을 고르면 어떤 숫자든 합격으로 포장할 수 있기 때문에, 기준을 먼저 고정하는 사전 등록 방식을 택했습니다.

필터 방식은 세 가지를 나란히 비교했습니다. 필터를 끈 off, 기준을 넘지 못하면 진입을 완전히 막는 hard, 막는 강도를 누그러뜨린 soft입니다. 이 세 방식을 약세·강세 두 구간에 모두 돌려 6개 조합을 만들었습니다. 다만 결정 기록에는 soft의 수익률 숫자가 따로 남아 있지 않아, 이 글의 수치 비교는 off와 hard 두 방식으로 한정합니다.

방식을 하나가 아니라 셋으로 둔 이유도 있습니다. 필터 하나만 시험하면 좋은 결과가 그 설정 하나의 요행인지, 필터라는 발상 전체의 효과인지 가를 수 없습니다. 차단 강도가 다른 방식들이 같은 방향의 결과를 내야 '시장이 나쁠 때 진입을 줄이면 낫다'는 주장에 힘이 실립니다. 실제로 약세 구간 통계 판정과 강세 구간 통계 판정은 세 방식 모두 같은 방향으로 나왔습니다.

  • **off** — 레짐 필터 없음. 비교의 출발점
  • **hard** — 코스피 20일 지표가 기준을 넘지 못하면 그날 신규 진입 차단
  • **soft** — 차단 강도를 누그러뜨린 방식(결정 기록에 수익률 미기재)
  • **합격선** — 약세 구간 수익률 0 초과(사전 등록)

가설은 어디서 틀렸나? — 손실은 줄었지만 흑자는 아니었다

방향만 보면 가설은 맞았습니다. hard 필터를 켜자 약세 구간 수익률이 -30.98%에서 -10.66%로 올라왔습니다. 20.3pp를 되찾은 셈이고, 코스피 대비 성적도 -16.5pp에서 +3.78pp로 뒤집혔습니다. 약세장에서 지수보다 덜 잃는 전략으로 바뀐 겁니다.

막대 그래프. 약세 구간 손실 폭 비교. 필터 없음 -30.98%, 코스피 -14.44%, hard 필터 -10.66%
약세 구간 손실 폭 — 필터가 지수보다 덜 잃게 만들었다

강세 구간에서는 거의 손해가 없었습니다. off +115.23%가 hard +114.09%로 1pp 남짓 내려갔을 뿐입니다. 진입을 막은 날이 있으니 거래 수는 1,308건에서 939건으로 28% 줄었는데, 수익률 변동 대비 성과를 나타내는 계좌 기준 샤프 비율은 오히려 1.80에서 2.29로 올랐습니다. 덜 매매하고 비슷하게 벌었으니 위험 대비 효율이 좋아진 결과입니다.

거래가 줄었다는 사실 자체도 정보였습니다. 강세 구간 안에도 코스피 20일 흐름이 꺾이는 날이 섞여 있고, 필터는 그날들의 진입을 막았습니다. 막힌 매매가 빠졌는데도 수익률이 거의 그대로였다는 말은, 그 매매들이 전체 수익에 기여한 몫이 작았다는 뜻으로 읽었습니다. 필터가 수익원은 남기고 소음만 걸러 낸 모양입니다.

강세 구간 — 필터를 켜도 수익은 거의 그대로
방식수익률거래 수계좌 기준 샤프통계 유의성
off (필터 없음)+115.23%1,308건1.80유의
hard (진입 차단)+114.09%939건2.29유의

강세 구간은 3방식 모두 p 0.008~0.013, 부트스트랩 신뢰구간 하한이 0보다 컸다.

그런데 합격선에서 걸렸습니다. 사전에 정한 기준은 약세 구간 수익률 0 초과였고, 세 방식 중 가장 좋은 hard도 -10.66%였습니다. 손실을 3분의 1 수준으로 줄였어도 손실은 손실입니다. 기준을 먼저 적어 둔 덕분에, 좋아 보이는 개선 폭에 끌려 합격선을 슬쩍 옮기는 일을 피할 수 있었습니다.

두 번째로 걸린 곳은 통계였습니다. 약세 구간은 off·hard·soft 세 방식 모두 t-검정 p값이 0.6을 넘었고, 부트스트랩으로 구한 신뢰구간도 0을 걸쳤습니다. 쉽게 말해 hard가 덜 잃은 차이가 매매 하나하나의 기대 수익이 양수라서 생긴 차이인지, 그 구간의 운으로 생긴 차이인지 구분할 수 없다는 뜻입니다. 결정 기록은 이를 ‘유의한 양의 기대값이 아니라 손실이 작아졌을 뿐’이라고 적었습니다.

hard의 손실완화는 "유의한 양의 기대값"이 아니라 "손실이 작아졌을 뿐".

강세 구간은 정반대였습니다. 세 방식 모두 p값이 0.008~0.013 사이였고 신뢰구간 하한도 0보다 컸습니다. 같은 전략이 강세장에서는 통계적으로 확실한 수익을 내고, 약세장에서는 필터를 켜도 운과 구분되지 않는 손실을 냈습니다.

여기서 '유의하지 않다'와 '효과가 없다'를 섞으면 안 됩니다. 필터는 손실 폭을 눈에 띄게 줄였고 지수를 앞서게 만들었습니다. 다만 그 차이를 근거로 '약세장에서도 이 전략은 기대 수익이 양수'라고 말할 수는 없습니다. 실전 투입은 두 번째 문장이 참이어야 가능한 결정이라, 첫 번째 사실만으로는 부족했습니다.

진짜 원인은 무엇이었나? — 약세장 표본이 단 1개

여기서 자연스러운 다음 수는 튜닝입니다. 20일이라는 레짐 창 길이를 바꾸거나, 진입을 허용하는 기준을 0 초과에서 조금 더 높은 양수로 올리면 약세 구간 -10.66%를 본전 위로 끌어올릴 수 있을지도 모릅니다. 실제로 이 방향을 검토 대안 첫 번째로 올렸습니다.

그 대안을 거부한 이유가 이 글의 핵심입니다. 우리가 가진 분봉 데이터는 2024-04-18부터만 있습니다. 그 기간 안에서 약세장이라고 부를 만한 구간은 2024년 하반기 하나뿐이었습니다. 약세장 표본 수가 1개라는 뜻입니다.

표본이 하나뿐일 때 파라미터를 바꿔 가며 그 표본에서 흑자가 나는 조합을 찾으면, 거의 반드시 하나쯤은 찾아냅니다. 문제는 그 조합이 약세장 일반에 통하는 설정인지, 2024년 하반기라는 특정 6개월의 굴곡에만 맞춘 설정인지 구분할 길이 없다는 점입니다. 결정 기록은 이를 n=1 레짐 과적합, 교과서적인 사례라고 불렀습니다.

흐름도. 사전 기준 약세장 수익률 0 초과 확인, hard -10.66%로 미달, 튜닝 검토, 약세장 표본 1개 확인, 과적합 위험으로 튜닝 거부, 실전 보류와 도구 보존으로 이어짐
판정 흐름 — 튜닝 대신 보류를 고른 경로

이 벽은 이번에 처음 만난 벽이 아니었습니다. 앞선 검토에서 이 전략을 다시 실전 후보로 올리려면 두 조건 중 하나가 필요하다고 정해 두었습니다. 하나는 2022년이나 2023년처럼 다른 시장 국면을 담은 데이터, 다른 하나는 학습에 쓰지 않은 완전한 약세 또는 횡보 구간 하나 이상입니다. 세 겹 정책 백테스트도 결국 같은 벽 앞에서 멈췄습니다.

돌아보면 ‘필터가 약세장을 막아 준다’는 가설 자체는 틀리지 않았습니다. 틀린 곳은 그 가설을 확인할 수 있다고 믿은 부분이었습니다. 약세장이 하나뿐인 데이터로는 ‘약세장에서 안전한 설정’을 검증할 수 없고, 더 돌리는 튜닝은 새 정보 없이 과적합 위험만 키웁니다.

튜닝의 비용도 따져 봤습니다. 창 길이 후보 몇 개와 기준값 후보 몇 개만 곱해도 조합은 금세 수십 개로 늘어납니다. 조합을 하나 시험할 때마다 그 단 하나의 약세 구간을 한 번 더 들여다보는 셈이라, 시험이 늘수록 '우연히 맞은 조합'을 '좋은 조합'으로 착각할 확률도 함께 커집니다. 표본이 늘지 않는 한 시험 횟수는 정보가 아니라 위험입니다.

조치 — 튜닝하지 않고 보류, 도구는 남겼다

결론은 실전 투입 보류였습니다. 현재 운용 중인 기본 전략은 바꾸지 않았고, 이 후보 전략은 실제 주문 경로에 연결하지 않았습니다. 대신 세 겹 정책을 돌리는 백테스트 코드와 테스트는 지우지 않고 남겼습니다.

  • **(a) 레짐 창·기준값 재튜닝으로 약세장 본전 맞추기 — 거부(핵심).** 약세장 표본이 1개라 n=1 과적합
  • **(b) 세 겹 정책 그대로 소액 실전 — 거부.** 약세장 절대 손실이 남고 통계적 유의성도 없음
  • **(c) 전략 폐기 — 거부.** 진입·청산 규칙의 강점은 시장 국면·차트 모양과 무관하게 확인했으므로 자산 가치가 있음
  • **(d) 보류 + 백테스트 도구 보존 — 채택.** 다음 약세·횡보 구간 데이터를 확보하면 같은 코드로 재실행

(c)를 거부한 이유도 적어 둡니다. 실패한 검증이 곧 실패한 전략을 뜻하지는 않습니다. 이번에 확인한 사실은 ‘약세장 안전성을 아직 증명할 수 없다’였지, ‘전략에 강점이 없다’가 아니었습니다. 그래서 다음에 데이터가 쌓였을 때 바로 돌릴 수 있도록 코드를 재실행 1순위 도구로 남겼습니다.

재평가의 문도 구체적으로 적어 두었습니다. 2022년이나 2023년처럼 다른 국면을 담은 데이터를 확보하거나, 이번 실험에 쓰지 않은 약세·횡보 구간이 한 번 이상 새로 쌓이면 같은 코드로 6개 조합을 다시 돌립니다. 이때 합격선은 이번과 마찬가지로 결과를 보기 전에 먼저 적습니다. 조건이 채워지기 전까지는 숫자를 더 좋게 만드는 작업을 하지 않습니다.

이 판단은 개발 일정에도 영향을 줬습니다. 튜닝을 계속했다면 약세 구간 숫자는 매번 조금씩 좋아졌을 테고, 그 개선이 진짜인지 확인할 방법이 없는 상태로 작업 시간만 늘었을 겁니다. 보류를 선택하면서 이 후보에 쓰던 시간을 다른 검증 작업으로 돌릴 수 있었습니다.

과적합 문제는 다른 글에서도 다뤘습니다. 짧은 구간에서 높은 샤프 비율을 낸 전략이 긴 구간에서 어떻게 무너졌는지는 백테스트 과최적화 — 5년 검증 기록에 정리해 두었습니다.

재측정에서 무엇이 드러났나? — 지수 데이터가 깨져 있었다

결과 리포트를 다시 맞춰 보다가 판정과 별개로 데이터 버그 2건을 찾았습니다. 첫 번째는 코스피 지수 파일이었습니다. 파일 끝부분 종가가 7648.1로 들어 있었는데, 실제 코스피는 약 2600 수준이었습니다(결정 기록 기재값). 지수 파일 꼬리 값이 깨져 있었던 겁니다.

통계 카드. 지수 파일 끝 종가 7648.1, 실제 코스피 약 2600, 리포트상 강세 구간 코스피 대비 -118pp, 실제 강세 구간 코스피 +6%
재측정에서 드러난 지수 파일 파손

이 파손 때문에 리포트의 강세 구간 ‘코스피 대비’ 열은 의미가 없었습니다. 리포트는 전략이 코스피보다 118pp 뒤졌다고 표시했지만, 실제 강세 구간 코스피 상승률은 +6%였습니다. 전략이 +114.09%를 냈으니 실제로는 지수를 크게 앞선 결과를, 깨진 데이터가 정반대로 뒤집어 보여 준 셈입니다.

두 번째는 상위 10개 매매의 수익 기여도 지표가 모든 조합에서 100.0으로 평평하게 찍힌 문제였습니다. 이 값은 지표를 계산하는 과정에서 생긴 부산물로 판단했습니다. 수익 집중도를 보려고 넣은 지표가 아무 정보도 주지 못한 상태였습니다.

두 버그 모두 판정은 바꾸지 않았습니다. 약세 구간 판정은 전략 수익률 자체와 통계 검정으로 내렸고, 강세 구간의 코스피 대비 열은 판정 근거로 쓰지 않았기 때문입니다. 영향 범위도 이 전략의 레짐 백테스트 2종에 그쳤고 실제 매매 경로와는 무관했습니다. 그래도 리포트에 두 버그를 명시해, 나중에 그 표를 보는 사람이 -118pp를 사실로 읽지 않게 했습니다.

이 일로 비교 기준 데이터도 검증 대상이라는 사실을 다시 확인했습니다. 전략 코드는 테스트 14개로 지켰지만, 그 결과를 재는 잣대인 지수 파일에는 아무 검사도 없었습니다. 잣대가 깨지면 멀쩡한 전략도 형편없어 보이고, 반대로 형편없는 전략이 멀쩡해 보일 수도 있습니다.

남는 한계 — 이 보류 판정도 나중에 정정했다

이 글의 결론에는 큰 단서가 붙습니다. 이 보류 판정은 이후 다른 검토에서 평가 틀이 잘못됐다는 이유로 정정됐습니다. 이 글에서 쓴 평가 틀은 약세 구간을 따로 떼어 내 그 구간만으로 본전 이상을 요구하는 방식이었습니다. 정정 이후의 결과 수치는 이 글의 재료 범위 밖이라 여기에 옮기지 않습니다.

그래도 이 기록을 지우지 않고 남기는 이유가 있습니다. 첫째, 약세장 표본이 하나뿐이라 튜닝으로 본전을 맞추면 과적합이라는 판단은 평가 틀과 무관하게 유효합니다. 둘째, 사전에 합격선을 적어 두는 습관이 있었기에 오히려 ‘기준 자체가 잘못 잡혔다’는 지적을 정확한 지점에서 받을 수 있었습니다. 기준이 흐릿했다면 무엇을 고쳐야 하는지도 흐릿했을 겁니다.

남은 한계를 정리하면 이렇습니다. 분봉 데이터가 2024-04-18부터라 약세장 표본은 여전히 1개입니다. soft 방식의 수치는 기록에 없어 비교하지 못했습니다. 강세 구간 성과의 코스피 대비 비교는 지수 파일을 바로잡기 전까지 신뢰할 수 없었습니다. 그리고 약세 구간에서 필터가 줄인 손실은 통계적으로 운과 구분되지 않았습니다.

비슷한 백테스트를 읽을 때 우리가 이제 먼저 확인하는 항목도 적어 둡니다. 데이터 안에 약세장이 몇 번 들어 있는가, 합격선을 결과보다 먼저 적었는가, 개선 폭과 별개로 통계 검정을 통과했는가, 비교 기준으로 쓴 지수 데이터 자체는 멀쩡한가. 이번 실험은 네 질문 모두에서 무언가를 배웠습니다.

  • 약세장 표본 1개(분봉 데이터 2024-04-18 이후) — 약세장 안전 설정 검증 불가
  • soft 방식 수익률 미기재 — off·hard만 비교
  • 약세 구간 3방식 모두 p_ttest>0.6 — 손실 감소가 우연과 구분 안 됨
  • 보류 판정 자체가 이후 평가 틀 오류로 정정됨

우리 회사 전략에도 레짐 필터를 붙여야 하나?

시장 국면 필터는 손실 구간을 줄이는 데 분명히 쓸모가 있었습니다. 이번 실험에서도 약세장 손실을 20.3pp 줄이고 강세장 수익은 거의 지켰습니다. 다만 필터의 효과를 검증할 약세장이 데이터에 몇 번 들어 있는지부터 세어 봐야 합니다. 그 수가 1이라면, 숫자를 더 좋게 만드는 튜닝보다 판정을 미루는 쪽이 정직한 선택입니다.

자동매매나 데이터 분석 시스템에서 비슷한 판정 문제를 겪고 있다면 상담으로 상황을 알려 주세요. 백테스트 결과를 어디까지 믿을 수 있는지부터 함께 따져 보겠습니다.

같은 방식으로 우리 업무를 재보고 싶다면

이 글에 쓴 계측·판정·자동화는 저희가 실제로 매일 돌리는 방식 그대로입니다. 어떤 작업을 자동화할 수 있고 어디를 사람이 잡아야 하는지, 현재 업무 흐름을 놓고 같이 짚어 드립니다.

새 글이 올라오면 알려 드립니다

이런 계측 기록을 새로 쓰면 메일로 한 통 보냅니다. 광고나 판촉은 보내지 않습니다.