트레이딩 봇은 전략 코드가 아니라 시스템이다
자동매매를 처음 볼 때 사람의 시선은 대개 전략으로 먼저 향한다. 어떤 지표를 쓰는지, 언제 진입하고 언제 청산하는지, 백테스트 수익률이 얼마나 좋아 보이는지가 먼저 눈에 들어온다. 그래서 많은 사람이 트레이딩 봇을 “매수·매도 규칙을 코드로 옮긴 것” 정도로 이해한다. 물론 전략은 중요하다. 시장에서 무엇을 할지 결정하는 규칙이 없다면 봇은 아무것도 판단할 수 없다. 하지만 실전으로 조금만 가까이 […]
자동매매를 처음 볼 때 사람의 시선은 대개 전략으로 먼저 향한다. 어떤 지표를 쓰는지, 언제 진입하고 언제 청산하는지, 백테스트 수익률이 얼마나 좋아 보이는지가 먼저 눈에 들어온다. 그래서 많은 사람이 트레이딩 봇을 “매수·매도 규칙을 코드로 옮긴 것” 정도로 이해한다.
물론 전략은 중요하다. 시장에서 무엇을 할지 결정하는 규칙이 없다면 봇은 아무것도 판단할 수 없다. 하지만 실전으로 조금만 가까이 가면 질문은 금방 달라진다. 이 가격은 어디에서 왔는가? 이 봉은 확정된 봉인가? 이 신호는 이미 처리된 신호인가? 지금 봇은 포지션을 보유 중이라고 믿고 있는가? 그리고 그 판단은 나중에 다시 확인할 수 있게 기록되고 있는가?
이 질문들이 등장하는 순간, 봇은 더 이상 전략 코드 하나로 설명되지 않는다. 트레이딩 봇은 시장 데이터를 읽고, 판단 가능한 상태로 바꾸고, 그 상태 위에서 결정을 만들고, 그 결정을 실행 가능한 요청으로 정리하고, 나중에 검증할 수 있게 남기는 하나의 시스템이다.
좋은 봇은 좋은 신호 하나로 완성되지 않는다. 좋은 봇은 데이터를 읽고, 상태를 만들고, 판단을 분리하고, 기록을 남기는 구조 위에서 만들어진다.
전략과 봇은 같은 말이 아니다
먼저 전략과 봇을 분리해서 보는 편이 좋다. 전략은 “무엇을 할지”를 정하는 규칙이다. 예를 들어 이동평균이 특정 방향으로 기울면 진입한다거나, 변동성이 일정 수준을 넘으면 거래를 피한다거나, RSI가 낮아지면 매수 후보로 본다는 식의 판단 규칙이 전략에 가깝다.
반면 봇은 그 판단이 반복 가능하게 만들어진 시스템이다. 봇은 단순히 “RSI가 낮으면 매수”라고 말하는 데서 멈추지 않는다. 어떤 가격 데이터를 기준으로 RSI를 계산할지, 그 데이터가 확정된 값인지, 이미 포지션을 가지고 있는지, 같은 신호를 중복으로 처리하지 않았는지, 판단이 실패했을 때 어디까지 기록할지까지 다뤄야 한다.
이 차이를 놓치면 봇은 쉽게 하나의 긴 함수가 된다. 데이터도 그 안에서 가져오고, 지표도 그 안에서 계산하고, 진입 판단도 그 안에서 하고, 주문도 바로 넣고, 로그는 마지막에 몇 줄 찍는 구조가 된다. 처음에는 빠르게 작동하는 것처럼 보일 수 있다. 하지만 시간이 지나면 문제가 생겼을 때 어디서 틀어졌는지 찾기 어렵고, 작은 변경 하나가 예상치 못한 곳까지 영향을 준다.
그래서 Build 관점에서 첫 번째로 봐야 할 것은 전략의 화려함이 아니라 경계다. 시장을 읽는 부분, 데이터를 정리하는 부분, 상태를 만드는 부분, 판단하는 부분, 실행 요청을 만드는 부분, 기록하는 부분이 어느 정도 분리되어 있어야 한다. 이 경계가 생길 때 봇은 단순한 코드 조각이 아니라 시스템의 형태를 갖기 시작한다.
봇은 시장 데이터를 판단 가능한 상태로 바꾸는 흐름이다
트레이딩 봇은 시장을 직접 보지 않는다. 봇은 거래소 API, 가격 데이터, 캔들, 체결, 호가, 거래량 같은 입력을 통해 시장을 읽는다. 이 말은 생각보다 중요하다. 봇이 읽는 것은 “시장 그 자체”가 아니라, 특정한 규칙과 지연과 형식을 가진 데이터다.
예를 들어 같은 가격이라도 1분봉의 종가인지, 15분봉의 고가인지, 아직 움직이고 있는 실시간 가격인지에 따라 의미가 완전히 달라진다. 아직 확정되지 않은 봉을 확정된 봉처럼 사용하면, 백테스트에서는 그럴듯했던 판단이 라이브에서는 흔들릴 수 있다. 거래소 응답이 늦거나 데이터가 일부 비어 있다면, 봇은 실제 시장과 조금 다른 장면을 보고 있을 수도 있다.
그래서 좋은 봇은 입력 데이터를 그대로 전략에 던지지 않는다. 먼저 데이터를 봇이 이해할 수 있는 형태로 정리한다. 어떤 시간 단위의 데이터인지, 마지막으로 확인한 시점은 언제인지, 계산에 쓸 수 있을 만큼 충분한 길이가 있는지, 아직 확정되지 않은 값은 아닌지 확인한다. 이 과정은 눈에 잘 띄지 않지만, 시스템의 신뢰도를 좌우한다.
그다음 봇은 데이터를 해석 가능한 맥락으로 바꾼다. 이동평균, 변동성, 추세, 레짐, 과열과 침체 같은 값들이 여기에 해당한다. 많은 사람이 지표를 곧바로 신호라고 생각하지만, Build 관점에서는 조금 다르게 보는 편이 좋다. 지표는 신호 그 자체라기보다 시장 상태를 압축해서 보여주는 언어에 가깝다.
전략 판단은 이 정리된 상태 위에서 만들어진다. 좋은 구조에서는 전략 엔진이 시장의 모든 세부사항을 직접 다루지 않는다. 전략은 정리된 데이터와 맥락을 받아 “지금 행동할 조건인가?”를 판단한다. 이때 전략은 독립적으로 읽히고 테스트될 수 있어야 한다. 그래야 나중에 데이터 입력이 바뀌었는지, 판단 규칙이 바뀌었는지, 실행 단계에서 문제가 생겼는지 분리해서 볼 수 있다.
Build 관점에서 봇을 나눠보면
Build 시리즈에서 말하는 구조는 거창한 플랫폼 설계를 뜻하지 않는다. 작은 개인 봇이라도 입력, 상태, 판단, 요청, 기록의 흐름이 분리되어 있으면 이미 시스템적으로 사고하고 있는 것이다. 단순화하면 트레이딩 봇은 다음과 같은 흐름으로 볼 수 있다.
Market Input
→ Data Model
→ Feature / Context
→ Strategy Decision
→ State
→ Action Request
→ Record
Market Input은 시장 데이터가 들어오는 입구다. 가격, 캔들, 거래량, 호가, 체결, 경우에 따라 환율이나 금리 같은 외부 데이터도 여기에 들어올 수 있다. 중요한 것은 봇이 시장을 직접 보는 것이 아니라, 데이터 인터페이스를 통해 시장을 읽는다는 점이다.
Data Model은 들어온 데이터를 봇이 이해할 수 있는 형태로 정리하는 층이다. 같은 가격 데이터라도 시간 단위, 확정 여부, 누락 여부, 계산 가능한 길이에 따라 의미가 달라진다. 이 층이 약하면 전략은 처음부터 불안정한 재료 위에서 판단하게 된다.
Feature / Context는 시장 상태를 압축해서 보여주는 층이다. 이동평균, 변동성, 추세, 레짐, 과열 여부, 필터 조건 같은 값들이 여기에 들어간다. 이 값들은 “바로 매수하라”는 명령이라기보다, 전략이 판단할 수 있도록 시장을 번역한 결과에 가깝다.
Strategy Decision은 실제 판단이 만들어지는 층이다. 여기서는 진입할지, 대기할지, 청산 후보로 볼지, 위험 구간으로 볼지 같은 결정을 내린다. 좋은 구조라면 이 판단은 데이터 수집이나 주문 처리와 과하게 섞이지 않아야 한다. 그래야 전략 자체가 무엇을 보고 어떤 결정을 했는지 설명할 수 있다.
State는 지금 봇이 무엇을 믿고 있는지에 관한 정보다. 마지막으로 처리한 봉은 무엇인지, 현재 포지션을 보유 중이라고 보는지, 같은 신호를 이미 처리했는지, 지금 시장을 어떤 레짐으로 해석하는지 같은 값들이 여기에 들어간다. 봇을 어렵게 만드는 것은 계산식보다 상태인 경우가 많다.
Action Request는 판단 결과를 실행 가능한 요청으로 바꾸는 층이다. 여기서 곧바로 주문 세부사항까지 깊게 들어갈 필요는 없다. Build 관점에서 중요한 것은 전략 판단과 실행 요청이 분리되어 있다는 점이다. “진입 조건이 맞다”와 “어떤 주문을 어떤 수량으로 어떤 방식으로 보낼 것인가”는 연결되어 있지만 같은 일은 아니다.
Record는 판단과 상태를 나중에 다시 확인할 수 있게 남기는 층이다. 기록되지 않은 판단은 검증하기 어렵다. 수익이 났을 때도 왜 났는지 알기 어렵고, 손실이 났을 때도 무엇이 문제였는지 분리하기 어렵다. 좋은 봇은 결과만 남기는 것이 아니라, 그 결과에 도달한 판단 경로를 남긴다.
좋은 봇은 경계가 분명하다
좋은 봇은 반드시 복잡해야 하는 것이 아니다. 오히려 처음에는 단순한 편이 좋다. 다만 단순한 것과 뒤섞인 것은 다르다. 단순한 구조는 각 부분이 적고 명확한 책임을 가진다. 뒤섞인 구조는 모든 책임이 한곳에 몰려 있다.
뒤섞인 구조
- 전략 코드가 데이터를 직접 가져온다.
- 지표 계산과 주문 요청이 한곳에 섞여 있다.
- 포지션 상태를 임의로 기억한다.
- 나중에 왜 그런 판단을 했는지 기록이 부족하다.
분리된 구조
- 데이터 입력과 전략 판단이 분리되어 있다.
- 상태가 별도로 관리된다.
- 판단 결과와 실행 요청이 구분된다.
- 판단 경로가 기록으로 남는다.
경계가 분명하면 문제가 생겼을 때 어디를 봐야 하는지 알 수 있다. 데이터가 이상하면 입력과 모델을 확인한다. 판단이 이상하면 feature와 전략 조건을 확인한다. 같은 신호가 반복 처리되면 state를 확인한다. 주문 요청이 어색하면 action request를 확인한다. 기록이 부족하면 record를 보강한다. 이렇게 문제를 좁혀갈 수 있을 때 시스템은 다룰 수 있는 대상이 된다.
반대로 모든 것이 한 함수 안에 섞여 있으면, 수익이 나도 왜 났는지 모르고 문제가 생겨도 어디서 틀어졌는지 찾기 어렵다. 자동매매에서 이 차이는 꽤 크다. 실전에서는 좋은 아이디어보다, 문제가 생겼을 때 다시 설명하고 고칠 수 있는 구조가 더 오래 살아남는다.
작은 봇도 시스템이어야 한다
시스템이라는 말은 때때로 너무 거창하게 들린다. 여러 서버, 대시보드, 복잡한 데이터 파이프라인, 운영팀이 있어야 시스템이라고 부를 수 있을 것처럼 느껴진다. 하지만 자동매매에서 시스템적 사고는 규모의 문제가 아니다. 아주 작은 개인 봇에도 시스템적 사고는 필요하다.
예를 들어 한 종목만 거래하는 간단한 봇이라도 다음 질문을 던질 수 있다. 데이터는 어디에서 들어오는가? 어떤 값이 확정된 값인가? 마지막으로 처리한 신호는 무엇인가? 이미 포지션이 있는데 또 진입하지 않도록 막는 기준은 어디에 있는가? 판단 결과는 나중에 볼 수 있게 남는가?
이 질문에 답할 수 있다면 작은 봇도 시스템의 형태를 갖기 시작한다. 반대로 거래 대상이 많고 지표가 복잡해도, 입력과 상태와 판단과 기록이 뒤섞여 있다면 그 봇은 아직 다루기 어려운 코드 덩어리에 가깝다.
Build 관점에서 중요한 것은 처음부터 완벽한 구조를 만드는 것이 아니다. 오히려 중요한 것은 구조를 볼 줄 아는 눈을 갖는 것이다. 지금 내 봇이 어디에서 데이터를 읽고, 어디에서 상태를 만들고, 어디에서 판단하고, 어디에 기록을 남기는지 그려볼 수 있어야 한다. 이 흐름을 그릴 수 없다면, 봇이 작동하고 있더라도 아직 충분히 설명 가능한 시스템은 아닐 수 있다.
신호보다 먼저 구조를 보자
자동매매에서 신호는 매력적이다. 어떤 조건에서 사야 하는지, 어떤 지표 조합이 수익률을 높였는지, 어떤 백테스트 곡선이 더 좋아 보이는지는 눈에 잘 들어온다. 하지만 신호는 혼자 움직이지 않는다. 신호는 데이터 위에서 만들어지고, 상태를 통과해 판단이 되고, 실행 가능한 요청으로 바뀌고, 기록으로 남아야 한다.
그래서 Build의 첫 질문은 “어떤 신호가 좋은가?”가 아니다. 그보다 먼저 물어야 할 질문은 이것이다. 이 신호는 어떤 데이터와 상태 위에서 만들어지는가?
이 질문이 생기면 봇을 보는 눈이 달라진다. 더 이상 봇을 매수·매도 규칙의 묶음으로만 보지 않게 된다. 봇은 시장을 읽는 입구, 데이터를 정리하는 방식, 상태를 보존하는 구조, 판단을 분리하는 경계, 기록을 남기는 습관으로 이루어진 시스템처럼 보이기 시작한다.
그리고 이 관점이 생기면 다음 질문도 자연스럽게 이어진다. 판단이 만들어졌다면, 그 판단은 실제 시장에서 어떻게 주문이 되고, 체결되고, 보호되어야 할까? 그 질문은 Build를 넘어 Execute의 영역이다.
좋은 전략이 기회를 만든다면, 좋은 구조는 그 기회를 반복 가능하고 설명 가능한 시스템으로 바꿔준다. 트레이딩 봇을 이해하는 첫걸음은 신호보다 먼저 구조를 보는 것이다.
Data / source