AI 에이전트로 시장을 분석한다는 것 / 2
market-analyst — 시스템은 더 조용하게 틀린다
인지 한계를 벗어나려고 시스템에 맡겼다. 그런데 시스템의 실수는 사람의 실수보다 조용했다. 그래서 정확성을 위해 가용성을 버렸다
목차
1편에서 이 시스템을 만든 이유를 한 문장으로 적었다. 직접 분석은 인지 범위에 막힌다고. 사람은 미국 전 종목을 매일 같은 기준으로 볼 수 없고, 그래서 놓친다. 그 한계를 벗어나려고 시스템에 맡겼다.
그런데 시스템이 나를 배신했다. 사람보다 조용하게.
이 글은 그 배신에 대한 기록이다. 그리고 결국 시스템을 일부러 더 자주 멈추게 만들기로 한 결정에 대한 글이다.
사람의 실수는 시끄럽다
직접 분석하던 시절의 실수는 눈에 보였다. 종목을 놓치면 나중에라도 "놓쳤다"는 걸 안다. 차트를 잘못 읽으면 결과가 틀린 걸 내가 안다. 판단이 틀렸을 때 틀렸다는 감각이 남는다. 사람의 실수에는 얼굴이 있다.
시스템의 실수에는 얼굴이 없다. 숫자는 여전히 숫자고, 표는 여전히 빈칸 없이 채워져 있고, 리포트는 정해진 시간에 정확히 도착한다. 시스템은 틀린 채로 완벽하게 작동한다.
이걸 머리로 아는 것과 데여서 아는 것은 다르다. 나는 세 번 데였다.
첫 번째: 빈칸 하나 없이 채워진 틀린 표
초기에 몇몇 종목의 Phase가 이상했다. 분명 우상향하는 종목이 Phase 2로 안 잡히거나, 멀쩡한 종목이 갑자기 Phase 4로 떨어져 있었다.
원인은 종목이 아니라 가격이었다. MA150을 조정되지 않은 원본 종가로 계산하고 있었고, 배당락일마다 가격이 계단처럼 꺼지는 게 그대로 폭락으로 읽혔다. 배당을 많이 주는 종목일수록 Phase가 더 심하게 뒤집혔다. 조정 종가로 통일해서 고쳤다. 여기까지는 교과서다.
교과서에 없는 건 그 표의 모습이었다. 표는 완벽했다. 미국 전 종목에 Phase가 빠짐없이 찍혀 있었다. 에러는 0건이었다. 그런데 배당주들은 전부 틀려 있었다. 내가 직접 봤다면 "이 종목이 Phase 4일 리가 없는데"라고 한 번은 멈췄을 것이다. 시스템은 그 의심을 하지 않는다. 의심은 시스템의 기능이 아니다.
그리고 몇 달 뒤, 다른 자리에서 같은 계열의 가격 오염이 또 나왔다. 상장폐지 종목과 살아 있는 종목을 잇는 이음매에서 스케일이 어긋나 있었고, 제공처에서 넘어온 값 자체가 일부 오염돼 있었다. 6월에 고쳤다고 믿은 것이 8월에 다시 올라왔다. "고쳤다"는 믿음이 두 번째 배신이었다.
두 번째: 아무 일도 일어나지 않은 며칠
이건 더 무서웠다. 아무 일도 없는 것처럼 보였기 때문이다.
원천 가격 테이블에 결손과 NaN이 섞여 들어오고 있었는데, 파이프라인은 그걸 조용히 통과시켰다. 에러도 경고도 없었다. NaN은 NaN인 채로 RS 계산에 들어갔고, 결손된 종목은 브레드스 모집단에서 슬그머니 빠졌다. RS 퍼센타일이 며칠 동안 미묘하게 틀어져 있었다.
그 며칠 동안 시스템은 정해진 시간에 후보 리스트를 냈고, 나는 그걸 읽었다. 오염된 RS 위에 서 있는 종목이 리스트에 올라와 있었고, 나는 그걸 정상으로 읽었다. 리스트가 틀렸다는 걸 알게 된 건 종목을 봐서가 아니라, 나중에 데이터를 파봐서였다.
여기서 처음으로 이 시스템의 구조적인 문제가 보였다. 나는 인지 한계를 벗어나려고 시스템을 만들었다. 그런데 시스템의 출력을 검증하는 인지는 여전히 나였고, 나는 여전히 한계가 있었다. 시스템은 내 한계를 없앤 게 아니라 옮겼을 뿐이다 — 종목을 보는 자리에서, 시스템을 의심하는 자리로.
그리고 두 번째 자리가 더 어렵다. 종목이 이상하면 티가 난다. 숫자가 이상한 건 티가 안 난다. 사람은 이상한 차트 앞에서는 멈추지만, 이상한 퍼센타일 앞에서는 멈추지 않는다. 그럴듯한 숫자는 의심을 통과한다.
세 번째: 휴장일이 아니었다
세 번째는 작은 사건이었는데, 이 글의 결론을 만들었다.
제공처에서 데이터가 늦게 들어오는 날이 있었다. 파이프라인은 그걸 "데이터가 없다, 즉 휴장일"로 해석했다. 실제로는 그냥 지연이었다. 그날 하루의 브레드스가 통째로 비었고, 지연이 풀린 뒤에도 그 하루를 다시 채우는 로직이 없었다. 시스템은 "오늘은 시장이 쉬었다"고 조용히 결론내고 다음 날로 넘어갔다.
비슷한 시기에 외부 호출에 타임아웃이 없어서, 제공처가 한 번 응답을 멈추면 파이프라인 전체가 멈춘 채로 아침을 맞은 적도 있다. 그날 아침엔 리포트가 없었다.
그런데 이 두 사건을 나란히 놓고 보니 이상한 게 있었다. 리포트가 안 온 날이 오히려 나았다. 리포트가 없으면 뭔가 잘못됐다는 걸 안다. 부재는 신호다. 반면 "휴장일" 오인은 부재조차 아니었다. 그럴듯한 설명이 붙은 부재였다. 시스템이 틀린 게 아니라, 시스템이 틀린 이유를 스스로 지어낸 것이다.
가장 위험한 실패는 실패하지 않은 것처럼 보이는 실패다.
그래서 시스템을 일부러 멈추게 만들었다
여기서 한 가지 결정을 했다. 대부분의 엔지니어링 상식과 반대되는 결정이다.
보통은 이렇게 한다. 종목 하나에 결손이 있다고 전체 파이프라인을 세우는 건 과잉이다. 그 종목만 빼고 나머지를 계산하고, 경고 하나 남기고, 다음 날 채우면 된다. 시스템은 가능한 한 계속 돌아가야 한다. 이게 정상적인 감각이고, 대부분의 시스템에서 맞는 감각이다.
이 시스템에서는 틀린 감각이었다.
이 시스템의 산출물은 데이터가 아니라 확신이다. 매일 아침 "이 종목들이 Phase 2 초입에 있다"는 문장이 온다. 부분적으로 오염된 데이터로 만든 확신에 찬 문장은, 문장이 없는 것보다 나쁘다. 없으면 나는 안 믿는다. 있으면 믿는다. 문제는 시스템이 틀리는 게 아니라, 틀린 채로 나를 믿게 만드는 것이다.
그래서 규칙을 뒤집었다. 결손도, NaN도, 0건도 통과 사유가 아니라 정지 사유로. 값이 있으면 통과가 아니라, 유한한 양수만 통과. 커버리지가 어제와 다르면 위층 계산을 아예 시작하지 않는다.
파이프라인이 자주 멈추기 시작했다. 아침에 리포트가 없는 날이 늘었다. 성가셨다. 정상적인 감각으로 보면 시스템이 나빠진 것이다. 가용성을 버렸으니까.
그 대가로 얻은 건 하나다. 리포트가 오면 믿을 수 있다는 것. 리포트가 안 오면 왜 안 왔는지 안다는 것. 시스템의 실수에 얼굴을 돌려준 것이다.
나는 시스템이 틀리는 걸 막지 못했다. 시스템이 조용히 틀리는 것만 막았다. 그걸로 충분했다.
자동화는 한계를 없애지 않는다, 옮긴다
1편의 문장으로 돌아간다. 직접 분석은 인지 범위에 막힌다. 맞다. 그래서 시스템에 맡겼다.
그런데 시스템은 내 한계를 없앤 게 아니라 옮겼다. 종목을 보는 자리에서 시스템을 의심하는 자리로. 그 두 번째 자리를 감당하지 못하면 자동화는 인지의 확장이 아니라 인지의 위임이고, 위임한 만큼 눈을 감는 것이다. 사람은 놓친 종목을 나중에라도 알지만, 시스템이 조용히 틀린 건 파보기 전까지 영원히 모른다.
그래서 이 층에서 배운 건 데이터를 다루는 기술이 아니었다. 시스템이 침묵할 수 없게 만드는 것, 그것 하나였다.
재료를 믿게 됐으니 — 정확히는, 못 믿을 때 시스템이 스스로 말하게 됐으니 — 다음 편에서는 그 재료로 Phase·RS·SEPA·브레드스를 계산하는 층으로 올라간다. 거기서 "같은 기준으로 매일 본다"는 말이 얼마나 미끄러운지 이야기하게 될 것이다.
사람의 실수는 시끄럽고, 시스템의 실수는 조용하다. 나는 시스템을 시끄럽게 만드는 데 몇 달을 썼다.