Files
auto-stock/docs/BATCH_GUIDE.md
shuim 2425fd2276 fix: ML 게이트 스케일 불일치 + 운영 실측 반영 (문서 정정 3건)
## ML 게이트 이중 블렌딩 (플래그 OFF 로 출고)
market_analyzer.py:603-608 이 이미 rule30/ML70 으로 블렌딩한 뒤 0~15 로 축소
저장하는데, trade_executor 가 그 값을 정규화 없이 **또** 블렌딩했다.
  weighted_score = score_val(0~15) * 0.3 + ml_score(0~100) * 0.7  ≥ 60
룰 기여가 최대 4.5 로 임계 60 의 7.5% — 문서상 "룰 30%" 가 지켜지지 않았다.

_ml_gate_score_v2() 신설 + ML_SCORE_NORMALIZE_ENABLED(기본 False).
OFF 시 7,373 조합 비트 동일 검증. RULE_SCORE_MAX=15 신설(하드코딩 제거).

운영 실측으로 확인된 것: ML-BUY 분기는 어느 설정으로도 발화 불가.
  OFF: ml_score ≥ 85.7 필요 / 실측 ml_score 최대 50
  ON : score ≥ 9 필요    / 실측 score 역대 최대 6 (801건)
즉 ML 게이트는 HOLD 차단(브레이크)으로만 기능해 왔다. 임계값 재보정이
필요하며 §8.1-5 에 따라 백테스트가 선행돼야 한다.

## 문서 정정 (잘못된 전제 제거)
1. "NAS 다운 → 백테스트 불가" 는 사실이 아니다. NAS 는 가동 중이고
   autostock-postgres 도 떠 있다. DB 가 127.0.0.1:15433 바인딩이라 외부
   직결만 안 되는 것이며, NAS 내부에서 접근 가능하다. **백테스트 재실행 가능.**
2. docs/BATCH_GUIDE.md 의 cron 서술 정정 — 운영 NAS 에 crontab 이 없고
   앱 내부 스케줄러(main.py:269 → schedulers.py:74, 10분 간격)가 배치를 돌린다.
   setup-cron.sh 를 쓰면 오히려 중복 실행된다.
3. market_schedule.py 에 휴장일 판정이 없다 — 2026-09-24~25 거래·분석 0건은
   추석 연휴이며 장애가 아니다.

## §8.4.1 운영 실측 신설
- daytrading 257건 vs swing 53건 (DT 가 거래 건수 주력). DT 포지션 0 은
  15:20 EOD 전량 청산이 설계대로 동작한 결과
- strategy_configs 가 옛 값으로 운영되던 상태(RSI 30 / SL -6%)를
  2026-09-28 배포(alembic 0011→0012)로 해소
- 룰 점수는 0~15 스케일(market_analyzer.py:608 에서 축소 저장), 실측 -1~6
- 9/23 에 active_trades 유령 행 129개(day_trade 120 + swing 9)를 수동 정리한
  백업이 남아 있다 — 전략명 없이 close 해 엉뚱한 행이 닫히던 문제의 증거

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-28 11:27:06 +09:00

5.9 KiB

배치 분석 가이드

2026-09-27 정리: BATCH_GUIDE.md 와 BATCH_ANALYSIS_GUIDE.md 두 문서를 하나로 합쳤다. 두 문서가 종목 수(200 vs 60)·cron 시각(09:00 vs 08:50)·실행 스크립트를 서로 다르게 적고 있었고, 양쪽 모두 존재하지 않는 스크립트(run-batch.sh, start-all.sh)를 안내하고 있었다. 아래 내용은 실제 코드(setup-cron.sh, backend/batch_daily_analysis.py, config.py)를 확인해 작성했다.

개요

장 시작 전에 전체 종목을 분석해 stock_analysis 테이블에 캐시한다. 대시보드 첫 진입 시 실시간 분석(30초)을 기다리지 않고 DB에서 바로 읽는다.

배치는 선택사항이다. 실행하지 않아도 첫 진입 시 실시간 분석이 자동 수행되며, 그 경우 10~30초가 걸린다.

무엇이 언제 도는가

⚠️ 2026-09-28 정정: 아래 cron 방식은 setup-cron.sh 가 제공하는 선택적 경로다. 운영 NAS 에는 crontab 이 등록되어 있지 않고(root·사용자 모두 비어 있음), 실제로는 앱 내부 스케줄러가 배치를 돌린다. 이전 판(2026-09-27)이 cron 을 주 메커니즘으로 기술한 것은 스크립트만 읽고 실제 운영 상태를 확인하지 않은 오류였다.

실제 동작 (기본): 앱 기동 시 main.py:269 가 batch_analysis_scheduler() 태스크를 띄우고, services/schedulers.py:74 가 10분 간격으로 stock_analysis 를 갱신한다. cron 등록 없이도 분석 데이터가 쌓이며, 실측으로 평일 200종목 전후가 매일 저장된다.

로그는 컨테이너 로그로 나간다: docker logs autostock-backend | grep -i batch

선택: cron 등록 — setup-cron.sh 를 실행하면 아래 3개 잡이 등록된다(모두 평일, docker exec 경유). 앱 내부 스케줄러와 중복 실행되므로, 쓸 거라면 어느 쪽을 정본으로 할지 먼저 정하라.

시각 스크립트 로그
06:00 prefetch_token.py logs/token_prefetch.log
08:50 batch_daily_analysis.py logs/batch_analysis.log
09:00~15:00 매 10분 batch_intraday_analysis.py logs/batch_intraday.log

토큰 프리페치가 06:00 에 먼저 도는 이유: KIS 토큰 발급은 1분에 1회 제한이라, 08:50 배치가 토큰 발급부터 시작하면 실패 시 재시도 여유가 없다.

⚠️ 공휴일 인식이 없다. core/market_schedule.py 는 요일·시간만 판정하고 휴장일 목록이 없다. 2026-09-24~25(추석 연휴)에 stock_analysis 행과 거래가 0건인 것은 정상이며 장애가 아니다. 휴장일에 분석이 도는 것을 막고 싶으면 휴장일 판정을 추가해야 한다.

수동 실행

컨테이너 밖에서 돌릴 때는 프로젝트 venv 를 쓴다.

cd backend

# 테스트 (10종목)
../.venv/bin/python batch_daily_analysis.py --test

# 개수 제한
../.venv/bin/python batch_daily_analysis.py --limit 30

# 전체
../.venv/bin/python batch_daily_analysis.py

컨테이너 안에서:

docker exec autostock-backend python /app/batch_daily_analysis.py --test

인자는 --test(10종목)와 --limit N 두 개뿐이다.

자동 실행

./setup-cron.sh          # 3개 잡 등록 (이미 있으면 건너뜀)
crontab -l | grep batch  # 확인
crontab -e               # 제거는 해당 라인 삭제

setup-cron.sh 는 docker 명령을 찾지 못하면 중단한다. 컨테이너명은 autostock-backend 로 고정되어 있다.

로그

tail -f logs/batch_analysis.log
tail -100 logs/batch_analysis.log

동작 방식

  1. 종목 목록 조회 — 네이버 시가총액 순위(naver_finance, KOSPI+KOSDAQ). 실패 시 stock_daily_prices 최근 거래일 기준으로 폴백
  2. 종목별 기술적 분석 — RSI, MA5/20/60, 볼린저, 스토캐스틱 등
  3. stock_analysis 테이블에 upsert
  4. 장 시작 후 첫 진입은 이 캐시를 읽는다

분석 종목 수는 config.py 의 ANALYSIS_STOCK_COUNT(기본 300)가 결정한다. 이 값은 strategy_configs DB 테이블로도 덮일 수 있다 — CLAUDE.md §0 파라미터 우선순위 참고.

소요 시간

종목당 API 대기가 있어 개수에 거의 비례한다. 10종목 약 30초, 30종목 약 2분 기준으로 추정하면 된다. 정확한 값은 logs/batch_analysis.log 의 실제 실행 기록을 보는 것이 맞다.

API 제한 대응

KIS API 제한:

  • 토큰 발급 1분에 1회
  • 호출 초당 2회 권장

배치 쪽 대응:

  • 종목 분석 사이 대기
  • 에러 시 지수 백오프 재시도

조회 API

전역 프리픽스는 /api/v1 이다.

# 빠른 조회 (DB 캐시)
GET /api/v1/recommendations/rule-based

# 실시간 분석 (느림)
GET /api/v1/recommendations/rule-based?realtime=true
GET /api/v1/recommendations/rule-based/realtime   # 분석 후 DB upsert + 반환

프론트엔드는 기본을 DB 조회로 두고, 실시간은 명시적 버튼으로 분리하는 것이 좋다.

stock_analysis 주요 컬럼

backend/app/models/models.py 의 StockAnalysis 가 정본이다.

stock_code, stock_name, analysis_date, current_price, change_rate, volume,
rsi, ma5, ma20, ma60, stochastic_k, stochastic_d, signals(JSONB), score, ...

문제 해결

cron 이 실행되지 않음 (macOS)

sudo launchctl list | grep cron

cron 잡이 docker exec 를 쓰므로 Docker Desktop 이 떠 있어야 한다.

"접근토큰 발급 잠시 후 다시 시도하세요" 반복 토큰 발급 1분 제한에 걸린 것이다. 06:00 프리페치 잡이 등록됐는지 먼저 확인하고, 수동 실행을 연달아 하지 않는다. ⚠️ 로컬에서 배치를 돌릴 때 NAS 와 같은 앱키를 쓰면 서로 토큰을 무효화한다. 로컬 실행은 앱키를 분리하거나 피한다.

DB 연결 에러

docker compose ps
docker compose logs autostock-db --tail 50