Files
ai-trade/signal_v1/CLAUDE.md
gahusb 7ea1a21487 refactor: web-ai V1 assets → signal_v1/ (graduation prep)
Atomic mv of root V1 assets (main_server.py + modules/ + data/ +
tests/ + entry scripts + docs + logs) into signal_v1/ subdirectory.
load_dotenv() updated to load web-ai/.env explicitly via Path.

Adds web-ai/CLAUDE.md (workspace guide) and web-ai/start.bat
(signal_v1 entry wrapper). Prepares for signal_v2/ Phase 2.

Tests: signal_v1/tests/unit baseline preserved (no regression).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 03:00:11 +09:00

697 lines
31 KiB
Markdown
Raw Permalink 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.
# 🤖 AI Trading Bot — 프로젝트 설계 문서 (CLAUDE.md)
> **최종 갱신**: 2026-03-19
> **런타임**: Windows (Python 3.x, PyTorch CUDA, FastAPI, Ollama)
> **하드웨어**: AMD 9800X3D + RTX 5070 Ti (16 GB VRAM)
---
## 1. 시스템 아키텍처 개요
```
┌──────────────────────────────────────────────────────────────────┐
│ main_server.py │
│ FastAPI (uvicorn, port 8000) — 프로세스 매니저 & REST API 서버 │
│ ┌──────────────┐ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ Trading Bot │ │ Telegram Bot │ │ ProcessWatchdog │ │
│ │ (Process #1) │ │ (Process #2) │ │ (Daemon Thread) │ │
│ └──────┬───────┘ └────────┬────────┘ └──────────┬───────────┘ │
│ │ │ │ │
│ └─── Shared Memory (IPC) ───┘ Health Check / Restart │
│ + Command Queue │
└──────────────────────────────────────────────────────────────────┘
```
### 1.1 멀티 프로세스 구성
| 프로세스 | 역할 | 진입점 |
|---------|------|--------|
| **Main Server (Uvicorn)** | FastAPI REST API 서버, 프로세스 오케스트레이터 | `main_server.py` |
| **Trading Bot** | 자동매매 메인 루프 (스케줄러, 분석, 주문) | `modules/bot.py``AutoTradingBot.loop()` |
| **Telegram Bot** | 사용자 인터랙션 (명령어 처리, 알림) | `modules/services/telegram_bot/runner.py` |
| **ProcessWatchdog** | 자식 프로세스 헬스체크 & 자동 재시작 (30초 간격) | `modules/utils/process_tracker.py` |
### 1.2 프로세스 간 통신 (IPC)
```
┌─────────────┐ SharedMemory (128KB) ┌──────────────┐
│ Trading Bot │ ─── write_status() ───────► │ Telegram Bot │
│ │ ◄── read_status() ──────── │ │
│ │ │ │
│ │ multiprocessing.Queue │ │
│ │ ◄── send_command() ──────── │ │
│ │ (텔레그램 → 봇 명령) │ │
└─────────────┘ └──────────────┘
```
- **SharedMemory** (`web_ai_bot_ipc`, 128KB): 메인 봇이 상태 데이터(잔고, GPU, 매크로 지표 등)를 JSON으로 기록, 텔레그램 봇이 읽기
- **Command Queue** (`multiprocessing.Queue`): 텔레그램 → 메인 봇 양방향 명령 채널 (`restart`, `evaluate` 등)
- **Lock** (`multiprocessing.Lock`): SharedMemory 동시 접근 보호
- **IPC Staleness**: 600초 (10분 이상 오래된 데이터는 무시)
### 1.3 서버 생명주기 (Lifespan)
```python
# main_server.py > lifespan()
1. Config.validate() # 환경변수 검증
2. ProcessTracker.check_and_kill_zombies() # 좀비 프로세스 정리
3. 전역 객체 초기화 (OllamaManager, KISClient, NewsCollector)
4. Shared Resources 생성 (Lock, Queue, Event)
5. Trading Bot 프로세스 생성 & 시작
6. Telegram Bot 프로세스 생성 & 시작
7. ProcessWatchdog 시작 (30 간격 헬스체크)
8. yield (서버 정상 운영)
9. [종료] shutdown_event 설정 자식 종료 SharedMemory 해제
```
---
## 2. 디렉토리 구조
```
web-ai/
├── main_server.py # [Entry Point] FastAPI + 프로세스 매니저
├── warmup_and_restart.py # LSTM 사전학습 + 봇 자동 시작 스크립트
├── watchlist_manager.py # 뉴스 기반 일일 Watchlist 자동 업데이트
├── backtester.py # 전략 백테스팅 CLI
├── theme_manager.py # 종목별 테마/섹터 관리
├── .env # 환경변수 (KIS, Telegram, Ollama 등)
├── modules/
│ ├── __init__.py
│ ├── config.py # [Config] 환경변수 & 상수 정의
│ ├── bot.py # [Core] AutoTradingBot (상태 머신 & 스케줄러)
│ │
│ ├── analysis/ # [AI Brain] 분석 엔진
│ │ ├── deep_learning.py # Attention-LSTM (7D 피처, PyTorch GPU)
│ │ ├── technical.py # 기술적 지표 (RSI, MACD, BB, ADX, OBV...)
│ │ ├── macro.py # 거시경제 분석 (KOSPI/KOSDAQ/MSI)
│ │ ├── ensemble.py # 적응형 앙상블 (3신호 가중치 자동조정)
│ │ ├── evaluator.py # 주간 성과 평가 + LLM 전문가 패널
│ │ └── backtest.py # 백테스팅 프레임워크 (Sharpe, MDD 등)
│ │
│ ├── strategy/ # [Decision] 매매 의사결정
│ │ └── process.py # 워커 프로세스용 분석 함수 (병렬 처리)
│ │
│ ├── services/ # [I/O] 외부 서비스 연동
│ │ ├── kis.py # 한국투자증권 REST API (동기 + 비동기)
│ │ ├── ollama.py # Ollama LLM 인터페이스 (GPU 충돌 방지)
│ │ ├── news.py # Google News RSS 크롤링 (동기 + 비동기)
│ │ ├── telegram.py # 텔레그램 메시지 발송 (Fire-and-forget)
│ │ └── telegram_bot/
│ │ ├── server.py # 텔레그램 봇 서버 (명령어 핸들러)
│ │ └── runner.py # 텔레그램 봇 독립 프로세스 실행기
│ │
│ └── utils/ # [Util] 유틸리티
│ ├── ipc.py # SharedMemory + Command Queue IPC
│ ├── process_tracker.py # PID 추적 & 좀비 정리 & Watchdog
│ ├── monitor.py # CPU/GPU/RAM 서킷 브레이커
│ └── performance_db.py # 일별 스냅샷 & 매매 기록 영구 저장
├── data/ # [Runtime Data]
│ ├── watchlist.json # 현재 감시 종목 리스트
│ ├── daily_trade_history.json # 일일 매매 기록
│ ├── kis_token.json # KIS OAuth 토큰 캐시
│ ├── peak_prices.json # 트레일링 스탑용 최고가
│ ├── ensemble_history.json # AdaptiveEnsemble 가중치 + 매매 히스토리 (종목별)
│ ├── models/ # LSTM 체크포인트 (종목별 .pt 파일)
│ └── performance/ # 성과 데이터 (daily_snapshots, trade_records)
└── tests/ # 테스트
```
---
## 3. 핵심 모듈 상세
### 3.1 AutoTradingBot (`modules/bot.py`)
**메인 트레이딩 루프** — 장 시작(09:00) ~ 장 마감(15:30) 사이에 자동 실행
```
[v3.1 주요 기능]
├── ATR 기반 동적 손절/익절 + 트레일링 스탑
├── Kelly Criterion 포지션 사이징 (실전 승률·손익비 기반, Half-Kelly)
├── AdaptiveEnsemble 연동 (매도 후 가중치 자동 학습)
├── 당일 누적 매수 추적 (_today_buy_total) - KIS T+2 미차감 보완
├── 사이클당 최대 매수 종목 수 제한 (MAX_BUY_PER_CYCLE)
├── ProcessPoolExecutor 병렬 분석 (워커 1개, OOM 대응 자동 재시작)
├── 일별 자산 스냅샷 (09:05~09:15)
├── 주간 성과 평가 (월요일 아침)
├── CPU 서킷 브레이커 연동
└── IPC Command Queue 폴링 (텔레그램 명령 처리)
```
**잔고 추적 로직 (v3.1 — 과매수 방지)**:
```
KIS get_balance() → raw_deposit (dnca_tot_amt)
max_daily_buy = raw_deposit × MAX_DAILY_BUY_RATIO (80%)
tracking_deposit = max_daily_buy - effective_today_buy
max(kis_today_buy, self._today_buy_total)
(KIS thdt_buy_amt vs 로컬 누적 중 큰 값)
```
- `_today_buy_total`: 인스턴스 변수, 사이클 간 유지 (09:00 리셋)
- `_buy_scores`: BUY 시 신호 점수 저장 → SELL 시 `record_trade()` 전달
**run_cycle() 흐름**:
1. 시스템 헬스 체크 (CPU/GPU/RAM)
2. 거시경제 분석 (KOSPI/KOSDAQ/MSI)
3. 위험 상태별 분기 (SAFE/CAUTION/DANGER)
4. Watchlist 종목 OHLCV 수집 (KIS 비동기 배치)
5. 잔고 조회 + 당일 누적 매수 차감 → 실제 가용 예수금 계산
6. `ProcessPoolExecutor`로 종목 병렬 분석 (Kelly Criterion + Ensemble 가중치)
7. 앙상블 점수 기반 매수/매도 판단 (사이클당 MAX_BUY_PER_CYCLE 제한)
8. 주문 실행 & 결과 텔레그램 알림
9. 매도 시 `record_trade()` → Ensemble 가중치 학습
10. IPC 상태 갱신
### 3.2 AI 분석 파이프라인
```
┌─────────────────────┐
│ analyze_stock_ │
│ process() │
│ (strategy/process)│
└─────────┬───────────┘
┌─────────────────────┼────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌────────────────┐ ┌─────────────────┐
│ Technical │ │ Deep Learning │ │ LLM (Ollama) │
│ Analyzer │ │ LSTM │ │ Sentiment │
│ (기술적 지표) │ │ (주가 예측) │ │ (뉴스 감성분석) │
├───────────────┤ ├────────────────┤ ├─────────────────┤
│ RSI 25% │ │ Attention-LSTM │ │ qwen2.5:7b │
│ 이격도 15% │ │ 4L×512H │ │ JSON 포맷 요청 │
│ MACD 15% │ │ 7차원 피처 │ │ 뉴스+지표 통합 │
│ Stochastic 5% │ │ 60일 시퀀스 │ │ 감성+신뢰도 │
│ BB 15% │ │ GPU 가속 │ │ │
│ ADX 15% │ │ 종목별 모델 │ │ │
│ MTF 10% │ │ (ModelRegistry)│ │ │
│ OBV ±보너스 │ │ │ │ │
└───────┬───────┘ └───────┬────────┘ └───────┬─────────┘
│ │ │
└──────────┬────────┘ │
▼ │
┌─────────────────┐ │
│ AdaptiveEnsemble│ ◄───────────────────┘
│ (학습형 가중치) │
├─────────────────┤
│ get_weights() │ ← 과거 매매 결과 반영
│ (ADX+macro+conf)│ 크기 가중 정확도 기준
│ 경계: 0.10~0.65 │ Water-Filling 정규화
│ Kelly Fraction │ ← 승률·손익비 기반
└────────┬────────┘
┌────────────────┐
│ 매수/매도/홀드 │
│ 최종 판단 │
└────────────────┘
```
#### 3.2.1 Deep Learning — Attention-LSTM (`analysis/deep_learning.py`)
| 항목 | 값 |
|------|-----|
| **아키텍처** | 4-Layer Stacked LSTM + Attention + FC |
| **Hidden Size** | 512 |
| **Input Features** | 7 (close, open, high, low, volume_norm, rsi_14, macd_hist) |
| **시퀀스 길이** | 60일 |
| **학습 에포크** | 최대 200 (Early Stopping patience=15) |
| **빠른 재학습** | 30 에포크 (체크포인트 존재 시) |
| **쿨다운** | 1200초 (20분, 동일 종목 재학습 방지) |
| **ModelRegistry** | LRU 방식, 최대 5개 모델 동시 적재 |
| **체크포인트** | `data/models/{ticker}_v3.pt` |
| **GPU 관리** | LSTM 학습 시 Ollama 자동 언로드/리로드 |
#### 3.2.2 기술적 분석 (`analysis/technical.py`)
`TechnicalAnalyzer.get_technical_score()` → 0.0 ~ 1.0 통합 점수
| 지표 | 비중 | 설명 |
|------|------|------|
| RSI (14일) | 25% | Wilder 방식, 30 이하 과매도/70 이상 과매수 |
| 이동평균 이격도 | 15% | 20일 MA 대비 현재가 위치 |
| MACD | 15% | 12/26/9, 히스토그램 방향 |
| Stochastic | 5% | Fast %K/%D (14/3/3) |
| Bollinger Bands | 15% | 20일/2σ, %B 위치 + 밴드폭 |
| ADX | 15% | 추세 강도 (>25 강한 추세) |
| Multi-Timeframe | 10% | 5일/20일/60일 추세 일관성 |
| OBV | ±0.1 보너스 | 거래량 기반 매집/분산 감지 |
추가 기능:
- `calculate_atr()` → ATR 기반 동적 손절/익절
- `calculate_dynamic_sl_tp()` → 변동성 적응형 SL/TP
- `calculate_obv()` → 스마트 머니 다이버전스 감지
#### 3.2.3 거시경제 분석 (`analysis/macro.py`)
```python
MacroAnalyzer.get_macro_status(kis_client) {
"status": "SAFE" | "CAUTION" | "DANGER",
"risk_score": int,
"indicators": {
"KOSPI": {"price", "change", "high", "low", "prev_close", "volume"},
"KOSDAQ": {"price", "change", ...},
"KOSPI200":{"price", "change", ...},
"MSI": float # Market Stress Index (0~100)
}
}
```
- **SAFE** (risk_score < 1): 정상 매매
- **CAUTION** (1 ≤ risk_score < 3): 매수 규모 축소
- **DANGER** (risk_score ≥ 3): 매수 중단, 보유분만 관리
#### 3.2.4 앙상블 (`analysis/ensemble.py`)
`AdaptiveEnsemble` — 과거 매매 결과 기반 가중치 자동 조정 + Kelly Criterion:
**가중치 학습 흐름**:
```
BUY 체결 → bot._buy_scores[ticker] = {tech, sentiment, lstm} 저장
SELL 체결 → ensemble.record_trade(ticker, ..., outcome_pct=yld)
→ _update_weights() → EMA(alpha=0.10) 가중치 점진 조정
→ _save() → data/ensemble_history.json
워커 프로세스 → reload_if_stale() → 파일 mtime 감지 시 재로드
```
**주요 메서드**:
- `get_weights(ticker, adx, macro_state, ai_confidence)``SignalWeights`
- 시장 컨텍스트 (strong_trend/sideways/danger/default) 별 기본 가중치
- 종목별 최근 10거래 크기 가중 정확도 반영
- ai_confidence >= 0.75 → LSTM 가중치 +25% (confidence 상한 0.80 반영)
- `get_kelly_fraction(ticker, half_kelly=True)` → 0.03~0.25 범위 투자 비중
- f* = (p·b - q) / b (p=승률, b=손익비)
- 거래 데이터 < 10건 → 보수적 기본값 8%
- Half-Kelly 적용으로 변동성 과대추정 보완
- `compute_ensemble_score(tech, sentiment, lstm, investor, weights)` → 통합 점수
- `reload_if_stale()` → 파일 mtime 기반 cross-process 동기화
**`SignalWeights.normalize()` — Water-Filling 알고리즘**:
- 경계(0.10~0.65) 위반 시 해당 값을 경계에 고정, 나머지에 잔여 비중 비례 배분
- 2차 정규화(합=1 보장)와 경계 클램핑이 상충하는 문제 해결
- 영구 저장: `data/ensemble_history.json` (가중치 + 매매 히스토리 통합)
#### 3.2.5 성과 평가 (`analysis/evaluator.py`)
`PerformanceEvaluator.generate_weekly_report()`:
- 핵심 지표: 총수익률, Sharpe Ratio, MDD, 승률, 평균손익비, KOSPI 상관도
- S/A/B/C/D/F 등급 산출
- **5명 전문가 LLM 패널** (Ollama): 각각 다른 관점으로 평가
- HTML 포맷 텔레그램 주간 보고서 자동 생성
---
## 4. 외부 서비스 연동
### 4.1 한국투자증권 KIS API (`services/kis.py`)
#### 인증
```python
KISClient.ensure_token()
# OAuth 2.0 → access_token 발급 → data/kis_token.json에 캐시
# 토큰 만료 시 자동 갱신 (_request_api에서 처리)
```
| 설정 | 모의투자 | 실전투자 |
|------|---------|---------|
| Base URL | `openapivts.koreainvestment.com:29443` | `openapi.koreainvestment.com:9443` |
| 환경변수 | `KIS_VIRTUAL_APP_KEY/SECRET/ACCOUNT` | `KIS_REAL_APP_KEY/SECRET/ACCOUNT` |
| 전환 | `.env``KIS_ENV_TYPE=virtual` | `.env``KIS_ENV_TYPE=real` |
#### API 스로틀링
- 초당 2회 제한 (`_throttle()` — 0.5초 딜레이)
- 토큰 만료 시 자동 갱신 (403 → retry with new token)
#### 주요 API 엔드포인트 매핑
| 기능 | KISClient 메서드 | KIS TR_ID |
|------|-----------------|-----------|
| 잔고 조회 | `get_balance()``{holdings, total_eval, deposit, today_buy_amt}` | `VTTC8434R` (모의) / `TTTC8434R` (실전) |
| 주문 (매수/매도) | `order()` | `VTTC0802U` / `VTTC0801U` (모의) |
| 현재가 조회 | `get_current_price()` | `FHKST01010100` |
| 일봉 OHLCV | `get_daily_ohlcv()``_get_daily_ohlcv_by_range()` | `FHKST03010100` |
| 일봉 종가 | `get_daily_price()``_get_daily_price_by_range()` | `FHKST03010100` |
| 거래량 순위 | `get_volume_rank()` | `FHPST01710000` |
| 지수 현재가 | `get_current_index()` | `FHPUP02100000` |
| 지수 일봉 | `get_daily_index_price()` | `FHKUP03500100` |
| 투자자 동향 | `get_investor_trend()` | `FHKST01010900` |
| Hash Key | `get_hash_key()` | - |
#### 비동기 클라이언트 (`KISAsyncClient`)
`aiohttp` 기반 — 다중 종목 동시 수집용:
- `get_daily_price_batch()` — 여러 종목 일봉 병렬 수집
- `get_daily_ohlcv_batch()` — 여러 종목 OHLCV 병렬 수집
- `get_investor_trends_batch()` — 여러 종목 투자자 동향 병렬 수집
---
### 4.2 Ollama LLM (`services/ollama.py`)
| 설정 | 값 |
|------|-----|
| **모델** | `qwen2.5:7b-instruct-q4_K_M` (VRAM ~4GB) |
| **API URL** | `http://localhost:11434` |
| **Context Window** | 4096 토큰 |
| **Max Output** | 200 토큰 |
| **Temperature** | 0.1 (결정론적, JSON 안정성) |
| **Keep Alive** | 5분 (비활성 시 자동 언로드) |
| **Timeout** | 90초 |
| **CPU Threads** | 8 (9800X3D 최적화) |
| **응답 포맷** | JSON (format: "json") |
**GPU 충돌 방지**:
- LSTM 학습 중 → Ollama 추론 최대 60초 대기
- VRAM > 12GB → 모델 즉시 언로드 (`keep_alive=0`)
- LSTM 학습 전 → Ollama 자동 언로드, 학습 후 → 자동 리로드
---
### 4.3 뉴스 수집 (`services/news.py`)
- **소스**: Google News RSS (`news.google.com/rss/search`)
- **동기**: `NewsCollector.get_market_news()` — 시장 일반 뉴스 5건
- **비동기**: `AsyncNewsCollector`
- `get_market_news_async()` — 시장 뉴스 (5분 캐시)
- `get_stock_news_async()` — 종목별 뉴스 (5분 캐시)
---
## 5. 웹 백엔드 서버 API (FastAPI)
### 5.1 서버 정보
| 항목 | 값 |
|------|-----|
| **프레임워크** | FastAPI + Uvicorn |
| **호스트** | `0.0.0.0:8000` |
| **NAS 백엔드** | `http://192.168.45.54:18500` (웹 프론트엔드 서버) |
### 5.2 API 엔드포인트
#### `GET /` — 서버 상태
```json
{
"status": "online",
"gpu_vram": 4.2,
"service": "Windows AI Server (Refactored)"
}
```
#### `GET /trade/balance` | `GET /api/trade/balance` — 잔고 조회
KIS API를 통해 현재 계좌 잔고(예수금, 보유종목, 평가금액) 조회.
```json
{
"total_eval": 10500000,
"deposit": 5000000,
"holdings": [
{
"ticker": "005930",
"name": "삼성전자",
"qty": 10,
"avg_price": 72000,
"current_price": 73500,
"profit_rate": 2.08
}
]
}
```
#### `POST /trade/order` | `POST /api/trade/order` — 수동 주문
```json
// Request Body
{
"ticker": "005930",
"action": "BUY", // "BUY" | "SELL"
"quantity": 10
}
// Response
{
"status": "executed",
"kis_result": { ... }
}
```
#### `POST /analyze/portfolio` | `POST /api/analyze/portfolio` — AI 포트폴리오 분석
현재 잔고 + 최신 뉴스를 종합하여 Ollama LLM으로 포트폴리오 분석.
```json
{
"analysis": "... AI 분석 결과 (한국어) ..."
}
```
### 5.3 NAS 서버와의 통신 흐름
```
┌──────────────┐ HTTP Request ┌────────────────────┐
│ NAS Backend │ ─────────────────────► │ Windows AI Server │
│ (웹 프론트) │ │ (FastAPI:8000) │
│ :18500 │ ◄──────────────────── │ │
│ │ JSON Response │ │
└──────────────┘ └────────────────────┘
[통신 시나리오]
1. 웹 → /api/trade/balance → 잔고 데이터 표시
2. 웹 → /api/trade/order → 수동 매수/매도 실행
3. 웹 → /api/analyze/portfolio → AI 분석 결과 표시
4. 웹 → / → 서버 상태 및 GPU 정보
```
- **NAS 서버** (`192.168.45.54:18500`): 웹 프론트엔드 호스팅, 사용자 인터페이스 제공
- **Windows AI 서버** (`0.0.0.0:8000`): GPU 연산, KIS API 통신, AI 분석 처리
- 내부 네트워크 (LAN) 통신, 외부 노출 없음
---
## 6. 텔레그램 봇 설정 & 명령어
### 6.1 환경변수
```env
TELEGRAM_BOT_TOKEN=8546032918:AAF5GJcP92DrtpSoQdaimMIZe7bz_xtGGPo
TELEGRAM_CHAT_ID=7388056964
```
### 6.2 봇 프로세스 아키텍처
```
runner.py
└── run_telegram_bot_standalone()
├── SharedIPC 초기화 (lock, queue, shutdown_event)
├── TelegramBotServer 생성
├── IPC에서 초기 데이터 로드
├── bot_server.run() (python-telegram-bot polling)
└── Conflict 감지 시 백오프 재시도 (최대 10회)
```
- **라이브러리**: `python-telegram-bot` (Application, CommandHandler)
- **메시지 포맷**: HTML (`parse_mode="HTML"`)
- **동시 업데이트**: `concurrent_updates=True`
- **로깅**: `telegram_bot.log` (파일 + 콘솔)
### 6.3 명령어 목록
| 명령어 | 설명 | 데이터 소스 |
|--------|------|------------|
| `/start` | 봇 시작 & 전체 명령어 안내 | - |
| `/status` | 봇 상태, 시장 지수, AI 모델 상태 | IPC (SharedMemory) |
| `/portfolio` | 보유 종목 & 수익률 조회 | IPC → FakeKIS.get_balance() |
| `/watchlist` | 현재 감시 종목 리스트 | IPC → watchlist 데이터 |
| `/update_watchlist` | Watchlist 즉시 업데이트 요청 | Command Queue → 메인 봇 |
| `/macro` | 거시경제 분석 (KOSPI/KOSDAQ/MSI) | IPC → macro_indices |
| `/system` | CPU/GPU/RAM 시스템 상태 | IPC → gpu_status + psutil |
| `/ai` | AI 모델 상태 (VRAM, 학습 여부) | IPC → gpu_status |
| `/restart` | 메인 봇 재시작 명령 | Command Queue |
| `/stop` | 봇 종료 | shutdown_event.set() |
| `/exec <cmd>` | 서버 쉘 명령어 직접 실행 | subprocess (10초 타임아웃) |
| `/evaluate` | 즉시 성과 평가 보고서 생성 | PerformanceEvaluator |
### 6.4 TelegramMessenger (`services/telegram.py`)
단방향 알림 전용 (메인 봇 → 사용자):
- **비동기 전송**: `threading.Thread(daemon=True)` — Fire-and-forget
- **HTML 파싱**: 마크다운 에러 방지
- 매매 실행, 서버 시작/종료, 에러 알림 등에 사용
### 6.5 Conflict 처리
텔레그램 봇 API는 동시에 하나의 polling 인스턴스만 허용:
- `Conflict` 에러 감지 시 지수 백오프 (5s → 10s → ... → 30s)
- 최대 10회 재시도 후 프로세스 종료
- Watchdog가 감지하여 자동 재시작
---
## 7. 환경 설정 (`modules/config.py`)
### 7.1 주요 설정 상수
| 그룹 | 키 | 값 | 설명 |
|------|-----|-----|------|
| **매매** | `MAX_INVESTMENT_PER_STOCK` | 3,000,000원 | 종목당 최대 투자금 |
| **매매** | `MAX_BUY_PER_CYCLE` | 2 | 사이클당 최대 매수 종목 수 (env: `MAX_BUY_PER_CYCLE`) |
| **매매** | `MAX_DAILY_BUY_RATIO` | 0.80 | 예수금 대비 일일 최대 매수 비율 (env: `MAX_DAILY_BUY_RATIO`) |
| **IPC** | `SHM_NAME` | `web_ai_bot_ipc` | SharedMemory 이름 |
| **IPC** | `SHM_SIZE` | 131,072 (128KB) | SharedMemory 크기 |
| **IPC** | `IPC_STALENESS` | 600초 | 데이터 유효 기간 |
| **GPU** | `VRAM_WARNING_THRESHOLD` | 12.0 GB | VRAM 경고 임계값 |
| **프로세스** | `WATCHDOG_INTERVAL` | 30초 | 헬스체크 간격 |
| **프로세스** | `MAX_RESTART_COUNT` | 3 | 최대 자동 재시작 횟수 |
| **LSTM** | `LSTM_COOLDOWN` | 1,200초 | 동일 종목 재학습 방지 |
| **LSTM** | `LSTM_FAST_EPOCHS` | 30 | 빠른 재학습 에포크 |
| **CPU** | `CPU_CIRCUIT_BREAKER_THRESHOLD` | 92% | 서킷 브레이커 임계값 |
| **CPU** | `CPU_CIRCUIT_BREAKER_CONSECUTIVE` | 2회 | 연속 초과 시 발동 |
| **Ollama** | `OLLAMA_NUM_CTX` | 4,096 | 컨텍스트 윈도우 |
| **Ollama** | `OLLAMA_NUM_PREDICT` | 200 | 최대 출력 토큰 |
| **Ollama** | `OLLAMA_NUM_THREAD` | 8 | CPU 스레드 수 |
| **Network** | `HTTP_TIMEOUT` | 10초 | 기본 HTTP 요청 타임아웃 |
### 7.2 .env 파일 구조
```env
# NAS Backend (웹 프론트엔드 서버)
NAS_API_URL=http://192.168.45.54:18500
# Ollama LLM
OLLAMA_API_URL=http://localhost:11434
OLLAMA_MODEL=qwen2.5:7b-instruct-q4_K_M
# KIS API (virtual/real 전환)
KIS_ENV_TYPE=virtual
KIS_REAL_APP_KEY=...
KIS_REAL_APP_SECRET=...
KIS_REAL_ACCOUNT=XXXXXXXX-XX
KIS_VIRTUAL_APP_KEY=...
KIS_VIRTUAL_APP_SECRET=...
KIS_VIRTUAL_ACCOUNT=XXXXXXXX-XX
# Telegram Bot
TELEGRAM_BOT_TOKEN=...
TELEGRAM_CHAT_ID=...
```
---
## 8. 운영 가이드
### 8.1 시작 방법
```bash
# 일반 시작
python main_server.py
# LSTM 사전학습 후 자동 시작
python warmup_and_restart.py
# 텔레그램 봇만 단독 실행 (디버깅용)
python -m modules.services.telegram_bot.runner
```
### 8.2 좀비 프로세스 관리
- `main_server.py` 실행 시 자동으로 이전 좀비 프로세스 정리
- `pids.txt` 기반 → 메모리 기반 PID 추적으로 전환 완료
- 수동 확인: `Get-Process python` (PowerShell)
### 8.3 로그 파일
| 파일 | 용도 |
|------|------|
| `server.log` | Uvicorn 서버 로그 |
| `telegram_bot.log` | 텔레그램 봇 로그 |
| `warmup.log` | LSTM 사전학습 진행 로그 |
| `bot_output.log` | 트레이딩 봇 출력 로그 |
### 8.4 트러블슈팅
| 증상 | 원인 | 해결 |
|------|------|------|
| KIS 403 Forbidden | 토큰 만료 또는 Rate Limit | `data/kis_token.json` 삭제 후 재시작 |
| Telegram Conflict | 이전 봇 프로세스 미종료 | `main_server.py` 재시작 (자동 정리) |
| GPU OOM | LSTM + Ollama 동시 적재 | `VRAM_WARNING_THRESHOLD` 낮추기 |
| CPU 100% 고정 | 좀비 워커 프로세스 | `main_server.py` 재시작 |
| IPC 데이터 오래됨 | 메인 봇 크래시 | Watchdog 자동 재시작 확인, 수동 재시작 |
| 예수금 초과 매수 | KIS 모의투자 T+2 미차감 | `MAX_DAILY_BUY_RATIO` / `MAX_BUY_PER_CYCLE` 조정 |
| Kelly 비중이 너무 낮음 | 거래 기록 부족 (< 10건) | 초기에는 기본값 8% 사용, 거래 누적 후 자동 조정 |
| 앙상블 가중치 갱신 안 됨 | 매도 체결 없음 또는 `_buy_scores` 누락 | 봇 재시작 전 매도 완료 확인; `data/ensemble_history.json` 확인 |
---
## 9. 데이터 흐름 요약
```
[시장 개장 전]
WatchlistManager → 뉴스 분석 → Watchlist 갱신
[장중 사이클 (≈5분 간격)]
1. SystemMonitor.check_health() → CPU/GPU 확인
2. MacroAnalyzer.get_macro_status() → 시장 상태 판단
3. KIS → get_balance() → raw_deposit - today_buy_total = 가용 예수금
4. KIS → get_daily_ohlcv_batch() → OHLCV 수집
5. ProcessPool → analyze_stock_process() × N종목
├── ensemble.reload_if_stale() → 파일 mtime 감지 시 가중치 재로드
├── TechnicalAnalyzer → 기술적 점수
├── PricePredictor → LSTM 예측
├── OllamaManager → LLM 감성 분석
├── AdaptiveEnsemble.get_weights() → 학습된 동적 가중치
└── calculate_position_size() → Kelly Criterion 수량 산출
6. 매수 판단 → 예수금 확인 → KIS 주문
├── _buy_scores[ticker] 저장 (앙상블 학습용)
├── _today_buy_total += 매수금액
└── buys_this_cycle++ (MAX_BUY_PER_CYCLE 제한)
7. 매도 판단 → KIS 주문
└── ensemble.record_trade() → 가중치 학습 + ensemble_history.json 저장
8. SharedIPC.write_status() → 텔레그램 봇에 공유
9. TelegramMessenger → 결과 알림
[장 마감 후]
PerformanceDB.save_daily_snapshot() → 일별 자산 기록
Evaluator → 주간 보고서 (월요일)
```
---
## 10. 버전 변경 이력
### v3.1 (2026-03-19) — 잔고 관리 & 앙상블 학습 완성
**버그 수정**:
- `tracking_deposit` 사이클 간 초기화 문제 → `_today_buy_total` 인스턴스 변수로 누적 추적
- KIS 모의투자 T+2 미차감으로 인한 예수금 초과 매수 방지
- `ai_confidence >= 0.85` 임계값 버그 (LSTM confidence 상한 0.80 미반영) → 0.75로 수정
- OHLCV 피처 누락 시 silent fallback → 경고 로그 출력
**신규 기능**:
- `MAX_BUY_PER_CYCLE`: 사이클당 최대 매수 종목 수 제한 (기본 2)
- `MAX_DAILY_BUY_RATIO`: 예수금 대비 일일 최대 매수 비율 (기본 80%)
- `kis.get_balance()``today_buy_amt` 필드 추가 (`thdt_buy_amt`)
**앙상블 (`analysis/ensemble.py`)**:
- `AdaptiveEnsemble``process.py`에 실제 연동 (하드코딩 가중치 제거)
- `get_kelly_fraction()`: Half-Kelly Criterion 포지션 비중 계산 추가
- `SignalWeights.normalize()`: Water-Filling 알고리즘으로 경계 위반 문제 해결
- `_accuracy()` 이진 지표 제거 → `_accuracy_weighted()` (크기 가중) 통일
- `reload_if_stale()`: 파일 mtime 기반 cross-process 동기화
**포지션 사이징 (`strategy/process.py`)**:
- `calculate_position_size()`: 하드코딩 10% → Kelly Criterion (과거 승률·손익비 기반)
- `bot.py` 중복 계산 제거 → 워커의 `suggested_qty` 직접 사용
**앙상블 학습 루프 (`bot.py`)**:
- BUY 체결 시 `_buy_scores[ticker]` 신호 점수 저장
- SELL 체결 시 `ensemble.record_trade()``ensemble_history.json` 갱신
- 워커 프로세스는 `reload_if_stale()`로 자동 반영