PersonalTrader — LangGraph 멀티에이전트 주식 자동매매
여러 역할의 LLM 에이전트가 리서치부터 주문까지 분담하는 한국·미국 주식 자동매매
배경
주식 자동매매 봇은 보통 단일 전략을 따르거나 LLM 한 번 호출로 모든 판단을 끝낸다. PersonalTrader는 한국투자증권·키움증권 실계좌 위에서, 종목 리서치·토론·리스크 판정·주문 실행을 각각 다른 역할의 LLM 에이전트가 맡고, 매일 저녁 거래를 회고해 다음날 프롬프트에 피드백하는 구조를 목표로 했다. 실계좌 연결이라는 제약 때문에 판단 계층(시세·분석)과 실행 계층(주문)을 네트워크로 분리하고, 배포를 점진화해야 했다.
시스템 구조
- 러너 두 층:
simplified_runner.py가 Scan→Score→Guard→Execute 4단계 메인 경로를 담당하고, LangGraph가 그 위에 Planning Graph(아침 리서치·저녁 회고)와 Session Graph(장중 모니터링)를 구성한다. - Zero Trust 3망:
analysis_net(시세·LLM),execution_net(주문 전용),shared_net(DB·Redis·Kafka)로 Docker 네트워크를 분리해 분석 컨테이너에서 주문 API를 호출할 수 없다. - 멀티 브로커 Factory:
broker/factory.py가 KIS(국내·해외)와 키움(국내) 어댑터를 계정 단위로 선택한다. 브로커 자격증명은 Fernet으로 암호화해 DB에 저장한다. - 이벤트 버스: Kafka 7 토픽에 15개
EventType(Sense/Think/Act/Learn)을 흘려AuditLog가 해시 체인으로 시퀀스 갭을 검증한다.
해결 과정
러너 단순화와 LangGraph 공존. 초기에는 LangGraph 노드가 파이프라인 실행까지 전담했는데, 디버깅·재시도·Celery 연결이 모두 무거워졌다. 메인 실행 경로를 SimplifiedRunner(Scan→Score→Guard→Execute) 4단계로 분리하고, LangGraph는 Planning/Session Graph처럼 LLM이 주도하는 의사결정 레이어에 남겼다. Celery 태스크가 SimplifiedRunner를 호출하고, LangGraph 노드들도 필요 지점에서 같은 러너를 재사용한다.
Planning Graph와 Session Graph 분리. LangGraph 인스턴스를 시점별로 둘로 나눴다. Planning Graph(planning_graph.py)는 장 시작 전 리서치(어제 회고 + 오늘 후보 종목 선정)와 장 마감 후 회고를 맡고, Celery Beat가 정해진 시각에 트리거한다. Session Graph(session_graph.py)는 장중 보유 종목 모니터링과 신규 진입 의사결정을 분 단위로 반응시키는 짧은 그래프다. 분리 덕에 디버깅 시 어느 그래프의 노드가 멈췄는지가 즉시 보이고, 비실시간 그래프는 LLM 호출을 모아 묶어 비용을 절감할 수 있다.
Zero Trust 네트워크 분리. 시세·분석을 맡는 backend와 주문을 내는 executor를 각각 analysis_net, execution_net에 두고, DB·Redis·Kafka만 shared_net으로 공유한다. 분석 컨테이너는 주문 엔드포인트에 TCP로 닿지 못한다.
브로커 자격증명 Fernet 암호화. 환경변수 마스터 키를 SHA-256으로 파생해 Fernet 키를 만들고, app_key_enc·secret_key_enc 컬럼에 암호화해 저장한다. key_version 컬럼으로 키 로테이션을 남겨둔다.
인증과 감사. /auth/login이 bcrypt로 1차 검증한 뒤 5분짜리 임시 토큰을 발급하고, pyotp 기반 TOTP(Time-based One-Time Password) 검증을 통과해야 Access/Refresh를 준다. AuditLog는 prev_hash = SHA-256(prev_hash | ts | actor | action | resource | outcome)로 해시 체인을 이어 변조를 탐지한다. 비상 시 POST /api/kill-switch로 Redis 플래그를 세우면 모든 파이프라인이 즉시 멈춘다.
4단계 점진 배포. BACKTEST(히스토리 OHLCV — 시·고·저·종가·거래량 캔들로 슬리피지·수수료 반영) → PAPER(KIS 모의투자 API) → CANARY(소규모 실계좌, 예산 제한) → LIVE(Kill Switch 필수, 일 손실 3% 한도)로 단계를 두고, 각 단계가 다음 단계의 전제 조건이 되도록 배포 상태를 DB에 기록한다.
학습 루프. 매일 저녁 거래별로 ReflectionRecord에 귀인(attribution_signal/execution/regime)·실패 유형·교훈을 쌓고, DailyReflectionSummary로 묶는다. 다음날 아침 Planning Graph가 이 요약을 feedback_context로 주입해 누적된 교훈이 프롬프트에 반영된다.
성과
- SimplifiedRunner(4단계) + LangGraph(Planning/Session Graph)의 2층 구조로 실행 경로와 의사결정 레이어를 분리.
- Backend 75 API 엔드포인트, 24 DB 테이블, Frontend 페이지 8·컴포넌트 72로 구성된 풀스택을 1인으로 설계·개발.
- Kafka 7 토픽 15 EventType으로 Sense/Think/Act/Learn 이벤트를 기록, 해시 체인
AuditLog로 위변조 검증. - Zero Trust 3망 분리 + Fernet 자격증명 암호화 + JWT+TOTP 2FA + Kill Switch로 실계좌 전제 보안 체계 구성.
- KIS(국내·해외)와 키움(국내) 어댑터를 Factory로 통합, 브로커 추가 시 어댑터 1개만 작성하면 된다.
- BACKTEST → PAPER → CANARY → LIVE 4단계 배포 모드와 Sharpe·Sortino·MaxDD·Calmar 등 위험조정 수익률 지표 기반 백테스트 프레임워크 구성.