Files
stock_chart_site/README.md
tkrmagid 5e6ce11491 feat(weights): shadow chronos/lgbm 예측 + ensemble_weights 자동 보정
- ensemble.predict() 가 chronos_raw / lgbm_raw 를 함께 반환
- predict_and_store() 가 매 호출마다 3종 행 적재:
    model='ensemble' (user_triggered=인자)
    model='chronos'  (user_triggered=FALSE, shadow)
    model='lgbm'     (user_triggered=FALSE, shadow)
- retrain_weekly.adjust_weights(): 최근 30일 prediction_outcomes 의
  chronos vs lgbm hit_rate 로 ensemble_weights upsert
    w_chronos = clamp(0.1, hr_c/(hr_c+hr_l), 0.9), w_lgbm = 1 - w_chronos
  모델별 표본 < 10 이면 기본값(0.6/0.4) 유지
- API 응답에 saved_shadow_ids 추가 (TS 타입도 동기화)
- README: 동작 모델 메모 섹션을 실제 구현과 일치하도록 갱신

리뷰어 지적 3번 (ensemble_weights 가 영원히 갱신 안됨, upsert_weights 미호출) 해결.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 16:27:21 +09:00

171 lines
7.7 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.
# stock_chart_site
개인용 주식 차트 + 단기 예측 사이트. 한국 종목 검색 → 현재 차트 표시 → "예상차트 보기" 클릭 시 Chronos+LightGBM 앙상블로 향후 1~5거래일 예측을 차트에 이어 붙임. 사용자가 한 번이라도 예측을 확인한 종목은 자동 저장해서 다음날 실제 가격과 비교 → 오차/방향성 적중률을 누적 → 앙상블 가중치를 자동 보정.
스펙 원문: `/home/claude/EJClaw/groups/stock_predictor/SPEC.md` (별도 채팅 그룹).
## 빠른 시작 (Windows + Docker Desktop + RTX 3070 Ti)
전제: Docker Desktop이 이미 설치되어 있고, GPU 사용하려면 `Settings → Resources → WSL Integration → GPU support`가 켜져 있어야 합니다.
```cmd
git clone https://git.tkrmagid.kr/tkrmagid/stock_chart_site.git
cd stock_chart_site
build.bat
```
`build.bat`이 자동으로
1. `.env.example``.env` 복사 (없는 경우)
2. `nvidia-smi` 로 GPU 감지 → GPU 있으면 GPU 모드, 없으면 CPU 폴백
3. `docker compose build` + `up -d`
확인:
- Web: http://localhost:3000
- Backend health: http://localhost:8000/health
- DB extensions: http://localhost:8000/health/db (`timescaledb`, `vector`, `pg_trgm` 셋 다 켜져 있어야 정상)
정지:
```cmd
docker compose down
```
## 빌드 모드 (수동)
`build.bat`을 안 쓰는 경우 `.env`가 먼저 있어야 합니다.
```bash
# .env 없으면 한 번만 복사
copy .env.example .env
# GPU 모드 (RTX 3070 Ti 등 NVIDIA GPU 사용)
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d --build
# CPU 모드
docker compose up -d --build
```
## API 키 발급 (모두 무료)
키 없어도 pykrx 기반 일봉/뉴스 RSS 만으로 일단 동작합니다. 다음 키를 받으면 데이터 품질이 좋아집니다.
### 1) 한국투자증권 KIS OpenAPI (실시간 시세 + EOD)
1. https://apiportal.koreainvestment.com 회원가입 (한국투자증권 계좌 필요)
2. 좌측 "Open API 신청" → 모의/실전 중 하나 신청
3. 발급 완료 후 마이페이지에서 App Key, App Secret, 계좌번호 확인
4. `.env` 에 입력:
```
KIS_APP_KEY=...
KIS_APP_SECRET=...
KIS_ACCOUNT_NO=...
```
### 2) DART OpenAPI (전자공시 본문)
1. https://opendart.fss.or.kr 회원가입
2. 마이페이지 → 인증키 신청 → 즉시 발급
3. `.env` 에 입력:
```
DART_API_KEY=...
```
### 3) HuggingFace (선택, 모델 다운로드 가속)
토큰 없어도 공개 모델 (`amazon/chronos-bolt-base`, `snunlp/KR-FinBert`) 다운로드가 됩니다. 토큰이 있으면 rate limit이 완화되고 첫 다운로드가 빨라집니다.
1. https://huggingface.co 회원가입
2. https://huggingface.co/settings/tokens 에서 Read 토큰 생성
3. `.env` 에 입력:
```
HUGGINGFACE_TOKEN=hf_...
```
## 학습/배치 대상 시드 종목 (10개)
검색은 KRX 전 종목을 대상으로 동작하지만, 일별 배치/재학습/메트릭 누적은 아래 10개를 우선 대상으로 합니다. 운영하면서 더 의미있는 종목이 보이면 교체합니다.
| 분류 | 종목 | 코드 |
|---|---|---|
| 대형 인기주 | 삼성전자 | 005930 |
| 대형 인기주 | SK하이닉스 | 000660 |
| 변동성 큰 종목 | 에코프로비엠 | 247540 |
| 변동성 큰 종목 | 한미반도체 | 042700 |
| 최근 인기 테마 | 두산에너빌리티 | 034020 |
| 최근 인기 테마 | 한화에어로스페이스 | 012450 |
| 최근 인기 테마 | HD현대중공업 | 329180 |
| 전통 IT/플랫폼 | NAVER | 035420 |
| 방어주/저변동 | KT&G | 033780 |
| 방어주/저변동 | 한국가스공사 | 036460 |
## 디렉토리 구조
```
stock_chart_site/
├── build.bat # Windows: 빌드+기동
├── docker-compose.yml # db + backend + web
├── docker-compose.gpu.yml # GPU 오버레이 (NVIDIA reservation)
├── .env.example # 환경 변수 템플릿
├── backend/
│ ├── Dockerfile # CUDA 12.1 + Python 3.11
│ ├── pyproject.toml
│ └── app/
│ ├── main.py # FastAPI entry
│ ├── config.py # env settings
│ ├── db/
│ │ ├── connection.py
│ │ └── migrations/
│ │ └── 001_init.sql # DB 스키마
│ ├── fetch/ # KIS / pykrx / DART / 뉴스 (Phase 1)
│ ├── models/ # Chronos / LightGBM / KR-FinBERT (Phase 2~4)
│ ├── pipelines/ # daily_batch / inference / retrain (Phase 1, 4)
│ └── api/ # FastAPI 라우터 (Phase 5)
└── web/
├── Dockerfile
├── package.json
└── app/
├── layout.tsx
└── page.tsx # 검색 + 차트 UI (Phase 6)
```
## 진행 계획
- [x] Phase 0 — 스캐폴드: Docker 환경 + DB 스키마 + FastAPI/Next.js + build.bat
- [x] Phase 1a — pykrx 데이터 파이프: 일봉/외인기관/지수 + DART + 뉴스 RSS + 거시
- [x] Phase 1b — KIS read-only EOD (스모크 통과)
- [x] Phase 2 — KR-FinBERT 감성 점수 + 일별 집계 뷰
- [x] Phase 3 — Chronos zero-shot 예측 어댑터 + 피처 빌더
- [x] Phase 4 — LightGBM walk-forward + ensemble + 매칭/재학습 잡
- [x] Phase 5 — FastAPI 엔드포인트 (검색/차트/예측/메트릭/뉴스)
- [x] Phase 6 — Next.js UI (검색 + 현재 차트 + 예상차트 overlay)
- [ ] Phase 7 (옵션) — 백테스트 페이지 + Chronos/LGBM 단독 shadow 예측
### API 엔드포인트 (요약)
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | `/health`, `/health/db`, `/health/keys` | 헬스/외부키 ping |
| POST | `/api/refresh/{code}?lookback_days=N` | 수동 갱신 |
| GET | `/api/symbols/search?q=&seed_only=` | 종목 검색 (trigram + prefix) |
| GET | `/api/symbols/{code}` | 종목 메타 |
| GET | `/api/chart/{code}?days=N` | OHLCV + 감성 + 외인기관거래대금 |
| POST | `/api/predict/{code}?horizons=1,3,5` | on-demand 앙상블 예측 (user_triggered) |
| GET | `/api/predict/{code}/latest` | 최신 base_date 예측 묶음 (UI overlay) |
| GET | `/api/metrics/{code}?window_days=N` | 종목 hit_rate / mae |
| GET | `/api/news/{code}?limit=N&source=` | 최근 뉴스/공시 + 감성 |
## 동작 모델 메모
- 예측 트리거: 사용자가 "예상차트 보기" 누른 종목에 대해 즉시 inference. 결과는 세 종류 행으로 적재:
- `model='ensemble'` (user_triggered=TRUE) — UI 가 표시하는 최종 예측
- `model='chronos'` (user_triggered=FALSE, shadow) — Chronos 단독 성능 추적용
- `model='lgbm'` (user_triggered=FALSE, shadow) — LGBM 단독 성능 추적용
- 매칭 배치: 평일 16:30 KST. `target_date <= today AND outcomes 미존재` 인 모든 행에 대해 `target_date` 이상 `today` 이하 범위의 **최초 거래일 종가**를 actual_close 로 사용 → 주말/공휴일 자동 이월. shadow 행도 함께 매칭됨.
- 주간 02:00 (일요일): 시드 10종목 × horizons LGBM 재학습. 최근 30일 prediction_outcomes 의 chronos vs lgbm hit_rate 비교 → `w_chronos = clamp(0.1, hr_c/(hr_c+hr_l), 0.9)` 공식으로 `ensemble_weights` upsert. 모델별 표본이 10 미만이면 기본값(0.6/0.4) 유지.
- DB bootstrap: 백엔드 첫 부팅 시 lifespan 에서 idempotent migration + symbols 시드(비어있을 때만 pykrx 전 종목 적재) 자동 수행. `BOOTSTRAP_DISABLED=1` 로 비활성화 가능.
## 안전/한계
- 본인 1인 개인용. 외부 공개/상업 사용 안 함.
- 자동매매 연결 없음. 예측은 참고용.
- 백테스트 정확도와 라이브 정확도는 다르며 단기 방향성 모델의 라이브 상한은 보통 55~60%.