97cf5aecb0
trading/pipeline/head This commit looks good
이번 세션 외 그간 쌓인 변경 일괄 저장: - bareunaapi: finance_dict 금융용어 / stock_loader 종목 로더 보강 - kis-api: 키움 토큰·수집 로직 - us-market / dart-collector: 수집 보강 - docker-compose: GEMINI_API_KEY 등 환경변수 추가 - score-engine/news-collector requirements, CLAUDE.md - 신규: PROJECT.md, news-collector/sentiment_rules.py Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
646 lines
28 KiB
Markdown
646 lines
28 KiB
Markdown
# Trading AI — Claude Code 프로젝트 가이드
|
||
|
||
> **역할**: 워렌 버핏 스타일 한국 주식 AI 투자 분석 전문가로 행동할 것.
|
||
> 가치투자 관점(ROE·영업이익률·부채비율·FCF)을 최우선으로 판단한다.
|
||
> 이 파일은 매 대화 시작 시 자동 로드됨 — 파일 탐색 없이 이 내용만으로 작업 시작.
|
||
|
||
---
|
||
|
||
## Claude 행동 원칙
|
||
|
||
### 1. 먼저 생각, 그 다음 코딩
|
||
- 가정은 명시적으로 밝힐 것. 불확실하면 질문.
|
||
- 해석이 여러 개면 나열하고 고를 것 — 혼자 결정 금지.
|
||
- 더 단순한 방법이 있으면 말할 것. 불필요한 복잡성에 반론.
|
||
|
||
### 2. 단순함 우선
|
||
- 요청한 것만 구현. 추측성 기능·추상화·유연성 추가 금지.
|
||
- "나중에 필요할 수도" 코드 금지. 200줄이 50줄로 가능하면 다시 짤 것.
|
||
- 불가능한 시나리오를 위한 에러 핸들링 금지.
|
||
|
||
### 3. 정밀한 변경
|
||
- 요청한 부분만 수정. 인접 코드 "개선" 금지.
|
||
- 기존 스타일 유지 (내 방식이 달라도).
|
||
- 내 변경으로 생긴 불필요한 import/변수/함수만 제거. 기존 dead code는 언급만.
|
||
|
||
### 4. 검증 기준 명시
|
||
- 다단계 작업 시 각 단계 완료 조건을 먼저 정의.
|
||
- Docker 서비스 변경 → 로그 확인 필수.
|
||
- DB 변경 → 쿼리로 확인 필수.
|
||
|
||
### 이 프로젝트 특이사항
|
||
- sudo 비밀번호 입력 불가 → sudo 필요 작업은 `! sudo <cmd>` 형태로 유저에게 요청.
|
||
- n8n 마이그레이션 충돌 이력 있음 → n8n 스키마 변경 시 반드시 백업 먼저.
|
||
- NAS fstab은 한 줄 유지 필수 (nfsvers=3).
|
||
- 상장폐지 필터(`is_active=true`) 빠지면 추천 결과 오염됨.
|
||
|
||
---
|
||
|
||
## 시스템 개요
|
||
|
||
뉴스 수집 → 형태소분석 → 임베딩 → 중복제거 → AI분석 → 재무스코어링 → 기술분석 → 매수/매도 추천 → 텔레그램 알림
|
||
|
||
---
|
||
|
||
## 인프라
|
||
|
||
| 항목 | 값 |
|
||
|------|-----|
|
||
| 서버 OS | Ubuntu 22.04 |
|
||
| GPU | GPU0: RTX 3060 12GB (EXAONE 추론) / GPU1: RTX 3070 8GB (bge-m3 임베딩) |
|
||
| NAS | `192.168.0.36:/volume1/trading → /mnt/nas` (nfsvers=3 필수) |
|
||
| DB 연결 | `postgres:5432`, DB명 `trading_ai`, user `kyu` |
|
||
| 환경변수 | `/home/kyu/trading/.env` |
|
||
| Docker | `docker compose` (파일: `/home/kyu/trading/docker-compose.yml`) |
|
||
| PostgreSQL 데이터 | `/mnt/nas/postgresql/data` (NAS 저장) |
|
||
|
||
---
|
||
|
||
## 서비스 목록
|
||
|
||
| 서비스 | 컨테이너 | 포트 | 내부IP | 역할 |
|
||
|--------|---------|------|--------|------|
|
||
| news-collector | trading-news-collector | 8787 | 172.30.0.16 | 뉴스수집+형태소+임베딩+Ollama분석 |
|
||
| bareunaapi | trading-bareunaapi | 5757 | 172.30.0.12 | 한국어 형태소분석 FastAPI 래퍼 |
|
||
| bareun | trading-bareun | 5656/9902 | 172.30.0.15 | 바른 NLP gRPC 서버 |
|
||
| dart-collector | trading-dart-collector | 8888 | 172.30.0.17 | DART 공시/재무제표 수집 |
|
||
| score-engine | trading-score-engine | 8686 | 172.30.0.19 | 종합 투자 스코어 계산+텔레그램 |
|
||
| ta-engine | trading-ta-engine | 8484 | 172.30.0.23 | 기술적분석 (MA/RSI/MACD/볼밴/스토캐스틱) |
|
||
| dashboard-api | trading-dashboard-api | 8989 | 172.30.0.22 | 대시보드 REST API |
|
||
| kis-api | trading-kis-api | 8585 | 172.30.0.18 | 네이버모바일 주가수집 + 매매시그널 |
|
||
| ollama | trading-ollama | 11434 | 172.30.0.13 | EXAONE 3.5 7.8B 추론(GPU0) + bge-m3 임베딩(GPU1) |
|
||
| n8n | trading-n8n | 5678 | 172.30.0.20 | 워크플로우 자동화 |
|
||
| n8n-worker | trading-n8n-worker | - | 172.30.0.21 | n8n Queue Worker |
|
||
| postgres | trading-postgres | 5432 | - | 메인 DB |
|
||
| redis | trading-redis | 6379 | 172.30.0.10 | 캐시/중복제거 |
|
||
| qdrant | trading-qdrant | 6333 | 172.30.0.11 | 뉴스 벡터 유사도 필터 |
|
||
| aux-signal | trading-aux-signal | 8282 | 172.30.0.25 | 보조 데이터: 네이버 컨센서스·기관/외국인 수급 + ECOS 매크로(USD/KRW, 국고채10년) |
|
||
| us-market | trading-us-market | 8383 | 172.30.0.24 | 미증시→한국 동조 시그널 (섹터ETF 14개 ±5점, 개별 페어 회귀 ±10점, 자동 페어발굴) |
|
||
| graph-engine | trading-graph-engine | 9090 | 172.30.0.27 | GAT 그래프 신경망 (12피처 노드 × 가격상관/섹터/뉴스공기 엣지) → graph_score |
|
||
| telegram-bot | trading-telegram-bot | - | 172.30.0.26 | 텔레그램 명령 처리 (/buy /sell /stock /deep /market) |
|
||
|
||
---
|
||
|
||
## 파일 구조 & 핵심 함수
|
||
|
||
### `/home/kyu/trading/news-collector/main.py` (21KB)
|
||
뉴스 수집 + AI 분석 파이프라인. 포트 8787.
|
||
|
||
| 함수/클래스 | 역할 |
|
||
|------------|------|
|
||
| `class S` | 전역 상태 (DB pool, Redis, Qdrant client) |
|
||
| `nhash(title, url)` | SHA256[:16] 뉴스 중복 해시 |
|
||
| `is_korean(text)` | 한글 포함 여부 체크 |
|
||
| `parse_rss_date(date_str)` | RSS pubDate → ISO timestamp |
|
||
| `@app.post("/collect/market")` | 네이버 금융 메인 뉴스 수집 |
|
||
| `@app.post("/collect/stocks")` | 종목별 네이버 뉴스 수집 |
|
||
| `@app.post("/collect/rss")` | 18개 RSS 피드 수집 |
|
||
| `@app.get("/sources")` | RSS 소스 목록 |
|
||
|
||
**파이프라인 순서** (함수 내부):
|
||
1. 바른API `/analyze` → 형태소분석 + 종목감지
|
||
2. Ollama `bge-m3` → 1024차원 임베딩
|
||
3. Qdrant → 코사인 유사도 ≥0.92 중복 제거
|
||
4. Ollama `exaone3.5:7.8b` (GPU0) → 호재/악재/중립 + intensity(1~5) + catalyst분류
|
||
5. PostgreSQL `news_analysis` 저장
|
||
|
||
**EXAONE 프롬프트**: 버핏 관점 (실적/수주/배당/리스크/모멘텀/기타 catalyst 분류)
|
||
|
||
**RSS 소스 (28개)**: 한국경제, 매일경제, 머니투데이, 이데일리, 연합뉴스, 조선비즈, 헤럴드경제, 아시아경제, 파이낸셜뉴스, SBS Biz, 뉴스1, 뉴시스 등 + 네이버금융 직접 크롤링
|
||
|
||
**스케줄러**:
|
||
- 평일 RSS: 8-18시 5분마다 (`rss_weekday`)
|
||
- 주말 RSS: 8-22시 15분마다 (`rss_weekend`) — 누적 학습용
|
||
- 평일 마켓: 9-17시 10분마다 (`market`, 네이버 금융 메인)
|
||
- raw 분석: 24시간 30분마다 200건 batch (`process_raw`) — 백로그 소화용으로 확장
|
||
- 주간 raw 백필: 일요일 02:00 전체 종목 × 50페이지 (`historical_raw_weekly`)
|
||
|
||
**수집/분석 분리** (대규모 백필용):
|
||
- `POST /collect/historical-raw?count=0&max_pages=100` — raw만 빠르게 수집 (LLM 스킵)
|
||
- `POST /process/raw?batch_size=200` — news_raw → news_analysis 점진 분석
|
||
- `GET /raw/stats` — 백필 진행률 (total/unprocessed/processed)
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/bareunaapi/main.py` (9.5KB)
|
||
한국어 형태소분석 FastAPI 래퍼. 포트 5757.
|
||
|
||
| 함수/클래스 | 역할 |
|
||
|------------|------|
|
||
| `class AppState` | bareun gRPC stub + Redis + 종목사전 |
|
||
| `class AnalyzeRequest / AnalyzeResponse` | 분석 요청/응답 모델 |
|
||
| `news_hash(title, url)` | Redis 중복제거용 해시 |
|
||
| `extract_morphemes(text)` | 바른API → 명사 추출 |
|
||
| `extract_stocks(text)` | 텍스트에서 종목코드 감지 |
|
||
| `build_filtered(nouns, stocks)` | 필터링된 텍스트 구성 |
|
||
| `scan_finance_terms(text)` | finance_dict.py 금융용어 매칭 |
|
||
| `_analyze(req)` | 핵심 분석 로직 |
|
||
| `@app.post("/analyze")` | 단건 분석 |
|
||
| `@app.post("/analyze/batch")` | 배치 분석 |
|
||
| `@app.get("/stocks")` | 로드된 종목 목록 |
|
||
| `@app.post("/stocks/refresh")` | KRX→Naver 종목 새로고침 |
|
||
| `@app.delete("/dedup/flush")` | Redis 중복제거 캐시 초기화 |
|
||
|
||
**관련 파일**:
|
||
- `bareunaapi/finance_dict.py` — 주식/금융 전문 용어 사전
|
||
- `bareunaapi/stock_loader.py` — KRX→Naver 폴백, ~3768 종목 로드
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/dart-collector/main.py` (34KB)
|
||
DART 공시/재무제표 수집. 포트 8888.
|
||
|
||
| 함수/클래스 | 역할 |
|
||
|------------|------|
|
||
| `class Stats` | 수집 통계 |
|
||
| `get_corp_code(stock_code)` | 종목코드 → DART corp_code 변환 |
|
||
| `get_corp_name(stock_code)` | 종목코드 → 기업명 |
|
||
| `calc_financial_ratios(key_items, prev_revenue)` | ROE/영업이익률/부채비율/FCF/매출성장률 계산 |
|
||
| `@app.post("/collect/disclosures")` | 공시 수집 |
|
||
| `@app.post("/collect/financials")` | 재무제표 수집 (300개 종목) |
|
||
| `@app.post("/collect/major")` | 주요 대형주 수집 |
|
||
| `@app.post("/collect/corps")` | DART 기업목록 갱신 |
|
||
| `@app.get("/corps")` | 기업목록 조회 |
|
||
| `@app.get("/corps/{stock_code}")` | 특정 기업 조회 |
|
||
| `@app.get("/financials/{stock_code}")` | 종목 재무데이터 |
|
||
| `@app.get("/stats")` | 수집 통계 |
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/score-engine/main.py` (27KB)
|
||
종합 투자 스코어 계산 + 텔레그램 알림. 포트 8686.
|
||
|
||
| 함수/클래스 | 역할 |
|
||
|------------|------|
|
||
| `get_recommendation(score)` | 점수→등급 변환 |
|
||
| `calc_fundamental_score(fin, per, pbr)` | 재무점수 산출 (-100~100) |
|
||
| `calc_magic_formula(fin, market_cap)` | 그린블라트 매직 포뮬러 (ROC + EY) 0~30점 |
|
||
| `calc_piotroski_score(curr, prev)` | 피오트로스키 F-Score 7신호 → -15~+15 |
|
||
| `calc_altman_z(fin, market_cap)` | 알트만 Z-Score 단순화 → 매수/매도/관망 신호 |
|
||
| `calc_peg(curr, prev, per)` | 린치 GARP — PER/이익성장률 → 신호 |
|
||
| `calc_momentum(conn, code)` | AQR 12-1개월 가격 모멘텀 → 신호 |
|
||
| `calc_beneish_simplified(curr, prev)` | Beneish M-Score 단순화 (분식 의심도) |
|
||
| `aggregate_signals(signals)` | 6공식 보팅 다수결 → (요약, 카운트) |
|
||
| `calc_trend_score(conn, code)` | 5년 ROE 일관성·추세 -30~+30 |
|
||
| `calc_dcf(fin, market_cap)` | 간이 DCF 내재가치 + 안전마진 |
|
||
| `calc_earnings_quality(fin)` | CFO/영업이익 비율 (분식의심 패널티) |
|
||
| `is_value_investable(fin, per, pbr, market_cap)` | 버핏 필터 통과 여부 |
|
||
| `@app.post("/score/calculate")` | 종목 점수 계산 실행 |
|
||
| `@app.post("/briefing/send")` | 텔레그램 브리핑 전송 |
|
||
| `@app.get("/ranking")` | 전체 종목 랭킹 |
|
||
| `@app.get("/recommendations")` | 추천 종목 목록 |
|
||
| `@app.get("/stock/{code}")` | 특정 종목 점수 상세 |
|
||
| `@app.get("/backtest")` | 추천 성과 백테스트 (수익률/승률/샤프/MDD/알파) |
|
||
| `@app.post("/learn-weights")` | 공식별 신호 → 7d 수익률 회귀로 가중치 학습 |
|
||
| `@app.get("/learn-weights")` | 현재 적용 중인 공식 가중치 조회 |
|
||
| `@app.post("/learn-pricing")` | D+E: 점수→30d 수익률 선형회귀 + Random Forest 학습 |
|
||
| `@app.get("/predict-price/{code}")` | 학습된 모델로 종목 30일 후 예상 수익률·가격 |
|
||
| `@app.get("/sector/concentration")` | 섹터 집중도 + 30% 초과 경고 |
|
||
|
||
**스코어링 공식 (실제 가중치)**:
|
||
```
|
||
종합점수 = 펀더멘털통합×0.24 + 뉴스(catalyst가중)×0.18 + 기술×0.15
|
||
+ DART공시×0.10 + 외국인수급×0.14 + 공매도×0.06
|
||
+ 가격모멘텀×0.03 + DCF안전마진×0.10
|
||
+ 시장레짐 보정(±5~10)
|
||
+ 앙상블 보팅(±18) ← 6공식 매수/매도 합 × 학습가중치
|
||
```
|
||
|
||
**10공식 앙상블 보팅** — 각 공식이 독립 신호 발신, 학습 가중치로 결합:
|
||
| 공식 | 출처/논문 | 데이터 | 매수 신호 |
|
||
|------|----------|--------|----------|
|
||
| 매직포뮬러 | Greenblatt | ROC + EY | magic_score ≥ 20 |
|
||
| F-Score | Piotroski 2000 | 7신호 (전년 대비) | f_score ≥ 6 |
|
||
| 알트만 Z | Altman 1968 | 6.72×ROA + 1.05×(시총/부채) | Z ≥ 2.6 |
|
||
| PEG | Lynch GARP | PER / 이익성장률 | PEG ≤ 1.5 |
|
||
| 12-1 모멘텀 | AQR (Carhart 1997) | (P_-21 / P_-252) - 1 | ≥ 10% |
|
||
| Beneish | Beneish 1999 | TATA·SGI·CFO/NI | 의심도 < 50 + CFO/NI > 1 |
|
||
| **GP/A** | Novy-Marx 2013 | 영업이익/총자산 (대체) | ≥ 15% |
|
||
| **G-Score** | Mohanram 2005 | 5신호 vs 섹터 중앙값 | ≥ 4 |
|
||
| **Amihud** | Amihud 2002 | avg(\|return\|/거래대금) | ≥ 100 (소형 알파) |
|
||
| **베타(BAB)** | Frazzini-Pedersen 2014 | 종목 vs KOSPI 60일 회귀 | β < 0.7 (저베타 알파) |
|
||
|
||
**학습 가중치** (`weight_config` 테이블):
|
||
- `POST /learn-weights?days=90` — 백테스트로 공식별 매수vs매도 그룹 7d 수익률 차이(edge) 측정
|
||
- edge가 큰 공식일수록 가중치 ↑ (정규화 후 합 = 6, 균등 시 각 1.0)
|
||
- 다음 점수 계산부터 자동 적용. 표본 부족 시 default(균등 1.0)
|
||
|
||
**펀더멘털통합** = `clip(buffett_score + trend_score + earnings_quality + magic_score + f_score_adj, -100, 100)`
|
||
- `buffett_score`: ROE / 영업이익률 / 부채비율 / 매출성장 / PER / PBR / FCF / 배당
|
||
- `trend_score`: 5년 ROE 일관성·추세 (-30~+30)
|
||
- `earnings_quality`: CFO/영업이익 ≥1 가산, <0.7 분식의심 패널티
|
||
- `magic_score`: ROC(영업이익/총자산) + EY(영업이익/EV) 임계값 합산 (0~30)
|
||
- `f_score_adj`: F-Score ≥6 +15, 5 +8, 4 +3, ≤2 -15 (가치함정 회피)
|
||
|
||
**매직 포뮬러 임계값** (한국 시장 보정):
|
||
- ROC: ≥25% +15 / ≥15% +10 / ≥8% +5
|
||
- EY: ≥15% +15 / ≥10% +10 / ≥6% +5
|
||
|
||
**피오트로스키 F-Score 7신호** (현재/전년 사업보고서 비교, 9중 2개는 데이터 부재로 생략):
|
||
1. ROA(NI/총자산) > 0 2. CFO > 0 3. ΔROA > 0 4. CFO > NI
|
||
5. Δ부채비율 < 0 6. Δ영업이익률 > 0 7. Δ자산회전율 > 0
|
||
|
||
**추천 등급** (점수 + 다수공식 동의 강제):
|
||
- 강력매수: 점수 ≥70 AND 매수보팅 ≥3
|
||
- 매수관심: 점수 ≥40 AND 매수보팅 ≥1 AND 매도보팅 <2
|
||
- 매도관심: 점수 ≤-30 OR 매도보팅 ≥3
|
||
- 강력매도: 점수 ≤-60 OR 매도보팅 ≥4
|
||
- 관망: 그 외
|
||
|
||
**버핏 가치투자 필터** (`is_value_investable`):
|
||
- `operating_profit > 0` 영업적자 제외
|
||
- ROE ≥ 10%
|
||
- 부채비율 ≤ 200%
|
||
- PER ≤ 60
|
||
- 시총 ≥ 100억
|
||
- `dart_corps.is_active=true` (상장폐지 제외)
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/ta-engine/main.py` (37KB)
|
||
기술적 분석 엔진. 포트 8484.
|
||
|
||
| 함수/클래스 | 역할 |
|
||
|------------|------|
|
||
| `_ema_series(values, period)` | EMA 계산 |
|
||
| `_ma(closes, n)` | 단순이동평균 |
|
||
| `_rsi(closes, period=14)` | RSI |
|
||
| `_macd(closes)` | MACD (12/26/9) |
|
||
| `_bollinger(closes, period=20)` | 볼린저밴드 |
|
||
| `_stochastic(highs, lows, closes, period=14)` | 스토캐스틱 K/D |
|
||
| `_vol_ratio(volumes, period=20)` | 거래량비율 |
|
||
| `calc_indicators(ohlcv)` | 전체 지표 계산 |
|
||
| `calc_tech_score(ind)` | 기술점수 (-100~100) |
|
||
| `calc_price_targets(price, ind, sig)` | 목표가/손절가 계산 |
|
||
| `analyze_position(price, buy_price, qty, ...)` | 포지션 분석 |
|
||
| `@app.get("/technical/{code}")` | 종목 기술분석 |
|
||
| `@app.get("/ranking")` | 기술점수 랭킹 |
|
||
| `@app.get("/buy-candidates")` | 매수 후보 |
|
||
| `@app.post("/analyze/all")` | 전체 종목 분석 |
|
||
| `@app.post("/analyze/{code}")` | 특정 종목 분석 |
|
||
| `@app.post("/position")` | 포지션 분석 |
|
||
| `@app.get("/report/{code}")` | 종합 리포트 |
|
||
|
||
**목표가 계산**:
|
||
- 진입가: `min(현재가, MA20×0.99)`
|
||
- T1: `max(볼밴상단, 현재가×1.05)`
|
||
- T2: `max((현재가+52주고가)/2, 현재가×1.10)`
|
||
- T3: `max(52주고가×0.97, 현재가×1.20)`
|
||
- 손절가: `min(MA60×0.98, 현재가×0.95)`
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/dashboard-api/main.py` (19KB)
|
||
대시보드 REST API. 포트 8989.
|
||
|
||
| 엔드포인트 | 역할 |
|
||
|-----------|------|
|
||
| `GET /api/summary` | 전체 요약 통계 |
|
||
| `GET /api/recent` | 최근 뉴스 분석 |
|
||
| `GET /api/ranking` | 종합 랭킹 |
|
||
| `GET /api/recommendations` | 추천 종목 |
|
||
| `GET /api/avoid` | 회피 종목 |
|
||
| `GET /api/signals` | 매매 시그널 |
|
||
| `GET /api/technical/{code}` | 기술분석 데이터 |
|
||
| `GET /api/buy-candidates` | 매수 후보 |
|
||
| `GET /api/alerts` | 알림 목록 |
|
||
| `GET /api/timeline` | 타임라인 |
|
||
| `GET /api/stock/{code}` | 종목 상세 |
|
||
| `GET /api/search` | 종목 검색 |
|
||
| `POST /api/position` | 포지션 등록 |
|
||
| `GET /api/report/{code}` | 종목 리포트 |
|
||
| `GET /api/fundamentals` | 전체 재무데이터 |
|
||
| `GET /api/fundamentals/{code}` | 종목 재무데이터 |
|
||
| `GET /api/name/{code}` | 종목명 조회 |
|
||
| `GET /` | 대시보드 HTML |
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/kis-api/main.py` (11KB)
|
||
네이버 모바일 주가수집 + 매매시그널. 포트 8585.
|
||
|
||
| 함수/엔드포인트 | 역할 |
|
||
|---------------|------|
|
||
| `class Stats` | 수집 통계 |
|
||
| `calc_signal(p, news_sc, dart_sc)` | 뉴스+공시점수 → 매매시그널 |
|
||
| `GET /price/{code}` | 단일 종목 주가 |
|
||
| `GET /prices` | 전체 주가 목록 |
|
||
| `GET /signals` | 전체 시그널 |
|
||
| `GET /signals/{code}` | 종목별 시그널 |
|
||
| `POST /collect` | 주가 수집 실행 |
|
||
|
||
**Redis DB 할당**:
|
||
- db=0: n8n Queue
|
||
- db=1: bareunaapi 중복제거
|
||
- db=3: kis-api/score-engine (`price:{code}`, `prices:last_update`)
|
||
- db=4: news-collector (`news:naver:{hash}`)
|
||
- db=5: ta-engine (`ta:{code}`)
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/aux-signal/main.py`
|
||
보조 데이터 수집. 포트 8282.
|
||
|
||
| 엔드포인트 | 역할 |
|
||
|-----------|------|
|
||
| `POST /collect/naver` | 네이버 integration API → 컨센서스 + 기관/외국인 일별 수급 |
|
||
| `POST /collect/macro` | 한국은행 ECOS → USD/KRW 환율, 국고채 10년 |
|
||
| `GET /consensus/{code}` | 종목 컨센서스 (목표가/투자의견) |
|
||
| `GET /flow/{code}` | 기관/외국인 일별 순매수 |
|
||
| `GET /macro/latest` | 최신 매크로 지표 |
|
||
| `GET /macro/{indicator}` | 지표별 시계열 |
|
||
|
||
스케줄: 영업일 18:00 네이버 수급/컨센서스, 08:30 ECOS 매크로.
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/us-market/main.py`
|
||
미국증시 동조 시그널. 포트 8383.
|
||
|
||
| 엔드포인트 | 역할 |
|
||
|-----------|------|
|
||
| `POST /collect` | Finnhub/AlphaVantage → 미국 ETF·개별주 가격 |
|
||
| `POST /collect/backfill` | 신규 페어용 과거 데이터 백필 |
|
||
| `POST /collect/yfinance-backfill` | yfinance 폴백 백필 |
|
||
| `POST /signal/calculate` | 페어 회귀로 한국 종목별 미증시 시그널 산출 |
|
||
| `GET /signal/{kr_code}` | 한국 종목 KR 코드별 시그널 |
|
||
| `GET /signal/latest` | 전체 종목 최신 시그널 |
|
||
| `GET /pairs` | 등록된 KR↔US 페어 |
|
||
| `POST /pairs/recalc-beta` | 60일 회귀 베타 재계산 |
|
||
| `POST /pairs/discover` | KOSPI200 × S&P500 상관 자동 발굴 |
|
||
| `GET /etfs` / `GET /etfs/{etf}/latest` | 섹터 ETF 현황 |
|
||
|
||
**기여 점수**:
|
||
- 섹터 ETF 동조 (SOXX/XBI/LIT 등 14개) → 같은 한국 섹터 ±5점
|
||
- 개별 페어 60일 회귀 베타 (NVDA↔SK하이닉스 등) → ±10점
|
||
|
||
스케줄: 매일 KST 07:30 수집, 08:00 시그널 계산.
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/graph-engine/main.py`
|
||
GAT 그래프 신경망 (PyTorch). 포트 9090.
|
||
|
||
| 엔드포인트 | 역할 |
|
||
|-----------|------|
|
||
| `POST /graph/build` | 노드/엣지 재구성 |
|
||
| `POST /train` | 학습 (6mo rolling) |
|
||
| `POST /predict` | 전체 추론 → `stock_scores.graph_score` |
|
||
| `GET /predict/{code}` | 종목별 예측 값 |
|
||
| `GET /status` | 모델/학습 상태 |
|
||
|
||
- **노드**: 활성 종목, 12피처 (1d/5d/20d 수익률, vol_ratio, RSI, tech_score, ROE, 영업이익률, 부채비율, 7d 뉴스, 미증시 overnight, log_mcap)
|
||
- **엣지**: ① 60일 가격 상관 |corr|≥0.4 ② 동일 섹터 ③ 뉴스 공기 ≥3회
|
||
- **스케줄**: 일요 06:00 학습 / 매일 08:30 추론
|
||
- **모델 저장**: `/mnt/nas/models/graph/`
|
||
|
||
---
|
||
|
||
### `/home/kyu/trading/telegram-bot/main.py`
|
||
텔레그램 명령 처리 봇 (python-telegram-bot).
|
||
|
||
| 명령 | 역할 |
|
||
|------|------|
|
||
| `/start /help` | 도움말 |
|
||
| `/buy /buys` | 강력매수/매수관심 톱 N |
|
||
| `/sell /sells` | 매도관심/강력매도 톱 N |
|
||
| `/stock <코드>` | 종목 점수·신호 요약 |
|
||
| `/deep <코드>` | RAG+EXAONE 심층분석 결과 |
|
||
| `/market` | 시장 요약(섹터·매크로) |
|
||
|
||
권한: `TELEGRAM_CHAT_ID` 일치 채팅만 응답.
|
||
|
||
---
|
||
|
||
## 데이터베이스 스키마 (PostgreSQL)
|
||
|
||
### `news_analysis`
|
||
```
|
||
id, title, url, source, published_at, hash(16자 UNIQUE)
|
||
sentiment(호재/악재/중립), intensity(1~5), primary_stock
|
||
affected_stocks(JSONB), reason, investment_action(매수관심/매도관심/관망)
|
||
keywords(JSONB), stock_names(JSONB), stock_codes(JSONB)
|
||
similar_count, catalyst, analyzed_at, created_at
|
||
```
|
||
|
||
### `stock_technical`
|
||
```
|
||
stock_code(UNIQUE), stock_name, price
|
||
ma5, ma20, ma60, ma120, rsi, macd, macd_signal, macd_hist
|
||
bb_upper, bb_mid, bb_lower, pct_b, stoch_k, stoch_d
|
||
vol_ratio, tech_score(-100~100), signal(매수/매도/관망)
|
||
obv, obv_trend, vwap20, ichimoku(JSONB) ← 새 지표
|
||
signals(JSONB), targets(JSONB), analyzed_at
|
||
```
|
||
|
||
### `dart_corps`
|
||
```
|
||
stock_code(PK), corp_code, corp_name, modify_date, is_active
|
||
※ is_active=true 필터 필수 (상장폐지 제외)
|
||
```
|
||
|
||
### `dart_financials`
|
||
```
|
||
stock_code, corp_code, corp_name, bsns_year, reprt_code
|
||
revenue, operating_profit, net_income
|
||
total_assets, total_liabilities, total_equity, operating_cashflow
|
||
roe, operating_margin, net_margin, debt_ratio, revenue_growth, fcf_ratio
|
||
UNIQUE(stock_code, bsns_year, reprt_code)
|
||
※ F-Score는 전년 11011 사업보고서 필요 → years≥2 백필
|
||
```
|
||
|
||
### `stock_scores` (주요 컬럼)
|
||
```
|
||
stock_code, score_date, total_score, recommendation
|
||
news_score, dart_score, technical_score, foreign_score, short_score, price_score
|
||
trend_score, intrinsic_value, margin_of_safety, earnings_quality
|
||
magic_score, f_score, roc_pct, earnings_yield_pct
|
||
altman_z, peg, momentum_pct, beneish_score
|
||
gpa_pct, g_score, amihud_illiq, market_beta ← 학술 논문 기반 4개
|
||
signals(JSONB), buy_votes, sell_votes
|
||
position_size_pct, volatility_60d, market_regime_adj, sector
|
||
top_reasons, UNIQUE(stock_code, score_date)
|
||
```
|
||
|
||
### `weight_config`
|
||
```
|
||
config_date(PK), weights(JSONB), period_days, sample_size
|
||
※ 최신 row가 calculate_daily_scores에서 자동 로드 → ensemble_bonus 가중
|
||
```
|
||
|
||
### `pricing_model_v2` (가격예측 모델 학습 결과 저장)
|
||
```
|
||
id, model_date, segment, model_type(linear/rf/xgb), target(return_7d/30d/alpha_30d)
|
||
feature_names(JSONB), feature_importance(JSONB), coef(JSONB), intercept
|
||
r2_oos, ic_spearman, hit_ratio, sample_size, period_days, model_blob(bytea), created_at
|
||
※ /learn-pricing 호출 시 모델별 row 갱신, /predict-price가 model_blob 역직렬화로 추론
|
||
```
|
||
|
||
### `news_raw` (수집/분석 분리용 임시 저장소)
|
||
```
|
||
id, stock_code, title, url, url_hash(UNIQUE), source,
|
||
published_at_text, collected_at, processed(BOOL), processed_at
|
||
※ 크롤러는 raw만 빠르게 저장 → 야간 cron(process_raw)이 batch로 LLM 분석
|
||
```
|
||
|
||
### 뷰
|
||
- `v_recent_signals` — 최근 24시간 호재/악재 (intensity DESC)
|
||
- `v_stock_news_count` — 종목별 7일 뉴스 감성 카운트
|
||
|
||
---
|
||
|
||
## 환경변수 키 목록 (.env)
|
||
|
||
```
|
||
POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB=trading_ai POSTGRES_USER=kyu
|
||
REDIS_MAX_MEMORY=2gb REDIS_MAXMEMORY_POLICY=allkeys-lru
|
||
OLLAMA_NUM_PARALLEL=4 (EXAONE→GPU0, bge-m3→GPU1 자동 분배)
|
||
QDRANT_COLLECTION=news_vectors QDRANT_VECTOR_SIZE=1024
|
||
TELEGRAM_CHAT_ID=8690666445
|
||
KIS_IS_PAPER=true (모의투자 모드)
|
||
ECOS_API_KEY=... (한국은행 매크로 — ecos.bok.or.kr/api 무료)
|
||
```
|
||
|
||
---
|
||
|
||
## 자주 쓰는 명령어
|
||
|
||
```bash
|
||
# 전체 상태
|
||
docker compose ps
|
||
|
||
# 특정 서비스 로그 (실시간)
|
||
docker logs trading-news-collector --tail 50 -f
|
||
docker logs trading-score-engine --tail 50 -f
|
||
docker logs trading-n8n --tail 30
|
||
|
||
# 재빌드+재배포
|
||
docker compose build <service> && docker compose up -d <service>
|
||
|
||
# PostgreSQL 쿼리 (DB명: trading_ai, user: kyu)
|
||
docker exec trading-postgres psql -U kyu -d trading_ai -c "SELECT ..."
|
||
|
||
# Redis
|
||
source /home/kyu/trading/.env && docker exec trading-redis redis-cli -a $REDIS_PASSWORD
|
||
|
||
# n8n 마이그레이션 확인
|
||
docker exec trading-postgres psql -U kyu -d trading_ai -c "SELECT COUNT(*) FROM n8n.migrations;"
|
||
|
||
# 추천 종목 조회
|
||
docker exec trading-postgres psql -U kyu -d trading_ai -c "
|
||
SELECT s.stock_code, d.corp_name, s.total_score, s.recommendation,
|
||
s.magic_score, s.f_score, s.roc_pct, s.earnings_yield_pct
|
||
FROM stock_scores s JOIN dart_corps d ON d.stock_code=s.stock_code
|
||
WHERE d.is_active=true AND s.score_date=CURRENT_DATE
|
||
ORDER BY s.total_score DESC LIMIT 10;"
|
||
|
||
# 다년치 사업보고서 백필 (F-Score / PEG용)
|
||
curl -X POST 'http://localhost:8888/collect/financials?count=3000&years=10&annual_only=true'
|
||
|
||
# 섹터 정보 채우기 (dart_corps.sector)
|
||
curl -X POST http://localhost:8888/collect/sectors
|
||
|
||
# 점수 수동 재계산 (전체 활성종목 대상)
|
||
curl -X POST http://localhost:8686/score/calculate
|
||
|
||
# 백테스트 기반 공식 가중치 학습
|
||
curl -X POST 'http://localhost:8686/learn-weights?days=90'
|
||
|
||
# 현재 가중치 조회
|
||
curl -s http://localhost:8686/learn-weights
|
||
|
||
# 종목별 6공식 신호 확인
|
||
docker exec trading-postgres psql -U kyu -d trading_ai -c "
|
||
SELECT stock_code, stock_name, total_score, signals
|
||
FROM stock_scores WHERE score_date=CURRENT_DATE
|
||
ORDER BY total_score DESC LIMIT 10;"
|
||
```
|
||
|
||
---
|
||
|
||
## 주의사항
|
||
|
||
- **상장폐지 필터**: 모든 추천 쿼리에 `JOIN dart_corps d ON d.stock_code=... WHERE d.is_active=true` 필수
|
||
- **fstab**: NAS 마운트는 반드시 한 줄로 작성, `nfsvers=3` 필수
|
||
- **GPU**: Ollama 단일 컨테이너가 GPU0(EXAONE 추론)·GPU1(bge-m3 임베딩) 동시 사용. `runtime: nvidia` 필요
|
||
- **KIS**: 현재 모의투자 모드 (`KIS_IS_PAPER=true`)
|
||
- **바른API**: KRX→Naver 폴백으로 ~3768 종목 로드. 형태소 실패 시 공백분리 폴백
|
||
|
||
---
|
||
|
||
## 현재 이슈 / TODO
|
||
|
||
- [ ] fstab NAS 항목이 두 줄로 분리됨 — sudo로 직접 수정 필요
|
||
- [x] n8n 워크플로우 재구성 완료 (워크플로우 16개 / 활성 14개)
|
||
- [x] vLLM 제거 → Ollama 단일 운영으로 전환 (EXAONE 3.5 7.8B + bge-m3)
|
||
- [x] n8n DB 마이그레이션 오류 수정 완료 (51개 마이그레이션 등록)
|
||
- [x] SSL 인증서 자동 갱신 설정 완료 (certbot.timer + deploy hook → nginx reload)
|
||
도메인: al/cla/n8/pns/tr.kyleyang.co.kr, 훅: /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
|
||
|
||
---
|
||
|
||
## Behavioral Guidelines (LLM 공통 실수 감축)
|
||
|
||
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
|
||
|
||
Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.
|
||
|
||
### 1. Think Before Coding
|
||
Don't assume. Don't hide confusion. Surface tradeoffs.
|
||
|
||
Before implementing:
|
||
|
||
- State your assumptions explicitly. If uncertain, ask.
|
||
- If multiple interpretations exist, present them - don't pick silently.
|
||
- If a simpler approach exists, say so. Push back when warranted.
|
||
- If something is unclear, stop. Name what's confusing. Ask.
|
||
|
||
### 2. Simplicity First
|
||
Minimum code that solves the problem. Nothing speculative.
|
||
|
||
- No features beyond what was asked.
|
||
- No abstractions for single-use code.
|
||
- No "flexibility" or "configurability" that wasn't requested.
|
||
- No error handling for impossible scenarios.
|
||
- If you write 200 lines and it could be 50, rewrite it.
|
||
|
||
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
||
|
||
### 3. Surgical Changes
|
||
Touch only what you must. Clean up only your own mess.
|
||
|
||
When editing existing code:
|
||
|
||
- Don't "improve" adjacent code, comments, or formatting.
|
||
- Don't refactor things that aren't broken.
|
||
- Match existing style, even if you'd do it differently.
|
||
- If you notice unrelated dead code, mention it - don't delete it.
|
||
|
||
When your changes create orphans:
|
||
|
||
- Remove imports/variables/functions that YOUR changes made unused.
|
||
- Don't remove pre-existing dead code unless asked.
|
||
|
||
The test: Every changed line should trace directly to the user's request.
|
||
|
||
### 4. Goal-Driven Execution
|
||
Define success criteria. Loop until verified.
|
||
|
||
Transform tasks into verifiable goals:
|
||
|
||
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
||
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
||
- "Refactor X" → "Ensure tests pass before and after"
|
||
|
||
For multi-step tasks, state a brief plan:
|
||
|
||
```
|
||
1. [Step] → verify: [check]
|
||
2. [Step] → verify: [check]
|
||
3. [Step] → verify: [check]
|
||
```
|
||
|
||
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
||
|
||
These guidelines are working if: fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
|