# 🤖 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()`로 자동 반영
