주문을 잘못 보내지 않는 봇을 만드는 일과, 돈을 맡길 만한 전략을 확인하는 일은 서로 다른 작업이었다. 국내 주식 봇을 만들면서 주문 실패를 감지하고 매수를 막는 규칙을 넣었지만, 그런 장치만으로 수익성을 판단할 수는 없었다. 2026년 7월 15일에는 실계좌 봇을 중단하고, 모의 운용은 계속하도록 했다.
구현에는 AI의 도움을 받았고, 실거래와 검증을 어떻게 나눌지 정하며 중단을 지시하는 일은 내가 맡았다. 이 글은 당시의 구조와 판단을 다룬다. 짧은 백테스트나 내부 점검을 검증된 초과수익으로 제시하지 않는다.
실제 주문과 실험을 같은 자리에 두지 않았다
실계좌로 주문하는 경로, 실제 돈을 주문에 쓰지 않는 페이퍼 운용, 새 전략을 시험하는 Lab을 나눴다. 과거 자료로 전략을 시험하는 백테스트에서 괜찮아 보이는 결과가 나와도, 바로 실계좌 설정을 바꾸는 근거로 삼지 않기 위한 구조였다.
전환 기준도 두 문제로 나눠 다뤘다. 하나는 주문·잔고 확인 같은 운영 경로를 제한적으로 시험할 준비가 됐는지이고, 다른 하나는 전략이 충분한 관찰과 비교를 거쳤는지였다. 작은 운영 시험이 끝났다고 두 번째 질문까지 풀리는 것은 아니었다.
주문이 실패한 뒤의 행동을 정했다
주문 단계에는 당일 실패 기록과 수동 중단 신호를 확인하는 가드를 붙였다. 가드는 조건에 걸리면 새 매수를 막는 장치다. 같은 거부 사유로 주문을 계속 시도하지 않도록, 계속 유효한 거부 이력과 당일의 일시적 실패를 나누어 저장하는 코드도 두었다. 매도와 청산은 이 매수 차단 규칙에 함께 묶지 않았다.
브로커가 알려 주는 보유 종목과 봇 내부 장부에 있는 종목도 대조했다. 한쪽에만 있는 종목을 찾으면, 실제로 보유하고 있는데 추적에서 빠졌거나 장부에만 남은 경우를 확인할 수 있다. 다만 이 대조는 모든 보유 수량이 같은지까지 검사하는 기능은 아니었다. 조회가 실패하거나 비어 있을 때 대조를 건너뛰는 경로도 있어, 이 코드가 모든 오류에서 주문을 안전하게 막는다고 설명할 수는 없다.
이처럼 가드가 구현돼 있다는 사실과, 실제 장애 상황에서 충분히 검증됐다는 판단을 나눠 두었다. 운영상의 실수를 줄이려는 코드가 전략의 수익성까지 입증해 주지는 않았다.
숫자를 표시하는 기능에도 빈칸이 있었다
별도의 게이지는 평가액 기록이 쌓인 기간과 최대 낙폭을 요약하고, 청산한 거래에서 얻는 수익계수와 같은 기간의 시장 기준을 함께 보도록 만들었다. 최대 낙폭은 평가액이 앞선 최고점에서 얼마나 내려갔는지를 뜻하고, 수익계수는 이익 거래의 이익 합계를 손실 거래의 손실 합계와 비교하는 값이다. 둘 다 관찰한 기간과 거래 내역에 묶인 지표다.
비교 대상의 가격을 가져오지 못하면 초과수익을 0으로 채우지 않고 알 수 없는 값으로 남겼다. 청산 자료가 부족한 수익계수도 측정할 수 없다고 표시했다. 게이지에 몇 가지 기준이 나타난다는 이유로, 뒤에 정한 모든 검증 조건까지 코드가 자동으로 강제한다고 보지는 않았다.
7월 15일에 멈춘 범위
당시에는 실계좌 봇을 멈추라고 지시하면서 페이퍼 운용은 남겨 두었다. 이어진 상태 확인에서는 실계좌 서비스가 실행 중이 아니며 자동 시작도 꺼진 것으로 나타났다. 이 날짜의 중단은 실거래 경로에 관한 것이고, 모든 실험을 없애거나 현재 서버 전체가 꺼져 있다는 뜻은 아니다.
주문 방어 코드와 검증 구조는 남겼지만, 운용을 이어 갈 판단을 그 코드의 존재에 맡기지는 않았다. 실제 돈이 걸리는 경로를 멈추고 모의 관찰을 분리해 둔 것이 이 단계에서 내린 결정이었다.
