누적 손실을 막으려던 안전장치가 하루 안의 일시적 하락에도 반응했습니다 — 두 지표를 같은 시간 단위로 재고 있는지가 핵심이었습니다
자동매매 시스템에는 손실이 누적될 때 신규 매수를 막는 안전장치가 있습니다. 최근 이 장치가 정상적인 매수 2건을 잘못 막는 일이 있었습니다.
원인을 따라가 보니 코드에 버그가 있었던 게 아니라, 판정에 쓰는 두 숫자가 서로 다른 시간 단위로 재고 있었습니다. 그 경위를 정리해봤습니다.
무슨 일이 있었나
어느 날 오전, 실계좌 주문 실행/안전장치 계층(새 창) 중 하나가 정상적인 매수 신호 2건을 차단했습니다.
당일 지수는 사실상 보합에 가까웠습니다. 그런데 이 계좌의 장중 평가금액만 유독 크게 빠져 있었고, 그 순간값을 근거로 "누적 손실이 위험 수위"라는 판정이 내려졌습니다.
더 이상한 건 당일 급락을 감시하는 다른 안전장치(서킷브레이커 층)는 전혀 반응하지 않고 있었다는 점입니다. 급락 감시 장치는 조용한데, 누적 손실 감시 장치만 발화한 상황이었습니다.
일단 그 자리에서는 사람이 직접 판단해 차단된 매수를 수동으로 집행했습니다. 시스템 자체는 오작동이 아니라 설계된 대로 판정했다는 걸 먼저 확인한 뒤였습니다. 문제는 그 판정 로직 안에 있었습니다.
안전장치가 왜 그렇게 설계돼 있었나
이 장치는 계좌가 고점 대비 얼마나 밀렸는지, 즉 누적 낙폭(peak-to-trough)을 감시합니다.
전략이 며칠에 걸쳐 서서히 열화되는 경우를 잡기 위한 장치입니다. 하루 급락은 다른 층(서킷브레이커)이 이미 담당하고 있으니, 이 장치는 "여러 날에 걸친 완만한 침식"을 보는 게 원래 역할이었습니다.
그런데 판정에 쓰는 두 숫자 중 하나는 마감 기준 시계열에서 뽑은 고점이었고, 다른 하나는 판정을 호출하는 시점의 장중 평가금액이었습니다.
설계 당시엔 "가장 최신 정보를 쓰는 게 더 안전하다"는 생각으로 장중값을 그대로 넘겼을 겁니다. 실시간성을 포기하지 않으려는 선택이었던 셈입니다.
진짜 원인 — 기준선과 현재값의 시간 단위가 달랐다
고점은 하루 단위(마감가)로 갱신되는데, 그 고점과 비교하는 현재값은 분 단위(장중 스냅샷)였습니다.
누적 지표인데 비교 대상 하나가 순간값이면, 하루 안의 정상적인 변동성만으로도 "누적 손실이 위험 수위"라는 판정이 나올 수 있습니다. 실제로 그 사고 당일이 정확히 그런 경우였습니다 — 지수는 거의 안 움직였는데 장중 한 시점의 평가금액만 일시적으로 빠져 있었고, 그 시점에 하필 판정이 걸렸습니다.
과거 구간을 마감 대 마감 기준으로 다시 계산해보니, 같은 기간 동안 이 임계값을 넘긴 적이 실제로는 없었습니다. 즉 이 장치가 실제로 "위험한 누적 손실"을 잡은 게 아니라, 시간 단위가 안 맞는 비교 때문에 존재하지 않던 손실을 본 것이었습니다.
어떻게 고쳤나
가장 먼저 한 일은 판정 기준을 마감 대 마감으로 바꾼 것입니다. 고점도 마감 시계열, 현재값도 마감 시계열 — 두 숫자를 같은 시간 단위로 맞췄습니다.
그런데 이렇게 하면 다른 문제가 생깁니다. 만약 정말로 위험한 급락이 장중에 벌어지면, 이 장치는 그날 마감까지 아무 반응을 하지 않게 됩니다. 완만한 침식을 잡으려다가 급격한 위험까지 하루 늦게 잡는 쪽으로 옮겨간 셈입니다.
그래서 임계값을 둘로 나눠 다르게 다루기로 했습니다. 상대적으로 자주 걸리고 놓쳐도 다음 마감에 다시 잡히는 완만한 쪽은 마감 대 마감 기준을 유지하고, 드물지만 놓치면 하루 더 손실이 방치되는 급격한 쪽만 장중 기준으로 되돌렸습니다. 두 임계값이 감시하는 위험의 성격 자체가 달랐던 겁니다.
이 과정에서 부수적으로 하나 더 발견했습니다. 하루 뒤 아침에 자동으로 도는 리셋 로직이, 급격한 위험 판정보다 먼저 돌면서 판정 대상이 되어야 할 낙폭을 조용히 지워버리는 경로가 있었습니다. 판정 순서를 뒤집어 리셋보다 위험 판정이 먼저 돌도록 고쳤습니다. 안전장치를 고치다가 그 안전장치를 무력화하는 또 다른 경로를 발견한 경우입니다.
일반화된 교훈
이번 사고에서 가장 크게 배운 건 "안전장치의 판정 기준이 무엇을 감시하려는 지표인지"와 "실제로 비교에 쓰는 값이 어떤 시간 단위인지"를 항상 함께 확인해야 한다는 점입니다.
누적/추세 지표는 원래 여러 시점에 걸친 완만한 변화를 감시하려고 만든 것입니다. 거기에 순간값 하나를 섞으면, 그 순간의 정상적인 변동성이 누적 지표의 판정을 흔들어버립니다. 지표의 이름이 "누적"이어도 구현이 실제로 그 이름값을 하고 있는지는 별개의 질문이었습니다.
반대 방향의 함정도 있습니다. 시간 단위를 무조건 느슨하게(예: 전부 마감 기준으로) 통일하면 이번엔 진짜 급격한 위험까지 놓칠 수 있습니다. 이번 사고에서도 안전장치를 고치다가 "급격한 위험은 여전히 즉각 반응해야 한다"는 요구를 뒤늦게 떠올렸습니다.
결국 정답은 위험의 성격별로 판정 시간창을 다르게 가져가는 것이었습니다. 자주 오탐하지만 놓쳐도 회복 가능한 쪽은 느슨한 시간창으로, 드물지만 놓치면 치명적인 쪽은 촘촘한 시간창으로. 하나의 안전장치 안에 서로 다른 위험을 하나의 시간 단위로 뭉뚱그려 넣지 않는 것 — 이게 이번 사고가 남긴 가장 일반적인 교훈이었습니다.
안전장치를 하나 손볼 때마다, 그 옆에 있는 다른 안전장치와의 경계가 어디인지, 그리고 위험이 어느 쪽으로 옮겨가는지를 같이 적어두려고 합니다. 커버리지가 사라지는 게 아니라 관할이 옮겨가는 것일 뿐이라면, 그걸 기록해두지 않으면 다음에는 그게 버그로 보일 겁니다.
Top comments (0)