14 KiB
14 KiB
자동매매 사용/검증/보안 가이드 (3계층 구조)
이 문서는 자동매매를 아래 3개 영역으로 나눠서 설명합니다.
- 사용자 브라우저
- Next.js 서버(API)
- 워커(Node)
프롬프트 입력값이 실제로 어디 함수/어디 API로 흘러가는지 추적하려면 아래 문서를 같이 보세요.
common-docs/features/autotrade-prompt-flow-guide.md
1) 한눈에 구조
┌───────────────────────────── 사용자 브라우저 ─────────────────────────────┐
│ /trade 자동매매 UI │
│ - 설정 입력(전략/투자금/손실한도/임계치) │
│ - start/stop/heartbeat/signals 호출 │
└───────────────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────── Next.js 서버 (API) ──────────────────────────┐
│ /api/autotrade/strategies/* │
│ /api/autotrade/sessions/* │
│ /api/autotrade/signals/generate │
│ /api/autotrade/worker/tick │
└───────────────────────────────────────────────────────────────────────────┘
▲
│ x-autotrade-worker-token
│
┌────────────────────────────── Worker (Node) ─────────────────────────────┐
│ scripts/autotrade-worker.mjs │
│ - 주기적으로 /api/autotrade/worker/tick 호출 │
│ - heartbeat 만료 세션 정리 │
└───────────────────────────────────────────────────────────────────────────┘
1-1) 개발 실행 시 (내 PC 기준)
- 브라우저: React 화면 사용
- Next 개발 서버(
npm run dev): 화면 + API를 함께 처리 - 워커(
node scripts/autotrade-worker.mjs): tick 호출 담당
즉, 개발에서는 보통 Next 1개 + Worker 1개 프로세스를 실행합니다.
1-2) 운영 배포 시
운영은 보통 아래 2가지 중 하나입니다.
- 같은 Linux 서버에 Next + Worker 같이 운영
- Next는 배포 플랫폼, Worker는 별도 Linux 서버에서 운영
공통 원칙:
- 브라우저는 Next API를 호출
- 워커도 Next API(
/api/autotrade/worker/tick)를 호출 - 워커 인증은
x-autotrade-worker-token으로 처리
2) 레이어별 역할
2-1) 사용자 브라우저
하는 일:
- 자동매매 설정 입력
- 전략 컴파일/검증 요청
- 세션 시작 후 10초마다 heartbeat 전송
- 신호 요청 후 주문 가능 여부 판단
- 브라우저 종료/외부 이동 시 중지 처리
핵심 소스:
- UI:
AutotradeControlPanel - 엔진:
useAutotradeEngine - heartbeat 루프:
useAutotradeEngine - 주문 직전 게이트+주문 호출:
useAutotradeEngine
2-2) Next.js 서버(API)
하는 일:
- 사용자 인증 검사
- 전략 compile/validate 처리
- 세션 start/heartbeat/stop/active 관리
- AI 호출 실패 시 폴백 전략/신호로 대응
- 워커 토큰 인증 후 만료 세션 정리
핵심 소스:
- 공통 유틸:
_shared.ts - compile:
POST /strategies/compile - validate:
POST /strategies/validate - sessions:
/sessions/start,/sessions/heartbeat,/sessions/stop,/sessions/active - 신호 생성:
POST /signals/generate
2-3) 워커(Node)
하는 일:
- 주기적으로 Next API
/api/autotrade/worker/tick호출 - heartbeat 끊긴 세션을 timeout 종료
- 정리 결과 로그 출력
핵심 소스:
- 워커 스크립트:
autotrade-worker.mjs - 워커 API:
POST /worker/tick - 만료 정리 함수:
sweepExpiredAutotradeSessions()
3) 가장 헷갈리는 개념 3개
3-1) 폴백 전략(fallback)
뜻:
- AI를 못 쓰는 상황에서 쓰는 대체 규칙
- 자동매매를 완전 중지하지 않고 보수적으로 유지
- 애매하면
hold를 더 자주 반환
관련 소스:
- 전략 폴백:
createFallbackCompiledStrategy() - 신호 폴백:
createFallbackSignalCandidate() - AI 호출:
callOpenAiJson()
3-2) heartbeat
뜻:
- 브라우저가 Next 서버로 보내는 "세션 살아있음" 신호
- 워커가 보내는 신호가 아님
3-3) worker tick
뜻:
- 워커가 Next 서버로 보내는 "만료 세션 정리 요청"
- heartbeat가 끊긴 세션을 timeout 종료
3-4) 구독형 CLI 자동판단(신규)
뜻:
- OpenAI API 키 대신 서버에 설치된
gemini또는codexCLI를 호출해 자동판단 - 자동판단 결과(JSON)를 파싱해 전략/신호에 반영
- CLI 호출 실패 또는 파싱 실패 시 규칙 기반으로 자동 폴백
UI에서 선택:
- 자동매매 설정창에서
구독형 CLI 엔진을auto/codex/gemini중 선택 codex또는gemini선택 시 공식 문서 기반 추천 모델 목록을 드롭다운으로 선택- 목록에 없는 최신 모델은
직접 입력으로 설정
모델 우선순위:
- UI에서 선택한 모델(있을 때)
AUTOTRADE_CODEX_MODEL/AUTOTRADE_GEMINI_MODELAUTOTRADE_SUBSCRIPTION_CLI_MODEL- 각 CLI 기본 모델
환경변수:
AUTOTRADE_AI_MODE=subscription_cli
AUTOTRADE_SUBSCRIPTION_CLI=auto
AUTOTRADE_SUBSCRIPTION_CLI_MODEL=
AUTOTRADE_CODEX_MODEL=
AUTOTRADE_GEMINI_MODEL=
AUTOTRADE_SUBSCRIPTION_CLI_TIMEOUT_MS=60000
AUTOTRADE_SUBSCRIPTION_CLI_DEBUG=0
AUTOTRADE_CODEX_COMMAND=
AUTOTRADE_GEMINI_COMMAND=
동작 우선순위:
AUTOTRADE_SUBSCRIPTION_CLI=auto면 codex -> gemini 순서로 시도- 모델 선택 우선순위는
vendor 전용 모델->AUTOTRADE_SUBSCRIPTION_CLI_MODEL->CLI 기본 모델 - 둘 다 실패하면 fallback 규칙 신호 사용
- 로그에
attempts=codex:default:timeout가 나오면 CLI 타임아웃이므로AUTOTRADE_SUBSCRIPTION_CLI_TIMEOUT_MS를 더 크게 설정 - 로그에
attempts=codex:gpt-5-codex:error(...)처럼 괄호가 붙으면 실제 실패 원인(stderr/spawn 에러)입니다.
어떤 CLI를 썼는지 확인:
- 자동매매 로그에서
신호 수신 [subscription_cli:codex:gpt-5-codex]또는신호 수신 [subscription_cli:gemini:flash]확인 - Network 응답에서
providerVendor확인/api/autotrade/strategies/compile응답:compiledStrategy.providerVendor/api/autotrade/signals/generate응답:signal.providerVendor
- Network 응답에서
providerModel확인/api/autotrade/strategies/compile응답:compiledStrategy.providerModel/api/autotrade/signals/generate응답:signal.providerModel
- 파싱 실패 시 reason/summary에
selected=vendor:model; attempts=...형태로 시도 결과 포함
selected=none:default; attempts=codex:gpt-5-codex:error(...)가 보이면:
AUTOTRADE_SUBSCRIPTION_CLI_DEBUG=1로 켜고npm run dev를 재시작합니다.- Next 서버 콘솔에서
[autotrade-cli]로그를 확인합니다. spawn:ENOENT가 보이면AUTOTRADE_CODEX_COMMAND또는AUTOTRADE_GEMINI_COMMAND에 CLI 절대경로를 넣습니다.- 예:
AUTOTRADE_CODEX_COMMAND=C:\\Users\\<계정>\\AppData\\Roaming\\npm\\codex.cmd
모델 지정 예시:
# Codex만 쓸 때
AUTOTRADE_SUBSCRIPTION_CLI=codex
AUTOTRADE_CODEX_MODEL=gpt-5-codex
# Gemini만 쓸 때
AUTOTRADE_SUBSCRIPTION_CLI=gemini
AUTOTRADE_GEMINI_MODEL=flash
# auto 모드에서 공통 모델 fallback만 쓸 때
AUTOTRADE_SUBSCRIPTION_CLI=auto
AUTOTRADE_SUBSCRIPTION_CLI_MODEL=auto
공식 문서:
- Codex CLI 옵션(
--model): https://developers.openai.com/codex/cli - OpenAI 모델 목록(
gpt-5-codex포함): https://platform.openai.com/docs/models - Gemini CLI 모델 선택: https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/model.md
- Gemini CLI 모델 우선순위(
--model>GEMINI_MODEL): https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/model-routing.md
모델 갱신 운영 런북:
- 새 모델 출시 대응 절차:
autotrade-model-catalog-runbook.md
관련 소스:
- CLI 공급자:
lib/autotrade/cli-provider.ts - 전략 compile 라우트:
/strategies/compile - 신호 generate 라우트:
/signals/generate
4) 환경변수: 어디에 넣는지
4-1) 앱(Next.js 서버)
위치:
- 로컬:
.env.local - 운영: 배포 환경변수
필수:
AUTOTRADE_WORKER_TOKEN=<랜덤시크릿>
OPENAI_API_KEY=<옵션, 없으면 폴백 동작>
4-2) 워커(Node/PM2)
위치:
- PM2 실행 셸 환경변수
- 서버 시스템 환경변수
필수:
AUTOTRADE_WORKER_TOKEN=<앱과동일값>
AUTOTRADE_APP_URL=<Next서버URL>
AUTOTRADE_WORKER_POLL_MS=5000
중요:
AUTOTRADE_WORKER_TOKEN은 사용자별이 아니라 서비스별 시크릿- 앱과 워커가 같은 값을 써야 인증 통과
5) 실행 순서 (앱/워커 분리)
5-1) 로컬 개발
터미널 A:
npm run dev
터미널 B:
AUTOTRADE_WORKER_TOKEN="<앱과같은값>" \
AUTOTRADE_APP_URL="http://127.0.0.1:3001" \
node scripts/autotrade-worker.mjs
Windows PowerShell:
npm run dev
# 새 터미널
$env:AUTOTRADE_WORKER_TOKEN="<앱과같은값>"
$env:AUTOTRADE_APP_URL="http://127.0.0.1:3001"
$env:AUTOTRADE_WORKER_POLL_MS="5000"
npm run worker:autotrade
또는 .env.local 기반:
npm run worker:autotrade:dev
5-2) 운영(PM2)
export AUTOTRADE_WORKER_TOKEN="<앱과같은값>"
export AUTOTRADE_APP_URL="https://your-domain.com"
export AUTOTRADE_WORKER_POLL_MS="5000"
pm2 start scripts/pm2.autotrade-worker.config.cjs
pm2 logs autotrade-worker
6) end-to-end 흐름 (브라우저 -> 서버 -> 워커)
- 브라우저: 설정 입력
- 서버:
/strategies/compile(AI 또는 폴백) - 서버:
/strategies/validate(리스크 계산) - 서버:
/sessions/start - 브라우저: 10초마다
/sessions/heartbeat - 브라우저: 주기적으로
/signals/generate - 브라우저: 리스크 게이트 통과 시 주문 API 호출
- 브라우저: 중지 이벤트 시
/sessions/stop - 워커:
/worker/tick로 heartbeat 만료 세션 정리
6-1) AI가 실제로 받는 판단 데이터
자동매매는 "자연어 프롬프트만" 보내는 구조가 아닙니다. 실행 중에는 아래 구조화된 데이터가 같이 전달됩니다.
- 전략(compile 결과)
selectedTechniquesconfidenceThresholdmaxDailyOrderscooldownSecmaxOrderAmountRatio
- 시세 스냅샷(signal 요청 시)
symbolcurrentPricechangeRateopen/high/lowtradeVolumeaccumulatedVolumerecentPrices(최근 체결가 배열)
- 서버 리스크 검증 결과
- AI 신호가
buy/sell이어도 리스크 게이트 미통과 시 주문 차단
- AI 신호가
즉, AI는 "현재 종목 + 현재가 + 가격 흐름 + 전략 제약"을 같이 받아 판단하고, 최종 주문은 리스크 게이트를 통과해야 실행됩니다.
관련 소스:
- 스냅샷 구성:
useAutotradeEngine.ts - 신호 route 검증:
signals/generate/route.ts - 리스크 게이트:
risk.ts
7) 보안: 레이어별 핵심
7-1) 브라우저
- KIS 민감정보는 세션 저장소(sessionStorage) 사용
- 브라우저 종료 시 세션 저장소 제거
7-2) Next 서버
- 자동매매 API는 사용자 인증 필요
- 워커 API는
x-autotrade-worker-token인증 필요 - 민감정보 문자열 마스킹 처리
7-3) 워커
- 토큰이 틀리면 401
- 토큰은 코드 하드코딩 금지
8) 역할별로 어디 보면 되는지
- 기획/대표: 1, 2, 6, 7장
- QA: 5, 6, 7장 + worker 문서 6, 7장
- 개발: 2장 소스링크 + worker 문서 전체
9) 추가 문서
- 워커 상세 운영:
autotrade-worker-pm2.md