fix: 매매 파라미터 3중 소스 정합 + 리스크 가드 복원 + 죽은 코드 2,695줄 제거

## 배경
"전략이 혼란스럽고 현재와 맞지 않는다"를 조사한 결과, 전략 설계가 아니라
전략을 검증했다는 도구와 파라미터 소스가 어긋나 있었다.

## 파라미터 소스 단일화
- 우선순위가 adaptive > strategy_cfg(DB) > config.py 인데 문서는 맨 마지막인
  config.py 를 기술하고 있었다. 11곳이 불일치(BULL RSI 46 vs DB 30, SL -7% vs -6%).
- DEFAULT_PARAMS 를 config.py 에 정합 + alembic 0012 로 기존 DB 행 갱신
  (운영자가 UI 로 바꾼 값은 보존, 옛 기본값과 같은 행만 갱신, 테이블 가드·멱등)

## 백테스트를 실전 로직에 정합
- calculate_adx_simple 이 정확히 period 배(14.0×) 발산 → Aggressive 게이트
  `ADX>25` 가 전 레짐 100% 통과. 전환 빈도 5.6%→2.0%(-65%), 성과 상방 편향
- 백테스트 RSI 는 SMA, 실전은 Wilder → 진입 판정 10~11% 불일치
- us_backtest_engine RSI 1봉 지연 제거 (룩어헤드 없음을 절단 테스트로 증명)
- backend/backtest_results/ 25건은 폐기 대상 (§8.4)

## 리스크 가드 복원
- 4% 절대 상한이 try 블록 안에 있어 예외 시 적응형 6~7% 가 통과 → try 밖으로
- 청산을 매수보다 먼저 평가 (보유 종목이 추천에 들면 손절 대신 물타기가 나갔다)
- 리스크 가드 4개를 매수 전용화 → MDD -10%·보유한도 도달 시에도 손절 작동
- MDD 갱신 5회 연속 실패 시 신규 진입 차단 fail-safe (청산은 계속 허용)
- 스윙 청산이 DT 보유분까지 매도하던 문제, sell_pct 기준 혼재 정정

## 죽은 코드 제거 (2,695줄)
- short_term_strategy, kosdaq_scanner, app/strategy/ 패키지
- app/trading/ + korea_investment_api_adapter (real_market_api 정본은
  korea_investment_api.py:1482, adapter 는 import 0건)

## 지표·사이징 단일화 (수치 무변경 증명)
- indicators_core.py: 3,274건 비교 최대 오차 0.000e+00
- sizing_core.py: 42,105건 비교 불일치 0
- 미국 전략 상수 13개 config 편입 (hex 까지 동일, 3,168 케이스 전수 비교)

## 테스트 안전 (실 KIS 호출 차단)
- 유닛 테스트가 실제 KIS 에 매도 주문을 2회 전송하고 있었다. 리팩터링이
  close_stale_positions 의 대상을 _execute_exit → _execute_exit_stale 로
  바꿨는데 목이 전자에 걸려 빗나갔다. test_api_endpoints 도 캡처된 싱글톤
  참조 누수로 실제 잔고 조회를 타 141초를 소비했다.
- backend/tests/conftest.py 신설: 주문·토큰·시세·잔고를 호출 즉시 예외로 차단.
  예외는 BaseException 파생(프로덕션 except Exception 폴백에 삼켜지지 않게),
  클래스 메서드에 적용(캡처된 참조까지 덮음), DATABASE_URL `_test` 가드 강제
- 전체 유닛 스위트: 365초/6 failed → 11.8초/0 failed (소켓 차단 하 559 passed)

## 신규 (둘 다 플래그 OFF, 백테스트 미검증)
- range_trading_strategy.py — SIDEWAYS 담당 전략이 없던 빈 칸. 미배선
- check_bear_buy_signal_v2 — BEAR 4중 AND(발화율 2.3%) → 점수제(12.4%)

## 문서
- CLAUDE.md 를 실제 코드 기준으로 재작성. §0 파라미터 우선순위, §4.1 테스트 규약,
  §6.4 문서화되지 않았던 진입 차단 게이트 9종, §8.4 백테스트 폐기 근거,
  §8.5 미해결 19항목
- 루트 md 6개 → 2개(docs/ 이동), 중복 배치 문서 병합, 스테일 worktree 제거

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-28 08:58:18 +09:00
parent b4608e5abf
commit 1b9257c4d2
71 changed files with 5510 additions and 3685 deletions

View File

@@ -1,101 +1,131 @@
# 배치 분석 시스템 사용 가이드
# 배치 분석 가이드
> 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`)를 확인해 작성했다.
## 개요
매일 아침 전체 종목을 분석하여 DB에 저장하는 배치 시스템입니다.
API 응답 속도가 **30초 → 0.1초**로 300배 빨라집니다!
장 시작 전에 전체 종목을 분석해 `stock_analysis` 테이블에 캐시한다. 대시보드 첫 진입 시 실시간 분석(30초)을 기다리지 않고 DB에서 바로 읽는다.
## 사용 방법
배치는 **선택사항**이다. 실행하지 않아도 첫 진입 시 실시간 분석이 자동 수행되며, 그 경우 10~30초가 걸린다.
### 1. 테스트 실행 (10개 종목만)
```bash
./run-batch.sh --test
```
## 무엇이 언제 도는가
### 2. 일부 종목만 분석 (예: 50개)
```bash
./run-batch.sh --limit 50
```
`setup-cron.sh` 가 등록하는 cron 잡은 **3개**다(모두 평일, `docker exec autostock-backend` 경유).
### 3. 전체 종목 분석 (실제 운영)
```bash
./run-batch.sh
```
| 시각 | 스크립트 | 로그 |
|------|----------|------|
| 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 배치가 토큰 발급부터 시작하면 실패 시 재시도 여유가 없다.
## 수동 실행
컨테이너 밖에서 돌릴 때는 프로젝트 venv 를 쓴다.
```bash
cd backend
python batch_daily_analysis.py
# 테스트 (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
```
## Cron 설정 (자동 실행)
매일 아침 9시에 자동 실행:
컨테이너 안에서:
```bash
# crontab 편집
crontab -e
# 아래 내용 추가 (경로는 실제 경로로 수정)
0 9 * * 1-5 cd /Users/commylife/myproject/java/workspace/auto-stock && ./run-batch.sh >> logs/batch.log 2>&1
docker exec autostock-backend python /app/batch_daily_analysis.py --test
```
## API 사용
인자는 `--test`(10종목)와 `--limit N` 두 개뿐이다.
## 자동 실행
### 빠른 모드 (DB 조회 - 0.1초)
```bash
./setup-cron.sh # 3개 잡 등록 (이미 있으면 건너뜀)
crontab -l | grep batch # 확인
crontab -e # 제거는 해당 라인 삭제
```
`setup-cron.sh` 는 `docker` 명령을 찾지 못하면 중단한다. 컨테이너명은 `autostock-backend` 로 고정되어 있다.
## 로그
```bash
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` 이다.
```bash
# 빠른 조회 (DB 캐시)
GET /api/v1/recommendations/rule-based
```
### 실시간 모드 (KIS API - 30초)
```bash
# 실시간 분석 (느림)
GET /api/v1/recommendations/rule-based?realtime=true
GET /api/v1/recommendations/rule-based/realtime # 분석 후 DB upsert + 반환
```
## 프론트엔드 버튼 추가 예시
프론트엔드는 기본을 DB 조회로 두고, 실시간은 명시적 버튼으로 분리하는 것이 좋다.
```typescript
// 실시간 새로고침 버튼
<button onClick={() => refetch({ realtime: true })}>
🔴 실시간 분석 (30초)
</button>
## `stock_analysis` 주요 컬럼
// 기본은 DB 조회 (빠름)
<button onClick={() => refetch()}>
✅ 빠른 조회 (0.1초)
</button>
`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, ...
```
## 데이터베이스 스키마
## 문제 해결
```sql
CREATE TABLE stock_analysis (
id SERIAL PRIMARY KEY,
stock_code VARCHAR(20),
stock_name VARCHAR(100),
analysis_date DATE,
current_price INTEGER,
rsi NUMERIC(10,4),
ma5 NUMERIC(15,2),
ma20 NUMERIC(15,2),
signals JSONB,
score INTEGER,
...
);
**cron 이 실행되지 않음** (macOS)
```bash
sudo launchctl list | grep cron
```
cron 잡이 `docker exec` 를 쓰므로 Docker Desktop 이 떠 있어야 한다.
## 장점
**"접근토큰 발급 잠시 후 다시 시도하세요" 반복**
토큰 발급 1분 제한에 걸린 것이다. 06:00 프리페치 잡이 등록됐는지 먼저 확인하고, 수동 실행을 연달아 하지 않는다.
⚠️ 로컬에서 배치를 돌릴 때 NAS 와 같은 앱키를 쓰면 **서로 토큰을 무효화**한다. 로컬 실행은 앱키를 분리하거나 피한다.
- ✅ **속도**: 30초 → 0.1초 (300배 빠름)
- ✅ **안정성**: KIS API Rate Limit 회피
- ✅ **편의성**: 사용자가 기다릴 필요 없음
- ✅ **확장성**: 과거 데이터 추적 가능
- ✅ **분석**: 백테스팅, 통계 분석 가능
## 주의사항
- 배치 실행 시간: 약 5-10분 (전체 200개 종목 기준)
- KIS API Rate Limit: 초당 1건 제한
- 데이터는 매일 아침 9시 기준
- 장중 실시간 가격은 `realtime=true` 옵션 사용
**DB 연결 에러**
```bash
docker compose ps
docker compose logs autostock-db --tail 50
```