이번 세션 외 그간 쌓인 변경 일괄 저장: - 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>
28 KiB
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 소스 목록 |
파이프라인 순서 (함수 내부):
- 바른API
/analyze→ 형태소분석 + 종목감지 - Ollama
bge-m3→ 1024차원 임베딩 - Qdrant → 코사인 유사도 ≥0.92 중복 제거
- Ollama
exaone3.5:7.8b(GPU0) → 호재/악재/중립 + intensity(1~5) + catalyst분류 - 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개는 데이터 부재로 생략):
- ROA(NI/총자산) > 0 2. CFO > 0 3. ΔROA > 0 4. CFO > NI
- Δ부채비율 < 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 무료)
자주 쓰는 명령어
# 전체 상태
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로 직접 수정 필요
- n8n 워크플로우 재구성 완료 (워크플로우 16개 / 활성 14개)
- vLLM 제거 → Ollama 단일 운영으로 전환 (EXAONE 3.5 7.8B + bge-m3)
- n8n DB 마이그레이션 오류 수정 완료 (51개 마이그레이션 등록)
- 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.