무엇이 문제였나 — 비상계엄 날, 급락 감지가 울리지 않았다
자동매매 급락 감지 기준을 낮추면 놓친 충격을 잡을 수 있다고 봤지만, 5년치 기록으로 다시 재 보니 기준을 낮춰도 비상계엄 같은 정치적 충격은 잡히지 않고 거래만 더 자주 막혔습니다. 그래서 기준값 -0.60을 그대로 두고, 고쳐야 할 손잡이를 기준값이 아니라 점수를 만드는 가중치 쪽으로 옮겼습니다. 이 글은 그 판단에 이른 순서를 적습니다.
우리 주식 자동매매 시스템에는 시장 전체가 얼마나 흔들리는지를 하나의 점수로 계산하는 장치가 있습니다. 이 점수를 종합 스트레스 점수라고 부르고, 값이 낮을수록 시장이 나쁘다는 뜻입니다. 점수가 정해 둔 기준선 아래로 내려가면 시스템은 시장 상태를 PANIC(공황)으로 판정하고 그날 신규 매매를 막습니다. 실시간 점수 계산기를 매매 필터에 연결하는 배선 작업도 이미 끝나 있었습니다.
문제는 2024-12-04 비상계엄 사태였습니다. 한국 주식시장에 큰 충격이 온 날인데, 그날 종합 스트레스 점수를 다시 계산해 보니 -0.287이었습니다. PANIC 기준선은 -0.60이므로 점수가 기준선 근처에도 가지 않았습니다. 사람이 보기에 명백한 공황이었던 날을 시스템은 평범한 날로 분류한 셈입니다.
이런 장치가 실패하는 방향은 두 가지입니다. 진짜 위험한 날을 놓치면(재현율 부족) 손실이 큰 날에 그대로 매매하고, 멀쩡한 날을 위험하다고 판정하면(오탐) 벌 수 있는 날에 매매를 쉬게 됩니다. 비상계엄 미검출은 첫 번째 실패였고, 가장 먼저 떠오르는 처방은 기준선을 느슨하게 만드는 일이었습니다. 그 처방이 두 번째 실패를 얼마나 키우는지가 이번 검토의 핵심 질문이었습니다.
두 실패의 무게는 같지 않습니다. 충격일을 놓치는 일은 드물게 일어나지만 한 번에 크게 잃을 수 있고, 평범한 날을 막는 일은 한 번의 손해는 작아도 해마다 반복됩니다. 그래서 「재현율을 올리자」는 말만으로는 판단이 서지 않고, 재현율 한 칸을 얻는 데 평범한 날을 며칠 내줘야 하는지가 먼저 나와야 했습니다.
처음 잰 숫자 — 점수 -0.287, 기준선 -0.60
처음 손에 쥔 숫자는 하나뿐이었습니다. 비상계엄 당일 종합 스트레스 점수 -0.287, PANIC 기준선 -0.60. 두 값의 차이가 커서, 기준선을 조금 옮기는 정도로는 이날을 잡을 수 없다는 점은 처음부터 보였습니다. 그래도 기준선을 옮기면 다른 알려진 충격을 더 많이 잡을 수 있는지는 따로 재야 했습니다.

한 사건만 보고 기준선을 고치면 그 사건에 맞춘 규칙이 나옵니다. 그래서 측정 범위를 넓혔습니다. 과거 5년, 1,240 거래일 동안의 종합 스트레스 점수 이력을 날짜별로 다시 만들고, 그 기간 안에서 시장 충격으로 알려진 사건 10건을 골라 정답표로 삼았습니다.
측정 방법은 단순합니다. `simulate_thresholds.py` 라는 시뮬레이션 스크립트가 기준선 후보 5개를 차례로 적용하면서 두 값을 셉니다. 하나는 5년 동안 PANIC이 울린 날의 비율과 일수(오탐 비용), 다른 하나는 알려진 충격 10건 중 몇 건에서 PANIC이 울렸는가(재현율)입니다. 기준선 후보는 -0.60(현재), -0.50, -0.45, -0.40, -0.35였습니다.
정답표를 따로 만든 데에는 이유가 있습니다. 비상계엄 하나만 기준으로 삼으면, 그날을 잡도록 맞춘 기준선은 다른 충격에서 어떻게 움직이는지 알 수 없습니다. 충격 10건을 함께 보면 「기준선을 옮겼더니 몇 건이 새로 잡혔나」를 셀 수 있고, 평범한 날 1,240일 가까이를 함께 보면 「그 대가로 며칠을 더 막았나」를 셀 수 있습니다. 두 숫자를 같은 기간, 같은 점수 이력에서 뽑아야 서로 비교가 됩니다.
어떤 가설을 세웠나?
가설은 하나였습니다. 「PANIC 기준선을 -0.60에서 조금 올리면(덜 엄격하게 만들면), 놓치던 충격을 더 잡으면서도 평범한 날에 울리는 횟수는 크게 늘지 않는다.」 점수가 -0.60과 -0.287 사이에 몰려 있는 충격일이 여럿 있다면 이 가설은 성립합니다.
이 가설이 그럴듯했던 이유도 있습니다. 기준선은 숫자 하나라서 바꾸기 쉽고, 코드 한 줄이면 실매매에 반영할 수 있습니다. 점수 계산식을 뜯어고치는 일보다 훨씬 싸 보였습니다. 바로 그 싸 보이는 성질 때문에, 실제 비용을 숫자로 확인하기 전에는 손대지 않기로 했습니다.
판정은 두 숫자를 함께 놓고 해야 했습니다. 기준선을 옮겨서 재현율이 오르더라도, 그 대가로 매매를 막는 날이 늘어나면 손해입니다. 막힌 날마다 전략이 벌 수 있던 기회를 버리기 때문입니다. 그래서 재현율 상승폭만이 아니라 차단 일수 증가폭도 같은 표에 올렸습니다.
반대로 이 가설이 틀렸다면 표에는 이런 모양이 나타나야 합니다. 기준선을 옮겨도 재현율이 그대로이거나, 재현율이 오르는 지점에서 차단 일수가 크게 뛰는 모양입니다. 그리고 비상계엄 당일이 어느 기준선에서도 잡히지 않는다면, 문제는 기준선이 아닌 다른 곳에 있다고 봐야 합니다.
기준선을 옮기면 무엇이 바뀌었나?
다섯 기준선의 결과를 그대로 옮기면 아래 표와 같습니다. 일수는 5년 1,240 거래일 중 PANIC이 울린 날의 수입니다.

| PANIC 기준선 | 발동 비율 | 발동 일수(5년) | 재현율(충격 10건) |
|---|---|---|---|
| -0.60 (현재) | 1.9% | 24일 | 20% |
| -0.50 | 2.7% | 33일 | 20% |
| -0.45 | 4.4% | 54일 | 30% |
| -0.40 | 7.2% | 88일 | 30% |
| -0.35 | 10.1% | 124일 | 40% |
현재 기준선 -0.60에서 PANIC은 평균 1.5일 연속으로 울렸다.
현재 기준선 -0.60에서 PANIC은 5년 동안 1.9%, 24일 울렸고, 한 번 울리면 평균 1.5일 연속으로 이어졌습니다. 알려진 충격 10건 중 재현율은 20%였습니다. 기준선이 원래 겨냥한 일, 즉 드물게만 울리는 일은 잘 해내고 있었지만 충격을 잡는 능력은 낮았습니다.
-0.50으로 올리면 발동 일수는 33일로 늘지만 재현율은 20% 그대로입니다. 비용만 늘고 얻는 것이 없는 구간입니다. 재현율이 처음 오르는 지점은 -0.45로, 30%가 됩니다. 그 대가로 발동 일수는 54일, 발동 비율은 4.4%로 뜁니다.
더 올려도 모양은 같습니다. -0.40에서는 재현율이 여전히 30%인데 발동 일수는 88일, 7.2%입니다. -0.35까지 가야 재현율이 40%로 오르고, 이때 발동은 124일, 10.1%입니다. 기준선을 한 칸 옮길 때마다 차단 일수는 꾸준히 늘었지만 재현율은 계단식으로, 그것도 두 칸에 한 번꼴로만 올랐습니다.

「평균 1.5일 연속」이라는 숫자도 읽어 둘 만합니다. 현재 기준선에서는 PANIC이 울려도 하루 이틀이면 풀립니다. 기준선을 느슨하게 하면 발동 일수만 늘어나는 것이 아니라, 시장이 조금 불안한 기간 내내 매매가 멈춰 있는 구간이 생길 수 있습니다. 이 글의 근거 기록에는 다른 기준선의 연속 일수가 없어서 비교하지 않았지만, 다음 측정에서는 함께 재야 할 값입니다.
가설이 틀린 지점 — 재현율은 계단, 비용은 비탈
가설은 두 군데에서 틀렸습니다. 첫째, 「조금 올리면 충격을 더 잡는다」가 아니었습니다. -0.60에서 -0.50으로 옮겨도 재현율은 20%에서 움직이지 않았습니다. 충격일의 점수가 기준선 바로 아래에 몰려 있지 않았다는 뜻입니다.
둘째, 「평범한 날에 울리는 횟수는 크게 늘지 않는다」도 틀렸습니다. 재현율이 처음 오르는 -0.45에서 차단 일수는 24일에서 54일로, 현재의 2.25배가 됩니다. -0.40에서는 88일로 3.67배인데 재현율은 -0.45와 같은 30%입니다. 같은 재현율을 사려고 비용만 더 내는 셈입니다.
-0.60에서 -0.50 사이가 평평하다는 사실은 그 자체로 정보입니다. 알려진 충격 10건 중 이 구간에 점수가 들어오는 사건이 하나도 없었다는 뜻이고, 충격일의 점수가 기준선 근처에 고르게 흩어져 있지 않고 몇 덩어리로 떨어져 있다는 뜻입니다. 이런 분포에서는 기준선을 미세하게 다듬는 작업이 효과를 내지 못하고, 다음 덩어리에 닿을 때까지 비용만 쌓입니다.

그리고 가장 중요한 사실이 하나 남습니다. 표의 어떤 기준선도 비상계엄을 잡지 못합니다. 가장 느슨한 -0.35도 그날 점수 -0.287보다 낮습니다. 처음 이 검토를 시작한 이유였던 바로 그 사건을, 기준선 조정으로는 거래를 124일 막아도 잡을 수 없었습니다. 기준선이 문제라는 출발점 자체가 틀렸던 셈입니다.
threshold 조정으로 해결 불가.
진짜 원인은 무엇이었나? — 점수를 만드는 재료가 비어 있었다
기준선이 아니라면 점수 자체가 낮게 나와야 할 날에 높게 나온 것입니다. 원인은 과거 점수를 다시 만드는 과정에 있었습니다. 종합 스트레스 점수는 여러 하위 점수를 가중치로 묶어 만드는데, 5년 이력을 재구축할 때 하위 점수 셋을 실제 값 대신 중립값으로 단순 처리해 두었습니다.
기준선 표에서 어떤 값도 비상계엄을 잡지 못한다는 사실이 나오면, 질문은 「기준선을 어디에 둘까」에서 「이 날 점수는 왜 -0.287밖에 안 나왔나」로 바뀝니다. 그 질문에 답하려면 점수를 이루는 재료 가운데 무엇이 실제 값이고 무엇이 채워 넣은 값인지부터 봐야 합니다.
그 셋은 코스닥 시장의 상승·하락 종목 분포(`kosdaq_breadth`), 우리가 매매하는 종목군 전체의 상승·하락 분포(`universe_breadth`), 코스닥의 실현 변동성(`kosdaq_realized_vol`)입니다. 이 값들을 종목별로 하루하루 계산하려면 시간이 들어서, 재구축 단계에서는 「보통인 날」의 값으로 채워 둔 상태였습니다.
검토 기록은 이 단순 처리 때문에 정치적 충격이 온 날 종합 점수가 희석된다고 결론지었습니다. 우리 해석으로는, 이런 충격은 지수 하나보다 시장 전체 종목이 한꺼번에 무너지는 폭과 코스닥처럼 변동성이 큰 시장의 출렁임에서 크게 드러나는데, 바로 그 자리가 비어 있었습니다. 그런데 그 자리가 중립값으로 채워져 있으니, 나머지 재료가 아무리 나쁘게 나와도 종합 점수는 중간 쪽으로 끌려 올라갑니다. 비상계엄 당일 -0.287은 그렇게 희석된 값이었습니다.
정리하면 기준선은 정상이었고, 기준선과 비교하는 점수가 측정 단계에서 무뎌져 있었습니다. 무딘 점수를 상대로 기준선만 옮기면, 위 표처럼 평범한 날까지 대량으로 걸려 들어오면서도 정작 무뎌진 날은 빠져나갑니다. 도구가 측정 대상을 제대로 못 보는 상황은 백테스트 갭 반영 누락 사례에서도 똑같이 겪었습니다. 그때도 규칙보다 측정 도구를 먼저 고쳐야 했습니다.
조치 — 기준선은 그대로, 손잡이를 가중치로 옮겼다
결정은 PANIC 기준선 -0.60 유지입니다. 기준선을 느슨하게 하는 선택지는 비용 대비 효과가 음수로 나왔기 때문입니다. 검토한 대안과 판정을 그대로 남깁니다.
- **(a) 기준선 -0.45로 완화 — 기각.** 재현율은 30%로 오르지만 차단 일수가 54일로 현재 24일의 2.25배입니다. 비상계엄은 여전히 못 잡습니다.
- **(b) 기준선 -0.40으로 완화 — 기각.** 재현율 30%로 (a)와 같은데 차단 일수는 88일, 3.67배입니다. (a)보다 나쁩니다.
- **(c) 하위 점수 가중치 탐색 — 다음 작업으로 채택.** 코스닥 지수·종목 분포·변동성의 가중치를 올리면 비상계엄 같은 날의 종합 점수가 더 낮게 내려갈 가능성이 있습니다. 기준선은 그대로 두고 가중치를 조정하는 쪽이 올바른 손잡이라고 판단했습니다.
- **(d) 하위 점수 실측 재구축 — 우선순위 낮춤.** 중립값으로 채운 코스닥 일별 분포·변동성을 종목별로 돌려 실제 값으로 다시 만드는 작업입니다. 데이터 한 해마다 약 30분이 걸려, 정확도는 오르지만 비용 대비 우선순위는 (c) 뒤로 두었습니다.
(c)를 먼저 고른 이유는 순서 때문입니다. 가중치를 바꿔도 비상계엄 점수가 거의 안 움직인다면, 그때 비로소 재료 자체를 실측으로 채우는 (d)가 필요해집니다. 반대로 가중치 조정만으로 충분히 내려간다면 (d)의 재구축 비용을 아낄 수 있습니다. 어느 쪽이든 그 결과를 본 뒤에 기준선을 다시 검토하기로 했습니다.
실매매 쪽에서는 아무것도 바꾸지 않았습니다. 지금 기준선이 거래 차단을 가장 적게 유지하면서 재현율도 -0.50과 같은 수준을 내기 때문입니다. 손대지 않는 것도 숫자로 고른 조치입니다.
같은 상황을 겪는 분들께 일반화할 수 있는 교훈도 하나 있습니다. 감지 장치가 어떤 사건을 놓쳤을 때 가장 먼저 손이 가는 곳은 기준선이지만, 기준선은 점수가 제대로 나온다는 전제 위에서만 의미가 있습니다. 그래서 기준선을 옮기기 전에 「놓친 그날의 점수가 기준선과 얼마나 떨어져 있나」를 먼저 보고, 그 거리가 크면 점수를 만드는 재료부터 확인하는 순서가 비용이 적게 듭니다.
재측정 결과 — 무엇을 얻고 무엇을 포기했나
이번 측정이 끝난 시점의 상태를 숫자로 정리하면 이렇습니다. 오탐 비용은 5년 1,240 거래일 중 24일, 1.9%로 유지합니다. 한 번 울리면 평균 1.5일 이어지는 패턴도 그대로입니다. 알려진 충격 10건 기준 재현율은 20%로, 이 값은 개선하지 못했습니다.
포기한 선택지의 값도 함께 남겼습니다. 재현율 30%를 원했다면 차단 54일(2.25배)을, 40%를 원했다면 124일, 발동 비율 10.1%를 내야 했습니다. 그리고 그 어느 쪽도 비상계엄 -0.287을 잡지 못합니다. 개선율 하나만 적으면 이 마지막 사실이 사라지기 때문에, 절대값과 미검출 사건을 함께 기록했습니다.
후속 작업도 시작했습니다. 이후 저장소에는 「종합 스트레스 가중치 탐색 + 하위 점수 실측 재구축」이라는 이름의 작업 커밋이 들어갔습니다. 다만 그 작업의 수치 결과는 이 글이 근거로 삼은 기록에 없어서 여기 적지 않습니다. 이 글의 결론은 「기준선 완화는 답이 아니다」까지이고, 가중치 조정이 비상계엄을 잡는지는 아직 이 기록 밖의 질문입니다.
이번 검토에서 얻은 것은 결국 「바꾸지 않을 근거」입니다. 다음에 비슷한 충격이 와서 장치가 또 울리지 않으면, 기준선을 다시 만지고 싶은 유혹이 생깁니다. 그때 이 표가 있으면, 기준선 완화가 이미 비용 대비 효과 음수로 판정났다는 사실과 남은 손잡이가 가중치와 재료라는 사실에서 바로 출발할 수 있습니다.
남는 한계 — 무엇을 아직 모르는가?
가장 큰 한계는 정치적 충격을 잡지 못하는 구조가 그대로 남아 있다는 점입니다. 기준선을 유지한다는 결정은 평범한 날의 거래를 지키는 대신, 비상계엄 같은 날에는 시스템이 여전히 매매를 막지 않는다는 뜻입니다. 이 위험을 알고 감수하는 결정이지 해결한 결정은 아닙니다.
표본도 작습니다. 정답표가 알려진 충격 10건이라, 재현율은 10% 단위로만 움직입니다. 20%와 30%의 차이는 사건 한 건 차이입니다. 그래서 「-0.45가 재현율을 올린다」는 판정 역시 사건 한 건에 기대고 있고, 정답표에 사건이 몇 건 더 들어오면 표의 모양이 바뀔 수 있습니다. 작은 표본에서 결론이 뒤집힌 사례도 같은 이유로 남겨 두었습니다.
기록 자체에도 확인할 점이 하나 있습니다. 결정 기록의 대안 설명은 차단 일수를 「연간」 24일·54일·88일로 적었지만, 같은 기록의 표는 이 숫자를 5년 누적으로 제시합니다. 1,240 거래일의 1.9%는 24일 언저리라, 이 글은 5년 누적 쪽으로 읽었습니다. 배수(2.25배·3.67배)는 어느 쪽으로 읽어도 같습니다.
이 결정을 다시 열 조건도 기록해 두었습니다. 가중치 탐색 뒤에 비상계엄 당일 점수를 다시 재고, 그 값이 기준선 쪽으로 충분히 내려오는지 본 다음 기준선을 재검토합니다. 그 전까지는 기준선 숫자만 바꿀 근거가 이 표에 없습니다. 결론을 고정하는 대신, 무엇이 바뀌면 결론도 바뀌는지를 함께 남긴 셈입니다.
마지막으로, 과거 점수 이력이 중립값으로 채운 재료 위에서 만들어졌다는 사실은 비상계엄 하루만이 아니라 표 전체에 영향을 줍니다. 오탐 24일이라는 숫자도 무뎌진 점수로 센 값입니다. 하위 점수를 실측으로 다시 만들면 기준선별 발동 일수 자체가 달라질 수 있고, 그때 이 표와 결론을 다시 재야 합니다. 비슷하게 감지 규칙과 측정 데이터 사이에서 판단이 막혀 있다면 상담으로 상황을 알려 주셔도 됩니다.