단타 매수/매도 시뮬레이션
QuantPilot의 두 번째 단계에서는 AI 미사용 단타 매수와 매도 시뮬레이션 흐름을 먼저 만들었다.
처음부터 실제 주문을 넣는 것은 부담이 컸다. 코드가 의도대로 동작하는지, 수량 계산이 맞는지, 익절과 손절 기준이 제대로 적용되는지 확인되지 않은 상태에서 실제 계좌와 연결하는 것은 위험했다.
그래서 먼저 만든 것은 가상 포지션이었다. 실제 프로젝트에서는 POST /simulations/intraday로 run을 만들고, KIS 현재가나 WebSocket 체결가를 tick으로 넣어 상태를 갱신하는 구조로 정리했다.
관심 종목에서 매수 조건이 맞았다고 판단되면 실제 주문을 넣는 대신, 현재가 기준으로 매수했다고 기록했다. 이후 가격이 움직이면 목표 수익률, 손절 기준, 보유 시간 기준에 따라 매도 시점이 발생하는지 확인했다.
이 단계에서 확인한 핵심 흐름은 다음과 같다.
- 관심 종목의 현재가 조회
- 사용자가 지정한 매수 가격 범위 판단
- 가상 매수 포지션 생성
- 가격 변화에 따른 평가 손익 계산
- 익절/손절 기준 도달 시 가상 매도 처리
- 매수/매도 판단 로그 저장
시뮬레이션이 성공하면서 최소한의 구조는 확인할 수 있었다. 시장 데이터가 들어오고, 조건이 평가되고, 포지션이 생기고, 매도 결과가 남는 흐름이 이어졌다.
실제 매수/매도에서 겪은 부분
시뮬레이션이 된다고 해서 실제 주문이 바로 안정적으로 되는 것은 아니었다.
실제 매수/매도에서는 KIS API 응답, 주문 가능 금액, 호가 단위, 주문 수량, 체결 여부 같은 요소가 추가로 들어왔다. 특히 시뮬레이션에서는 “현재가에 샀다”고 가정하면 끝이지만, 실제 주문에서는 주문이 접수됐는지, 체결됐는지, 일부만 체결됐는지, 거절됐는지까지 봐야 했다.
처음 겪은 문제는 시스템 상태와 실제 계좌 상태가 어긋날 수 있다는 점이었다.
예를 들어 주문 요청은 성공했지만 체결 확인이 늦게 들어오면, 앱 입장에서는 포지션이 생겼다고 봐야 할지 기다려야 할지 애매해진다. 반대로 주문이 실패했는데 내부 상태만 매수 완료로 바뀌면 이후 매도 판단 전체가 틀어진다.
그래서 실제 주문 쪽은 다음 기준으로 정리했다.
- 주문 요청 성공과 체결 성공을 같은 의미로 보지 않는다.
- 실제 보유 수량은 API 조회 결과를 기준으로 다시 확인한다.
- 주문 전 계산 값과 주문 후 응답 값을 모두 남긴다.
dry_run,kill_switch,live_trading_enabled, KIS 잠금 상태를 모두 확인한다.- 실패 응답은 예외로만 처리하지 않고 거래 이벤트로 기록한다.
- 자동 매도는 실제 보유 상태 확인 후에만 실행한다.
이 결정은 조금 느려 보일 수 있지만, 돈과 연결되는 기능에서는 맞는 방향이라고 봤다.
AI 자동 적용을 고민한 이유
두 번째 단계에서 AI 자동 판단도 같이 검토했다.
처음 생각은 단순했다. 관심 종목의 가격, 등락률, 거래량, 최근 움직임을 모델에 넘기고 “지금 매수할 만한가”를 판단하게 하면 좋지 않을까 싶었다. 사람이 점심시간에 30분만 확인할 수 있다면, 나머지 시간에는 AI가 후보를 골라주면 편할 것 같았다.
하지만 실제로 생각해보니 바로 GPT를 붙이는 것은 맞지 않았다.
가장 큰 이유는 비용이었다.
주식 데이터는 한 번 물어보고 끝나는 데이터가 아니다. 장중에는 계속 변한다. 관심 종목이 여러 개라면 각 종목의 상태를 반복해서 판단해야 한다. 여기에 모델 호출을 계속 붙이면 개인 프로젝트 기준에서는 비용이 금방 부담이 될 수 있었다.
그리고 투자 판단은 단순한 텍스트 요약과 다르다. 모델이 그럴듯한 이유를 말해도, 그 판단이 수익으로 이어진다는 보장은 없다. 오히려 모델 답변을 너무 믿으면 내가 세운 기준보다 설명이 더 그럴듯해 보이는 문제가 생길 수 있다.
그래서 GPT는 자동 루프의 기본 엔진으로 쓰지 않기로 했다.
GPT를 바로 쓰지 않은 결론
GPT를 완전히 배제한 것은 아니다. 실제 프로젝트에도 OpenAI Responses API를 이용한 1회 판단 API는 남겨두었다. 다만 대시보드에서 반복 실행되는 자동 판단 루프의 기본 공급자는 Ollama 로컬 모델로 두기로 했다.
정리하면 이유는 다음과 같다.
- 장중 반복 호출 비용이 개인 프로젝트 범위를 넘어갈 수 있다.
- 실시간성이 필요한 판단에 외부 API 지연 시간이 부담이 될 수 있다.
- 투자 판단 근거가 그럴듯해 보여도 검증 가능한 규칙으로 남기 어렵다.
- 모델 응답 실패나 제한 상황에서 매매 흐름이 흔들릴 수 있다.
- 초기 단계에서는 AI보다 규칙 기반 판단과 로그 축적이 더 중요하다.
대신 GPT는 나중에 매매 결과를 요약하거나, 내가 놓친 패턴을 복기하는 용도로 더 적합하다고 판단했다. 즉, 실시간 매수 버튼을 누르는 역할보다 기록을 분석하고 설명하는 역할에 가깝다.
Ollama는 비용 부담 없이 반복 테스트를 돌릴 수 있다는 점이 컸다. 품질은 계속 검증해야 하지만, 관심종목을 주기적으로 순회하며 buy, sell, hold, watch 판단을 남기는 실험에는 로컬 모델이 더 맞았다.
AI 모델 선택 기준
그렇다고 AI를 아예 빼겠다는 의미는 아니었다. 다만 모델을 고를 때 기준이 필요했다.
QuantPilot에서 AI 모델을 본다면 기준은 다음 순서가 맞다고 봤다.
- 비용: 장중 반복 판단을 감당할 수 있어야 한다.
- 속도: 판단 결과가 늦게 오면 단타에는 의미가 줄어든다.
- 일관성: 같은 조건에서는 비슷한 판단을 내려야 한다.
- 설명 가능성: 왜 매수/보류/매도인지 근거가 남아야 한다.
- 로컬 실행 가능성: 외부 API 없이 테스트할 수 있으면 좋다.
- 보수적인 판단: 애매하면 매수하지 않는 쪽이 안전하다.
처음에는 Ollama 쪽도 qwen2.5:7b를 기준으로 생각했다. 가볍고 로컬에서 돌리기 쉬워서 자동 판단 루프를 검증하기에는 좋았다. 하지만 관심종목, 최근 시세, 1초봉, 공시, 뉴스, 가상 포지션, 운용금액 기준을 한 번에 넣기 시작하니 판단 근거가 너무 얕아지는 문제가 보였다.
그래서 이후 기본 모델은 qwen2.5:14b 쪽으로 올리는 방향을 잡았다. 7b는 빠른 테스트용으로 남기고, 자동 판단 품질을 조금 더 봐야 하는 단계에서는 14b를 쓰는 방식이다. 32b도 후보로 볼 수 있지만 로컬 실행 부담이 커서 관심종목 수와 판단 주기를 줄여야 한다.
이 결정은 단순히 “더 큰 모델이 좋다”는 이야기가 아니었다. 장중 자동 판단에서는 속도도 중요하지만, 판단 근거가 빈약하면 오히려 위험하다. 그래서 빠른 모델은 개발 루프에, 조금 큰 모델은 실제 판단 품질 확인에 쓰는 식으로 역할을 나누기로 했다.
결론적으로 두 번째 단계에서는 AI 판단을 바로 실거래에 연결하지 않았다. 먼저 규칙 기반으로 판단하고, AI는 그 판단을 보조하거나 시뮬레이션 결과를 분석하는 방향으로 남겨두었다.
이번 단계의 결론
이번 작업을 통해 시뮬레이션과 실제 주문 사이의 간격을 체감했다.
시뮬레이션에서는 “조건이 맞으면 매수, 목표가에 도달하면 매도”로 단순하게 생각할 수 있다. 하지만 실제 주문에서는 계좌 상태, 주문 상태, 체결 상태, API 응답 지연, 실패 처리까지 모두 시스템 안에 들어와야 한다.
그래서 결론은 다음과 같았다.
- 단타 매수/매도 시뮬레이션은 성공했다.
- 실제 매수/매도는 주문 성공과 체결 성공을 분리해서 관리하기로 했다.
- GPT는 비용과 실시간성 문제 때문에 실거래 판단 엔진으로 바로 쓰지 않기로 했다.
- Ollama 모델은 빠른 테스트용
qwen2.5:7b, 판단 품질 확인용qwen2.5:14b로 나누어 보기로 했다. - AI 모델은 비용, 속도, 일관성, 설명 가능성, 보수성을 기준으로 검토한다.
- 다음 단계에서는 Ollama 기반 AI 자동 판단을 가상 매매와 통계에 먼저 붙여본다.
“실제 매매 기능에서 중요한 것은 매수 버튼을 누르는 코드보다, 누르지 말아야 할 상황을 구분하는 코드였다.”
시리즈
- QuantPilot 프로젝트를 시작하며
- 단타 매수/매도 시뮬레이션과 AI 모델 검토 (현재 글)
- AI 자동 판단 테스트와 현재 시스템 정리