Quant Trading Bot Devlog

Read in English

[260706~260712] 겉보기 지표를 의심하는 데서 시작해, 재현되는 속도로 끝난 한 주

월요일 "제일 깨끗하다"던 모델이 사실 아무 근거 없이 돌고 있었다는 게 화요일에 드러난 뒤로, "겉보기 지표도 빨라진 속도도 그대로 믿지 말자"가 이번 주를 관통했습니다

이번 주는 월요일부터 일요일까지 하나의 질문이 계속 따라다녔습니다 — "지금 내가 보고 있는 게 진짜인가?" 겉보기엔 멀쩡한 지표, 그럴듯한 도구의 답, 빨라진 속도가 매일 한 번씩 뒤집혔고, 그 의심이 결국 이번 주의 방향을 정했습니다.

전환점: "제일 깨끗한 모델"이 사실은 아무 근거 없이 돌고 있었다

주 초에는 최적화하는 기분으로 시작했습니다. 로컬 LLM 후보 몇 개를 같은 조건으로 돌려 비교했고, 실패율·등급 분포 같은 지표가 제일 깨끗한 모델을 골라뒀습니다. 표면 지표만 봐선 안 잡히는 실패(최종 판단 생성 자체가 실패해 기본값으로 떨어지는 것, 낮은 확률로 아예 다른 대상을 분석하는 것)를 이때도 두 개나 걸러냈으니, 나름 꼼꼼히 봤다고 생각했습니다.

그런데 다음 날, 그 "제일 깨끗하다"는 결론 자체가 맹점 위에 서 있었다는 게 드러났습니다. 리서치 파이프라인의 한 단계가 실제 데이터를 조회해야 하는데 도구 호출 자체를 못 하고, "조회하겠다"는 의도만 텍스트로 남긴 채 아무 근거 없이 리포트를 쓰고 있었습니다. 지표(실패율·등급 분포)는 깨끗했지만, 정작 리포트 안에 실제 데이터가 들어 있는지는 아무도 확인하지 않았던 겁니다. 모델을 바꿔 도구 호출을 고친 뒤에도 절반 이상이 여전히 이상해서 더 파보니, 그 밑에 조용히 기본값으로 방치된 컨텍스트 윈도우가 있어 입력의 상당 부분이 잘려나가고 있었습니다.

이 발견이 이번 주의 방향을 바꿨습니다. "어떤 모델이 제일 좋은가"라는 최적화 문제가, "내 측정 자체를 믿을 수 있는가"라는 문제로 바뀐 겁니다.

그 의심은 매일 한 번씩 반복됐다

한번 이렇게 데고 나니, 이후 며칠은 "그냥 믿었다가 데이는" 패턴이 계속 반복됐습니다.

공통된 교훈은 하나였습니다. 모델이든, 요약 도구든, 검증하라고 세운 또 다른 모델이든, 검증됐다는 외부 라이브러리든 — "이건 맞을 것"이라고 넘어가는 순간이 사고의 입구라는 것. 설정을 바꾼 뒤엔 반드시 속도를 실측하고, API는 원본 스펙을 직접 까고, 사실관계는 직접 찾아보는 쪽으로 습관을 바꿨습니다.

의심만 하지 않고, 믿을 수 있는 토대를 다시 세웠다

의심이 늘었다고 손을 놓은 건 아니고, 오히려 "그럼 무엇을 믿을 수 있게 만들까"에 시간을 많이 썼습니다.

새 자동투자 아이디어는 실제 돈을 걸기 전에 모의(페이퍼) 트랙부터 세웠습니다. 후보 선정은 똑같이 하되 배분 방식만 다른 두 트랙을 나란히 돌려 비교하고, "충분히 긴 기간 동안 벤치마크를 유의미하게 이겨야 한다"는 판정 기준을 먼저 정해두고 1일차부터 돌리는 방식입니다. 만들다 보니 지금 배분이 참고하는 입력값 하나가 그동안 기록조차 안 되고 있어서 되짚어 검증할 방법이 없다는 것도 알게 됐습니다 — 오늘부터라도 기록을 시작해뒀습니다.

인프라 쪽에서는 몇 주째 미궁이던 새벽 크래시의 진짜 범인을 드디어 잡았습니다. 파이썬 코드상으로는 반납한 메모리가 운영체제 입장에선 회수되지 않고(메모리 파편화) 매일 조금씩 쌓여 새벽에 시스템을 죽이던 것이었습니다. 이미 계산해둔 결과는 캐시만 읽기·무거운 계산 뒤 명시적 메모리 반납·날짜가 안 바뀌면 계산 건너뛰기, 이 세 가지로 잡았고 한 프로세스는 메모리 사용량이 크게 줄었습니다. "껐다 켜면 낫는다"로 덮어두던 걸 근본까지 판 셈입니다. 핵심 백그라운드 프로세스들이 개발 환경(에디터)의 자식으로 떠 있어 에디터가 죽으면 같이 죽던 구조도 발견해, 넷 다 독립적인 OS 서비스로 승격시켰습니다.

"빠른 것"에서 "흔들리지 않는 것"으로

이번 주 자원(GPU)과 속도를 둘러싼 이야기가 가장 극적으로 뒤집혔습니다.

처음엔 소프트웨어로 풀려 했습니다. 서빙 엔진을 하나 더 붙였더니 같은 GPU에서도 눈에 띄게 빨라져서, 고민하던 그래픽카드 추가를 한 번 보류했습니다. 그런데 이번 주에 잡은 속도 저하·메모리 문제 상당수가 결국 GPU 메모리 여유 부족에서 왔고, 비교 실험에서 "하드웨어 차이 때문에 결과가 달라졌다"는 잡음까지 없애고 싶어서, 결국 지금 쓰는 것과 같은 카드를 하나 더 두는 쪽으로 방향을 굳혔습니다.

주말엔 실제로 카드를 갈아 끼워 단독 안정성부터 확인했고(온도·소음·오류 모두 양호), 두 장을 같이 꽂으려니 케이스 안에서 전원 공급 장치 자리와 몇 센티미터 차이로 부딪힌다는 걸 미리 발견해 케이스 교체 뒤로 미뤘습니다.

그 사이 예전에 "효과 없다"고 접었던 병렬 처리(한 서버가 여러 요청을 동시에)를 다시 꺼내 재봤더니, 이번엔 조건이 달라서인지 속도가 꽤 빨라졌습니다. 토요일엔 "예전 결론도 전제가 바뀌면 유효기간이 끝난다"며 기뻐했는데 — 일요일에 더 파보니 이야기가 뒤집혔습니다. 속도는 진짜 빨라졌지만, 같은 입력·같은 설정으로 반복 실행하면 결과가 매번 조금씩 달라졌습니다. 동시 처리를 아예 빼고 요청 하나만 반복해도 달라졌으니, 범인은 병렬 처리가 아니라 GPU 연산이 매번 완전히 똑같이 재현되지는 않는다는, 원래 있던 성질이었습니다. 동시 처리는 그 흔들림을 아주 조금 더 키웠을 뿐이고요.

그래서 이 병렬 방식은 실제 판단에 쓰는 파이프라인엔 당분간 안 쓰기로 했습니다. 결과가 흔들리면 "어제와 오늘 판단이 다른 게 진짜 시장이 바뀐 건지, 그냥 계산이 흔들린 건지" 구분할 수 없기 때문입니다. 대신 새로 생긴 두 번째 카드로 완전히 독립된 두 계산을 나란히 돌려, 흔들림 없이 속도만 얻는 쪽으로 다시 틀었습니다. 같은 맥락에서, 야간 분석에 시장 전체 분위기를 넣을 때도 매번 달라지는 요약문 대신 항상 똑같이 재현되는 숫자만 규칙 기반으로 넣도록 설계했습니다.

주 초의 "겉보기 지표를 못 믿겠다"가, 주말엔 "빠르지만 흔들리는 것보다 느려도 재현되는 것을 택하자"로 자연스럽게 이어진 셈입니다.

접을 것은 접었다

안 되는 걸 붙들지 않고 정리한 것도 이번 주의 한 축이었습니다. 오래 "실전 미검증" 상태로 남겨뒀던 실험적 모델 하나는, 여러 번 튜닝해도 벤치마크를 이긴 적이 없고 설계 관점에서 봐도 이 역할엔 애초에 맞지 않는다는 결론이 나서 미련 없이 접었습니다. 반대로 핵심 예측 모델 몇 개는 학습한 지 오래돼 최근 시장을 잘 못 따라가고 있어, 앞으로 주기적으로 자동 재학습하는 체계를 붙이기로 했습니다.

맺으며

돌아보면 이번 주는 "새로운 걸 많이 만든 주"라기보다 "이미 있다고 믿었던 걸 하나씩 다시 의심한 주"에 가깝습니다. 제일 깨끗해 보이던 모델, 그럴듯하던 도구의 답, 어제 좋아졌다던 속도까지 — 파고들 때마다 매번 다른 게 나왔습니다. 덕분에 남은 결론은 단순합니다. 겉보기 지표와 속도를 그대로 믿지 말고, 느려도 재현되는 토대 위에서만 판단하자.