Files
auto-stock/CLAUDE.md
shuim 5f0f839039 전략 취약점 15건 수정 (코드 리뷰 기반)
## CRITICAL/HIGH (S1-S8)
- S1: Aggressive 모드 %B 스케일링 캡 1.3 (BB 중앙선 위 매수 방지)
- S2: ML scaler train-only fit (데이터 누수 제거)
- S3: SIDEWAYS = ADX<20 AND slope≈0 (트렌드 초기 차단 해소)
- S4: EOD 청산 실패 시 재시도 + CRITICAL 로그
- S5: 일일 손실 한도에 미실현 P&L 포함
- S6: trailing stop 고점 매 사이클 갱신
- S7: 섹터 필터 미매핑 종목 "기타" 분류 (max 3 적용)
- S8: 스캐너 RSI 기준 25→46, BB 점수 -3%~+1.5% 구간

## MEDIUM (M1-M7)
- M1: 스캐너 최소 거래량 100만→10만주
- M2: ADX 히스테리시스 18/22 (국면 플리핑 방지)
- M3: 분할매도 최소 수익 1.0%→0.5%
- M4: ORB 갭 필터 4% + 레인지 폭 0.3% 최소
- M5: 쿨다운 스트릭 부분매도 시 미변경
- M6: MDD 강제매도 loss_tracker 기록 제거 (허위 ban 방지)
- M7: RSI Wilder 스무딩으로 통일

## 인프라/보안
- 인증 누락 엔드포인트 수정 (analysis, journals)
- nginx 보안 헤더 location 블록 누락 수정
- Alembic 마이그레이션 IF NOT EXISTS 가드 추가
- SellRequest/UsOrderRequest 입력 검증 강화
- 차트 네이버 폴백 추가 (DB 데이터 없을 때)
- 서버 이전 시 자동 DB 마이그레이션 + KRX 초기 수집
- CLAUDE.md 섹션 5.1 백테스트 값 동기화 (4%→6%, -6%→-7%)
- MAX_SWING_POSITIONS 25→20 (CLAUDE.md 준수)
- mdd_manager failed_count에서 skip 종목 제외

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:44:14 +09:00

264 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 자동 주식 매매 시스템 — Claude 컨텍스트 가이드
> **핵심 지침 (Core Directive)**: 이 문서는 시스템의 전략, 규칙 및 아키텍처를 정의합니다. 모든 코드 수정 및 분석은 이 가이드라인을 엄격하게 준수해야 합니다.
---
## 1. 프로젝트 개요
### 1.1 기술 스택
- **백엔드**: Python 3.11, FastAPI, SQLAlchemy 2.0 (Async), PostgreSQL 15, Redis 7, RabbitMQ 3
- **프론트엔드**: React 18, TypeScript, Vite, Recharts, Lightweight Charts
- **인프라**: Docker Compose, Nginx, Alembic (DB 마이그레이션)
- **AI 계층**: Claude 3.5 Sonnet / Gemini 2.0 Flash (`.env`의 `AI_PROVIDER`로 전환)
- **ML**: PyTorch, LightGBM, scikit-learn (앙상블 예측)
- **연동 (Integration)**: 한국투자증권(KIS) REST/WebSocket API, MCP Server (stdio)
### 1.2 주요 환경 변수 (`.env`)
- **AI_PROVIDER**: `gemini` 또는 `claude`
- **KIS_MODE**: `virtual` (모의투자) 또는 `real` (실전투자)
- **TOKEN_SAVE_MODE**: `true` (JSON을 압축하고, 차트 데이터를 30일치로 제한함)
- **AUTO_TRADE_ENABLED**: 자동 매매 활성화 여부
- **US_TRADING_ENABLED**: 미국 주식 매매 활성화 여부
---
## 2. 디렉토리 구조
### 2.1 백엔드 (`backend/app/`)
- **API**: `api/endpoints/` — 20개 엔드포인트 모듈 (portfolio, market_data, trades, day_trading, backtest 등)
- **코어 (Core)**: `core/config.py` (전역 설정), `core/database.py`, `core/security.py` (API 키 인증), `core/json_helpers.py`, `core/market_schedule.py`
- **모델 (Models)**: `models/models.py` — SQLAlchemy ORM (Portfolio, TradeHistory, ActiveTrade, StockAnalysis, StockBan 등)
- **실시간 (Realtime)**: `realtime/websocket_client.py`, `realtime/event_handler.py`
- **전략 추상화 (Strategy)**: `strategy/base_strategy.py`, `strategy/strategy_manager.py`
### 2.2 서비스 (`backend/app/services/`)
- **전략 (Strategies)**:
- `mean_reversion_strategy.py` — RSI+BB 평균 회귀 v2 (섹션 6)
- `short_term_strategy.py` — 15분봉 단기 전략 (섹션 7.2)
- `day_trading_strategy.py` — 5분봉 데이트레이딩 ORB/VWAP/RSI_BB (섹션 7.3)
- `kosdaq_scanner.py` — 코스닥 스윙 스캐너 (섹션 7.1)
- `us_stock_strategy.py` — 미국 주식 전략
- **데이트레이딩 모듈 (Modular)**: `daytrading/entry_service.py`, `daytrading/exit_service.py`, `daytrading/position_manager.py`, `daytrading/scheduler.py`
- **스윙 모듈 (Modular)**: `swing/entry_service.py`, `swing/exit_service.py`, `swing/position_manager.py`, `swing/scheduler.py`
- **매매 실행**: `trade_executor.py` — 핵심 매매 엔진 (매수/매도/체결확인/슬리피지)
- **분석 (Analysis)**: `feature_engineering.py`, `ml_ensemble.py`, `tensorflow_predictor.py`, `technical_indicators.py`
- **리스크**: `mdd_manager.py` (MDD 추적 + 자동 축소 실행), `loss_tracker.py` (연속 손실 ban), `correlation_filter.py` (상관관계 필터)
- **아키텍처**: `db_worker.py` (비동기 DB 처리 워커, 재시도 3회)
- **데이터**: `korea_investment_api.py` (KIS REST), `kis_realtime_stream.py` (KIS WebSocket), `naver_finance.py`
- **유틸**: `websocket_manager.py`, `order_dispatcher.py`, `signal_types.py`, `watchlist.py`
### 2.3 MCP (`mcp-server/`)
- `stdio_server.py`, `auto_trade_claude.py`, `claude_client.py`, `gemini_client.py`, `trade_monitor.py`, `risk_validator.py`, `mcp_tools.py`
### 2.4 배치 스크립트 (`backend/`)
- `batch_daily_analysis.py` — 일일 분석 배치
- `batch_intraday_analysis.py` — 장중 분석 배치
- `train_ensemble.py` — ML 모델 학습
- `collect_krx_data.py` — KRX 데이터 수집
---
## 3. 아키텍처 원칙 (필수 준수 사항)
### 3.1 관심사 분리 (Separation of Concerns)
- **실시간 계층 (Real-time Layer)**: API 콜백, 웹소켓 브로드캐스트 및 메모리 캐싱을 처리합니다. **DB I/O(데이터베이스 입출력)는 절대 허용되지 않습니다.**
- **영속성 계층 (Persistence Layer)**: 백그라운드 워커를 통해 DB INSERT/UPDATE 작업을 처리합니다.
- **예외**: `sync_portfolio()`는 SELECT→UPDATE/DELETE→commit이 같은 트랜잭션에서 이뤄져야 하므로 API 엔드포인트 경로에서 직접 DB 접근을 허용합니다.
### 3.2 비동기 DB 워커 규칙
- **직접적인 DB 접근 금지**: API 콜백이나 실시간 스케줄러 내부에서 `AsyncSessionLocal()` 또는 `commit()`을 절대 호출하지 마십시오.
- **큐(Queue) 사용**: 모든 데이터 저장(매매 내역, 분석 결과 등)은 `db_worker.py`의 `db_task_queue`로 보내야 합니다.
- **워커 (Worker)**: 백그라운드 워커가 큐를 처리하고 안전한 DB 트랜잭션을 순차적으로 수행합니다.
- **재시도**: 실패한 task는 최대 3회까지 지수 백오프(1→2→4초)로 재시도합니다.
- **지원 task 타입**: `insert_trade_history`, `update_trade_history`, `update_trade_history_by_order_id`, `upsert_stock_analysis`, `bulk_upsert_stock_analysis`, `upsert_stock_ban`, `upsert_portfolio`, `upsert_active_trade`, `close_active_trade`, `insert_trade_journal`, `log_mcp_deny`
### 3.3 동시성 안전
- **종목별 세마포어**: `trade_executor.py`의 `_order_semaphores`로 동일 종목 동시 주문 방지.
- **Redis 분산 락**: 여러 워커 프로세스간 동일 종목 동시 매도 방지.
- **loss_tracker 락**: `asyncio.Lock`으로 `_tracker` 딕셔너리 보호. 동시 접근 경로에서는 `is_banned_safe()`, `record_trade_result_safe()` 사용.
- **MDD 매니저 락**: `asyncio.Lock`으로 MDD 업데이트 및 축소 실행 보호.
---
## 4. 코딩 가이드라인
### 4.1 안정성
- **기존 코드 파괴 금지 (No Breaking Changes)**: 기존 함수나 클래스의 시그니처를 절대 변경하지 마십시오.
- **버전 관리**: 새로운 전략 구현 시 `_v2`, `_v3` 등의 접미사를 사용하십시오.
- **안전 래퍼**: 기존 동기 API를 비동기로 확장할 때 `_safe` 접미사의 새 메서드를 추가하십시오 (예: `is_banned_safe()`).
### 4.2 최적화
- **JSON 처리**: `json.dumps` 대신 항상 `core.json_helpers._dumps()`를 사용하십시오.
- **프롬프트 엔지니어링**: 토큰 사용을 최소화하고 컴팩트한 포맷을 사용하십시오.
### 4.3 보안
- **API 인증**: 쓰기/삭제 엔드포인트에는 반드시 `Depends(require_api_key)`를 적용하십시오.
- **SSL 검증**: 외부 API 호출 시 `verify=True` 유지 (KIS API 포함).
- **비밀키**: `.env`의 `SECRET_KEY`는 64자 이상 랜덤 문자열 사용.
---
## 5. 리스크 관리 규칙
### 5.1 포지션 사이징 (Position Sizing)
- **최대 비중**: 종목당 총 자본의 **6%** (`config.py: MAX_POSITION_SIZE = 0.06`, 백테스트 검증 반영).
- **최대 보유 종목 수**: **20개** (`config.py: MAX_HOLDINGS_COUNT = 20`).
- **레버리지**: 인버스/레버리지 ETF의 경우 총 자본의 최대 **20%**로 제한 (`config.py: LEVERAGE_ETF_MAX_RATIO = 0.20`).
### 5.2 손절(SL) 및 익절(TP) — 일봉/스윙 기준
- **기본 손절 (SL Base)**: -7% (안정적 종목), -10% (변동성 종목). (백테스트 검증: 기존 -6% → -7%)
- **ATR 손절**: `진입가 - (2.5 * ATR)` (`config.py: ATR_STOP_MULTIPLIER = 2.5`). **기본 손절과 ATR 손절 중 타이트한(더 작은) 쪽 적용** — 코드에서 `min(stop_loss, atr_stop_pct)` 사용.
- **익절 (TP)**: +2R 수익(리스크 대비 2배 수익) 도달 시 50% 분할 매도.
- **트레일링 스탑 (Trailing Stop)**: 나머지 50% 물량에 대해 `고점 - (1.5 * ATR)` 적용.
### 5.3 MDD(최대 낙폭) 관리
- **MDD -10%**: 신규 진입을 중단합니다. 포지션 규모를 30% 축소합니다. **단기 매매 전략 및 데이트레이딩을 중단합니다.** (`mdd_manager.py: REDUCE_AND_PAUSE`)
- **MDD -20%**: 모든 포지션을 강제로 50% 축소합니다. 레버리지/인버스 ETF부터 우선 청산합니다. (`mdd_manager.py: FORCE_REDUCE`)
- **자동 실행**: `mdd_manager.execute_reduction()`이 `portfolio.py`와 `swing/scheduler.py`에서 자동 호출됩니다. 중복 실행 방지 플래그가 내장되어 있습니다.
- **복구**: 잔고가 peak를 갱신하면 모든 MDD 플래그가 리셋됩니다.
### 5.4 필터 (Filters)
- **가격**: 5,000원 초과 (국내), $4 초과 (미국). (예외: ETF, 리츠). (`config.py: MIN_PRICE_KRW = 5000, MIN_PRICE_USD = 4.0`)
- **상관관계 (Correlation)**: 섹터당 최대 3종목 (`correlation_filter.py: max_per_sector = 3`). 기존 포트폴리오와의 상관계수가 0.7을 초과하면 진입을 거부합니다.
### 5.5 연속 손실 관리
- 동일 종목에서 **3회 연속 손실 시 42캘린더일(≈30거래일) 진입 금지** (`loss_tracker.py`).
- DB 영속화: `save_to_db()` → `db_worker`의 `upsert_stock_ban` 경유.
- 앱 재시작 시 `load_from_db()`로 ban 상태 복원.
---
## 6. 전략 A: RSI + 볼린저 밴드 평균 회귀 v2
> **구현 파일**: `mean_reversion_strategy.py`, `swing/` 모듈
> **자산 배분**: 스윙 포트폴리오 (코스닥 스캐너 25% 외 나머지)
### 6.1 시장 국면 (일봉 기준)
- **상승장 (BULL)**: 코스피200 > 200일 이동평균선(MA200) AND MA200 기울기 > 0.
- **하락장 (BEAR)**: 코스피200 < MA200 AND MA200 기울기 < 0.
- **횡보장 (SIDEWAYS)**: ADX < 20 OR 기울기 ≈ 0. **(이 국면에서는 모든 진입 신호를 무시합니다)**
- `market_analyzer.py`에서 `position_multiplier=0.0`, `max_trades=0` 반환.
### 6.2 진입 조건
- **상승장**: RSI(14) < 40 (기본값, `.env`에서 `MEAN_REVERSION_RSI_THRESHOLD`로 조정 가능), 가격이 볼린저 밴드(BB) 하단 부근 (-3% ~ +1.5%), 거래량 > 20일 평균 거래량(20MA).
- **하락장**: RSI(14) < 30, 가격 < 볼린저 밴드 하단, 거래량 > 1.5배 × 20MA, 반전 캔들(Reversal candle) 필수.
- **선제 진입 (Pre-emptive)**: 일봉 RSI < 40 AND 60분봉 RSI < 30 AND 5일 이동평균선(MA5) 상향 돌파.
### 6.3 청산 조건
- **부분 매도 (50%)**: RSI >= 50 OR 가격 > 볼린저 밴드 중앙선 OR 수익 > 2×ATR.
- **전량 매도**: RSI >= 65 OR 가격 > 볼린저 밴드 상단 (99%) OR 트레일링 스탑 도달 (`고점 - 1.5×ATR`).
---
## 7. 전략 B: 공격적 성장 (Aggressive Growth)
### 7.1 코스닥 스캐너 (스윙 매매)
> **구현 파일**: `kosdaq_scanner.py`
- **대상 (Scope)**: 코스닥 전 종목 (약 1,600개).
- **필터 (Filter)**: 가격 > 5,000원, 거래량 상위 20%.
- **점수 (Score)**: `0.5×RSI_score + 0.3×BB_score + 0.2×Vol_score`. 최소 점수 0.15 이상인 종목 중 상위 20개 선정.
- **자산 배분 (Allocation)**: 전체 자본의 25%.
### 7.2 단기 전략 (15분봉)
> **구현 파일**: `short_term_strategy.py`
- **타겟 (Target)**: 일봉 RSI < 40 인 종목.
- **진입 (Entry)**: 15분봉 RSI < 30, 가격이 볼린저 밴드 하단 부근, 종가 > MA5 (상향 돌파 확인), 거래량 > 1.3배 × 20MA (`config.py: SHORT_TERM_VOLUME_MULTIPLIER = 1.3`).
- **최소 변동성**: ATR/close ≥ 0.8% (`config.py: SHORT_TERM_MIN_ATR_RATIO = 0.008`) — 거래비용 커버 보장.
- **청산 (Exit)**: 15분봉 RSI > 55 OR 수익 > 1.5 × ATR(15분봉).
- **손절 (SL)**: `진입가 - 1.0 × ATR(15분봉)` 또는 `-2% 하드 스탑` 중 **타이트한(더 높은 stop_price) 쪽** — 코드에서 `min(atr_stop, hard_stop)` 사용. *(15분봉 단기전략 전용 — 섹션 5.2 ATR 2.5×는 일봉/스윙 기준)*
- **자산 배분 (Allocation)**: 전체 자본의 최대 25%. **MDD가 -10% 미만이면 비활성화합니다.**
### 7.3 데이트레이딩 (5분봉, ORB/VWAP/RSI_BB)
> **구현 파일**: `day_trading_strategy.py`, `daytrading/` 모듈
#### 전략 3종
| 전략 | 진입 조건 | 손절 기준 |
|------|----------|----------|
| **ORB** | 시초가 레인지 돌파 + 거래량 ≥ 1.5× 평균분당거래량 + 직전 5분봉 양봉 | `max(ORB 저점, 현재가×(1-ORB_SL%))` + ATR 하한, 상한 -2.5% 클램프 |
| **VWAP** | VWAP 지지 반등 + RSI(14) < 40 + 거래량 ≥ 1.3× + 양봉 | `min(ATR×1.5 기반, 하드스탑 -2.5%)` + 최소 1원 보장 |
| **RSI_BB** | RSI(14) ≤ 30 + 종가 ≤ BB 하단 + 거래량 ≥ 1.3× + 양봉 | `min(ATR×1.5 기반, 하드스탑 -2.5%)` + 최소 1원 보장 |
#### 포지션 사이징
- 종목당 최대 4% (섹션 5.1 준수, `config.py: DAY_TRADE_MAX_CAPITAL_RATIO = 0.04`).
- 동시 최대 3종목 (`config.py: DAY_TRADE_MAX_POSITIONS = 3`).
- confidence 기반 동적 조정: `예산 × (signal.confidence / 0.7)`.
#### 자산 배분
- 전체 자본의 최대 25% (`config.py: DAY_TRADE_MAX_RATIO_DT = 0.25`).
#### 청산 규칙
- **분할 매도**: 목표가(+2R) 달성 시 50% 분할 매도, 잔량은 트레일링 스탑(ATR × 1.0) 적용.
- **시간 손절**: 진입 후 30분(6봉)간 +0.3% 미달 시 청산 (기회비용 관리).
- **과매수 청산**: 5분봉 RSI ≥ 70 AND 수수료 이상 수익 시 청산.
- **EOD 강제 청산**: 15:20 이후 전량 청산 (`config.py: DAY_TRADE_EOD_FLAT_HOUR/MIN`).
#### 필터 및 제한
- **시장 국면**: SIDEWAYS 국면에서 진입 차단 (섹션 6.1 준수).
- **시간대 제한**: 점심시간(11:30~13:00) VWAP/RSI_BB 진입 제한, **14:30 이후 신규 진입 마감**.
- **일일 손실 한도**: -3% 초과 시 당일 신규 진입 중단 (`config.py: DAY_TRADE_DAILY_LOSS_LIMIT = -0.03`).
- **쿨다운**: 당일 3연패 시 신규 진입 차단 (`daytrading/position_manager.py`).
- **loss_tracker 연동**: 전량 매도 시 `loss_tracker.record_trade_result()` + `save_to_db()` 호출.
- **MDD -10% 미만이면 비활성화합니다.**
---
## 8. Claude에 대한 지침
### 8.1 주요 점검 사항 (Critical Checkpoints)
1. **아키텍처**: 모든 DB 쓰기 작업이 `db_worker.py`를 사용하는지 확인하십시오. 예외: `sync_portfolio()`.
2. **안전성 (Safety)**: 모든 매매에 리스크 규칙(섹션 5)을 항상 적용하십시오.
3. **시장 국면 (Regime)**: 횡보장(SIDEWAYS) 국면에서는 진입을 제안하지 마십시오.
4. **테스트**: 백테스트 및 전진 분석(Walk-forward validation) 없이는 실전 투자를 하지 마십시오.
5. **손절 방향**: 손절가 선택 시 항상 `min()` (타이트한 쪽)을 사용하십시오. `max()`는 절대 사용하지 마십시오.
6. **loss_tracker 영속화**: `record_trade_result()` 호출 후 반드시 `save_to_db()` 호출을 확인하십시오.
7. **인증**: 쓰기/삭제 API에는 반드시 `require_api_key` 의존성을 적용하십시오.
### 8.2 응답 형식 (Response Format)
- JSON 출력 시 `_dumps()`를 사용하십시오.
- 새로운 기능 개발 시 새 파일을 생성하십시오.
- 기존 시그니처를 수정하지 마십시오.
### 8.3 주요 설정값 참조 (`config.py`) — 백테스트 검증 완료
| 설정 | 값 | 설명 | 백테스트 변경 |
|------|---|------|------------|
| `MAX_POSITION_SIZE` | 0.06 | 종목당 최대 6% | 기존 0.04 → 0.06 |
| `MAX_HOLDINGS_COUNT` | 20 | 동시 보유 최대 | 유지 |
| `LEVERAGE_ETF_MAX_RATIO` | 0.20 | 레버리지 ETF 최대 | 유지 |
| `ATR_STOP_MULTIPLIER` | 2.5 | 스윙 ATR 손절 배수 | 유지 |
| `STOP_LOSS_PERCENT` | 7.0 | 기본 손절 7% | 기존 6.0 → 7.0 |
| `MEAN_REVERSION_RSI_THRESHOLD` | 46.0 | 평균회귀 RSI 임계값 | 기존 40.0 → 46.0 |
| `MEAN_REVERSION_BEAR_RSI_THRESHOLD` | 35.0 | BEAR RSI 임계값 | 기존 30.0 → 35.0 |
| `MEAN_REVERSION_RSI_EXIT_THRESHOLD` | 55.0 | 1차 익절 RSI | 기존 50.0 → 55.0 |
| `MEAN_REVERSION_RSI_FULL_EXIT` | 70.0 | 전량 청산 RSI | 기존 65.0 → 70.0 |
| `DAY_TRADE_MAX_POSITIONS` | 3 | 데이트레이딩 동시 최대 | 유지 |
| `DAY_TRADE_ENTRY_CUTOFF` | 14:30 | 데이트레이딩 마감 | 기존 15:00 → 14:30 |
| `CONSECUTIVE_LOSS_BAN_COUNT` | 3 | 연속 손실 ban 횟수 | 유지 |
### 8.4 듀얼 전략 (백테스트 검증: 2023-03 ~ 2026-03)
스윙 전략은 3가지 진입 전략을 병행합니다:
| 전략 | 조건 | 청산 방식 | 기여도 |
|------|------|----------|--------|
| **평균회귀** | RSI 과매도 + BB 하단 | RSI 55 부분익절 → RSI 70 전량 | 베이스 수익 |
| **모멘텀 돌파** | 20일 신고가 + 거래량 2x + RSI 50~70 | +10% 30%매도 → +20% 30%매도 → 트레일링 | 큰 이익 |
| **눌림목 매수** | MA20>MA60 + MA20 근처 조정 + RSI 반등 | 평균회귀와 동일 | 안정 수익 |
### 8.5 적응형 모드 (4단계)
시장 상황에 따라 파라미터가 자동 전환됩니다 (`adaptive_strategy.py`):
| 모드 | RSI 진입 | 포지션 | 손절 | 트리거 |
|------|---------|--------|------|--------|
| **Aggressive** | 50 | 7% | -9% | ATR백분위<30 + ADX>25 + 5일수익>+2% |
| **Normal** | 46 | 6% | -7% | 기본 |
| **Defensive** | 38 | 4% | -6% | ATR백분위>70 또는 5일수익<-3% |
| **Crisis** | 25 | 1.5% | -3% | ATR백분위>90 또는 5일수익<-5% |
*마지막 업데이트: 2026-03-25 (백테스트 검증 반영)*