Files
auto-stock/CLAUDE.md
shuim b4a1fc79ab feat: 멀티테넌트 1단계 — 사용자별 KIS 계좌·포트폴리오·수동매매 (MULTI_TENANT_ENABLED 기본 OFF)
설계: docs/multi_tenant_design.md / 검수: docs/multi_tenant_phase1_review.md (High 0, MT=False 배포 가능)

데이터·인프라
- user_kis_credentials(Fernet 암호화, PBKDF2 키 파생, key_version), stock_bans_v2 신설,
  portfolio/trade_history/active_trades/trade_journals/trading_sessions 등 user_id nullable 추가
- alembic 0009~0011(idempotent, legacy owner 백필). main.py 기동 시 portfolio.user_id 스키마 검사(H1)
- Jenkinsfile: DB Migration 을 Deploy 앞으로, alembic 이력 없으면 stamp 0008 후 upgrade(N1)
- bootstrap: users 비어 있으면 BOOTSTRAP_ADMIN_* 로 관리자 시드 + .env KIS 자격증명 이관 + 백필(SAVEPOINT)

백엔드
- core/crypto.py, core/tenant_auth.py(get_current_user — 비활성 사용자 401, API 키→legacy owner,
  deny_non_owner_session_when_mt), core/dt_utils.py
- services/tenant: context, kis_pool, registry(UserContextRegistry, 락 최소화·복호화 to_thread), risk_factory
- KoreaInvestmentAPI.for_user(사용자별 인스턴스, 토큰캐시 users/{id}/, 시세는 공용 위임)
- trade_executor.safe_place_order_v2(사용자별 락/세마포어, legacy ctx 는 기존 키)
- mdd_manager/loss_tracker _v2 + ban_until tz-aware/naive 경계 정규화(레거시 경로 버그 포함 수정)
- db_worker: payload user_id 옵션 필터, upsert_stock_ban_v2, legacy ActiveTrade 조회 LIMIT 1
- API: /account/credentials(등록·마스킹조회·삭제·연결테스트·자동매매), /auth/admin/tenant/*,
  /portfolio/v2(조회·요약·sync·buy·sell), /trades/v2(+pending). PortfolioResponse Optional 수정

프론트
- /account 내 계좌 설정, useTenantMode(세션=v2 / API키=legacy, 미확정 시 쿼리·버튼 비활성),
  계좌 미등록 인라인 안내, v2 매수/매도/거래이력 분기

테스트: tests/integration(격리 Postgres, KIS 전면 mock) 20 passed / 1 xfailed(0012 이전 제약)
2단계(스케줄러 사용자화·legacy 라우터 격리) 전까지 MULTI_TENANT_ENABLED=True 전환 금지

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 10:26:51 +09:00

124 lines
9.8 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 가이드
> 모든 코드 수정·분석은 이 문서의 규칙을 엄격히 준수할 것.
## 1. 스택 & 환경
- **백엔드**: Python 3.11 / FastAPI / SQLAlchemy 2.0(Async) / PostgreSQL 15 / Redis 7 / RabbitMQ 3
- **프론트**: React 18 / TypeScript / Vite / Recharts / Lightweight Charts
- **인프라·ML**: Docker Compose, Nginx, Alembic / PyTorch, LightGBM, scikit-learn
- **연동**: 한국투자증권(KIS) REST·WebSocket, MCP 서버(stdio) / AI 계층: `AI_PROVIDER`=claude|gemini
- **주요 .env**: `KIS_MODE`(virtual|real), `TOKEN_SAVE_MODE`(JSON 압축+차트 30일 제한), `AUTO_TRADE_ENABLED`, `US_TRADING_ENABLED`
- **배포**: 코드 수정 후 `docker compose up -d --build`(옛 이미지 재사용 방지) — **스키마(모델) 변경 시 반드시 `alembic upgrade head`를 이미지 기동보다 먼저 실행**(`create_all`은 기존 테이블에 컬럼을 추가하지 않음, H1).
## 2. 구조 (`backend/app/`)
- `api/endpoints/` — 20개 모듈 (portfolio, market_data, trades, day_trading, backtest 등)
- `core/` — config(설정), database, security(require_api_key), json_helpers(_dumps), market_schedule
- `models/models.py` — Portfolio, TradeHistory, ActiveTrade, StockAnalysis, StockBan 등
- `realtime/` — websocket_client, event_handler / `strategy/` — base_strategy, strategy_manager
- `services/` 전략: mean_reversion_strategy(§6), short_term_strategy(§7.2), day_trading_strategy(§7.3), kosdaq_scanner(§7.1), us_stock_strategy
- `services/daytrading/`·`services/swing/` — entry_service, exit_service, position_manager, scheduler
- `services/` 핵심: trade_executor(매매엔진: 매수/매도/체결확인/슬리피지), db_worker(비동기 DB워커), mdd_manager·loss_tracker·correlation_filter(리스크), korea_investment_api·kis_realtime_stream·naver_finance(데이터), feature_engineering·ml_ensemble·technical_indicators(분석)
- `mcp-server/` — stdio_server, auto_trade_claude, claude_client, gemini_client, trade_monitor, risk_validator, mcp_tools
- 배치(`backend/`) — batch_daily_analysis, batch_intraday_analysis, train_ensemble, collect_krx_data
## 3. 아키텍처 원칙 (필수)
1. **실시간 계층 DB I/O 절대 금지** — API 콜백·웹소켓·실시간 스케줄러에서 `AsyncSessionLocal()`/`commit()` 호출 금지.
2. **모든 DB 쓰기는 `db_worker.py`의 `db_task_queue` 경유** (실패 시 지수 백오프 1→2→4초, 최대 3회 재시도). 예외: `sync_portfolio()`만 단일 트랜잭션 필요로 엔드포인트 직접 DB 접근 허용. auth/credentials/bootstrap 시드(회원가입·로그인, `user_kis_credentials` 등록/삭제, 앱 기동 시 관리자·자격증명 시드)도 단일 트랜잭션 직접 접근 허용 — 실시간 계층(콜백·스케줄러) 아님.
3. 지원 task: insert_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
4. **동시성**: trade_executor `_order_semaphores`(종목별 동시 주문 방지) / Redis 분산 락(워커 간 동시 매도 방지) / loss_tracker·mdd_manager `asyncio.Lock`. 동시 접근 경로에서는 `is_banned_safe()`, `record_trade_result_safe()` 사용.
## 4. 코딩 규칙
- **기존 함수/클래스 시그니처 변경 금지** → 새 전략은 `_v2`/`_v3`, 동기→비동기 확장은 `_safe` 접미사의 새 메서드.
- JSON은 `json.dumps` 금지, `core.json_helpers._dumps()` 사용.
- 쓰기/삭제 엔드포인트에 `Depends(require_api_key)` 필수. 외부 API 호출 `verify=True` 유지(KIS 포함). `SECRET_KEY` 64자+ 랜덤.
- 프롬프트는 토큰 최소화, 컴팩트 포맷.
## 5. 리스크 규칙
### 5.1 사이징·필터
- 종목당 최대 **6%** (`MAX_POSITION_SIZE=0.06`), 최대 **20종목**(`MAX_HOLDINGS_COUNT`), 레버리지/인버스 ETF 최대 **20%**(`LEVERAGE_ETF_MAX_RATIO`).
- 가격 필터: 국내 >5,000원, 미국 >$4 (ETF·리츠 예외) (`MIN_PRICE_KRW`, `MIN_PRICE_USD`).
- 상관관계: 섹터당 최대 3종목, 기존 포트폴리오와 상관계수 >0.7 진입 거부 (`correlation_filter`).
- 연속 손실: 동일 종목 **3연패 → 42캘린더일(≈30거래일) 진입 금지** (`loss_tracker`). `record_trade_result()` 후 반드시 `save_to_db()`(db_worker upsert_stock_ban 경유). 재시작 시 `load_from_db()` 복원.
### 5.2 SL/TP (일봉/스윙)
- 기본 SL: **-7%**(안정) / -10%(변동성). ATR SL: `진입가 − 2.5×ATR` (`ATR_STOP_MULTIPLIER=2.5`).
- **SL은 기본/ATR 중 타이트한 쪽 — 항상 `min()`, `max()` 금지.**
- TP: +2R 도달 시 50% 분할 매도, 잔량 트레일링 스탑 `고점 − 1.5×ATR`.
### 5.3 MDD (mdd_manager — portfolio.py·swing/scheduler.py에서 자동 호출, 중복 실행 방지 내장)
- **-10%**: 신규 진입 중단 + 포지션 30% 축소 + 단기·데이트레이딩 중단 (REDUCE_AND_PAUSE)
- **-20%**: 전 포지션 50% 강제 축소, 레버리지/인버스 ETF 우선 청산 (FORCE_REDUCE)
- 잔고가 peak 갱신 시 모든 MDD 플래그 리셋.
## 6. 전략 A: RSI+BB 평균 회귀 v2 (`mean_reversion_strategy`, `swing/`) — 스윙 자본 75%
- **시장 국면(일봉)**: BULL = 코스피200>MA200 & MA200 기울기>0 / BEAR = 코스피200<MA200 & 기울기<0 / **SIDEWAYS = ADX<20 or 기울기≈0 → 모든 진입 무시** (market_analyzer: position_multiplier=0, max_trades=0)
- **진입** (RSI 임계값은 §8.3 config 참조): BULL: RSI(14)<46 + BB하단 부근(-3%~+1.5%) + 거래량>20MA / BEAR: RSI<35 + 가격<BB하단 + 거래량>1.5×20MA + 반전캔들 필수 / 선제: 일봉 RSI<46 & 60분봉 RSI<30 & MA5 상향돌파
- **청산**: 50% 부분매도: RSI≥55 or 가격>BB중앙 or 수익>2×ATR / 전량: RSI≥70 or 가격>BB상단(99%) or 트레일링(고점−1.5×ATR)
## 7. 전략 B: 공격적 성장
### 7.1 코스닥 스캐너 (`kosdaq_scanner`) — 자본 25%
코스닥 전 종목(~1,600) / 가격>5,000원 + 거래량 상위 20% / 점수 = `0.5×RSI + 0.3×BB + 0.2×Vol`, ≥0.15 중 상위 20개 선정.
### 7.2 단기 15분봉 (`short_term_strategy`) — 자본 최대 25%, **MDD -10% 시 비활성**
- 타겟: 일봉 RSI<40 / 진입: 15분 RSI<30 + BB하단 부근 + 종가>MA5(상향돌파) + 거래량>1.3×20MA(`SHORT_TERM_VOLUME_MULTIPLIER`) + ATR/close≥0.8%(`SHORT_TERM_MIN_ATR_RATIO`, 거래비용 커버)
- 청산: 15분 RSI>55 or 수익>1.5×ATR(15분) / SL: `min(진입가−1.0×ATR, -2% 하드스탑)` — 타이트한(stop가 높은) 쪽. *§5.2 ATR 2.5×는 일봉/스윙 전용*
### 7.3 데이트레이딩 5분봉 (`day_trading_strategy`, `daytrading/`) — 자본 최대 25%(`DAY_TRADE_MAX_RATIO_DT`), **MDD -10% 시 비활성**
| 전략 | 진입 | SL |
|------|------|-----|
| 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≤30 + 종가≤BB하단 + 거래량≥1.3× + 양봉 | `min(ATR×1.5, -2.5% 하드)` + 최소 1원 |
- 사이징: 종목당 4%(`DAY_TRADE_MAX_CAPITAL_RATIO`), 동시 3종목(`DAY_TRADE_MAX_POSITIONS`), confidence 조정 `예산×(confidence/0.7)`
- 청산: +2R 시 50% 분할→잔량 트레일링(ATR×1.0) / 진입 30분(6봉)간 +0.3% 미달 시 시간손절 / 5분 RSI≥70 & 수수료 이상 수익 시 / **15:20 EOD 전량 청산**(`DAY_TRADE_EOD_FLAT_*`)
- 제한: SIDEWAYS 진입 차단 / 점심(11:30~13:00) VWAP·RSI_BB 제한 / **14:30 이후 신규 마감** / 일일 -3% 손실 시 당일 중단(`DAY_TRADE_DAILY_LOSS_LIMIT`) / 당일 3연패 쿨다운(position_manager) / 전량 매도 시 loss_tracker 기록 + `save_to_db()`
## 8. Claude 지침
### 8.1 체크포인트
1. DB 쓰기 = db_worker 경유 (예외: sync_portfolio)
2. 모든 매매에 §5 리스크 규칙 적용
3. SIDEWAYS 국면 진입 제안 금지
4. 백테스트·Walk-forward 없이 실전 투입 금지
5. **SL 선택 = 항상 `min()`(타이트한 쪽). `max()` 절대 금지**
6. `record_trade_result()` 후 `save_to_db()` 호출 확인
7. 쓰기/삭제 API에 `require_api_key` 필수
8. JSON 출력 시 `_dumps()` / 새 기능은 새 파일 / 기존 시그니처 수정 금지
### 8.2 config.py 주요값 (백테스트 검증 2023-03~2026-03 완료)
| 설정 | 값 | 비고 |
|------|-----|------|
| `MAX_POSITION_SIZE` | 0.06 | 0.04→0.06 |
| `MAX_HOLDINGS_COUNT` | 20 | |
| `LEVERAGE_ETF_MAX_RATIO` | 0.20 | |
| `ATR_STOP_MULTIPLIER` | 2.5 | 스윙 ATR SL 배수 |
| `STOP_LOSS_PERCENT` | 7.0 | 6.0→7.0 |
| `MEAN_REVERSION_RSI_THRESHOLD` | 46.0 | 40→46 |
| `MEAN_REVERSION_BEAR_RSI_THRESHOLD` | 35.0 | 30→35 |
| `MEAN_REVERSION_RSI_EXIT_THRESHOLD` | 55.0 | 1차 익절, 50→55 |
| `MEAN_REVERSION_RSI_FULL_EXIT` | 70.0 | 전량 청산, 65→70 |
| `DAY_TRADE_MAX_POSITIONS` | 3 | |
| `DAY_TRADE_ENTRY_CUTOFF` | 14:30 | 15:00→14:30 |
| `CONSECUTIVE_LOSS_BAN_COUNT` | 3 | |
### 8.3 스윙 듀얼 전략 (3종 병행)
| 전략 | 진입 | 청산 |
|------|------|------|
| 평균회귀 | RSI 과매도 + BB하단 | RSI 55 부분 → RSI 70 전량 |
| 모멘텀 돌파 | 20일 신고가 + 거래량 2× + RSI 50~70 | +10% 30%매도 → +20% 30%매도 → 트레일링 |
| 눌림목 매수 | MA20>MA60 + MA20 근처 조정 + RSI 반등 | 평균회귀와 동일 |
### 8.4 적응형 모드 (`adaptive_strategy.py` 자동 전환)
| 모드 | RSI 진입 | 포지션 | SL | 트리거 |
|------|---------|--------|-----|--------|
| Aggressive | 50 | 7% | -9% | ATR백분위<30 + ADX>25 + 5일수익>+2% |
| Normal | 46 | 6% | -7% | 기본 |
| Defensive | 38 | 4% | -6% | ATR백분위>70 or 5일수익<-3% |
| Crisis | 25 | 1.5% | -3% | ATR백분위>90 or 5일수익<-5% |
*마지막 업데이트: 2026-09-06 (문서 압축 최적화, 규칙 변경 없음)*