Files
web-page-backend/docs/superpowers/specs/2026-05-31-stock-holdings-intelligence-design.md
gahusb 2996cf16d1 docs(spec): 주식 보유종목 인텔리전스 설계
스크리너 엔진을 보유종목에 restrict 적용 + 신규 매도/리스크 룰 +
이슈 감지(급변·거래량·외인·뉴스 LLM) + 포트 건강 → 매일 advisory 브리핑.
EOD 일봉 + 장중 경량 가드, KIS 실주문 미사용. 기존 screener/snapshot/
news_sentiment/portfolio 재활용, 신규 데이터소스 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 21:25:21 +09:00

9.4 KiB
Raw Blame History

주식 보유종목 인텔리전스 — 설계 Spec

  • 작성일: 2026-05-31
  • 상태: 설계 승인 (구현 plan 대기)
  • 대상 서비스: stock + agent-office(StockAgent) + web-ui(stock/포트폴리오 페이지)
  • 사이클: 스마트 에이전트 고도화 3종 중 2번 주식. (1번 로또 완료, 3번 인스타 후속)

1. 배경 & 목표

현재 StockAgent는 아침 뉴스 요약(07:30) · KRX 강세주 스크리너(16:30) · AI 뉴스 sentiment(08:00)를 브리핑한다. CEO는 여기서 더 나아가 내 보유종목을 집중 분석해 ①종목별 매수/매도 자세 ②이슈 정리 ③포트폴리오 건강을 매일 advisory로 브리핑받길 원한다.

핵심 결정 (2026-05-31 brainstorming)

  1. 실행 수준 = 브리핑 전용(advisory). /api/trade/order(KIS 실주문) 미사용. 매수/매도는 "제안"만, 실제 주문은 사용자 수동. (로또와 동일한 정직·관찰 철학)
  2. 분석 주기 = 일봉 EOD + 장중 경량 가드. 장마감 후 일봉으로 기술분석 → 다음날 아침 브리핑. 장중엔 현재가로 손절·급변(±N%)만 경도 알림. 인트라데이 분봉 파이프라인 신설 안 함.
  3. 브리핑 범위 = 보유종목 + 포트 레벨. 종목별 액션 + 포트폴리오 건강(집중도·비중·현금·손익).
  4. 이슈 소스 = 기존 뉴스+감성+LLM 요약 + 급변·거래량·외인수급 이벤트. 신규 스크래핑 0 (DART·실적 일정 제외).

기존 자산 (100% 재활용, 신규 ML/데이터소스 없음)

  • stock/app/screener/snapshot.pykrx_daily_prices(일봉 OHLCV) + krx_master(listing) + naver 외인 flow. 스크리너 잡(평일 16:30)이 갱신.
  • stock/app/screener/engine.py + nodes/(ma_alignment·momentum·rs_rating·vcp_lite·volume_surge·foreign_buy·high52w·hygiene). ScreenContext.restrict(tickers) + latest_close()/latest_high()로 보유종목 한정 분석 가능.
  • portfolio 테이블(broker·ticker·name·quantity·avg_price·purchase_price) + /api/portfolio(현재가·손익 계산) + broker_cash(예수금).
  • price_fetcher(현재가 3분 TTL) · news_sentiment 테이블(종목별 감성) · ai_summarizer(Claude Haiku).

알려진 제약 (설계 반영)

  • 섹터 필드 없음: portfolio·krx_master에 sector 없음 → 섹터 편중은 best-effort(FDR StockListing의 Sector/Industry가 있으면 사용, 없으면 생략)이고, 시장(KOSPI/KOSDAQ)·종목 비중 집중도를 기본 지표로 사용.
  • KRX 외 종목(미국주 등): krx_daily_prices 밖 → 기술분석 불가, 뉴스·현재가·손익만 graceful 처리.
  • snapshot 히스토리 의존: MA200·52주 고점 노드는 ~1년 일봉 필요. 스크리너가 이미 이 노드들을 쓰므로 윈도우는 충족 가정(plan에서 lookback 확인 단계 포함).

2. 데이터 모델 & 컴포넌트

신규 테이블 holdings_signals (stock.db, 일별 종목 시그널 이력)

date        TEXT NOT NULL          -- KST 거래일
ticker      TEXT NOT NULL
name        TEXT
action      TEXT NOT NULL          -- 'add' | 'hold' | 'trim' | 'sell'
tech_score  REAL                   -- 매수강도(score 노드 가중합, 0~1 정규화)
exit_flags  TEXT NOT NULL DEFAULT '{}'  -- JSON {stop_loss,ma50_break,ma200_break,momentum_loss,take_profit,climax}
issues      TEXT NOT NULL DEFAULT '[]'  -- JSON [{type, severity, summary}]
close       INTEGER
pnl_rate    REAL                   -- 평단 대비 % (스냅샷 시점)
reasons     TEXT                   -- 액션 근거 텍스트
created_at  TEXT NOT NULL DEFAULT (datetime('now'))
PRIMARY KEY(date, ticker)          -- 멱등 upsert

추세/이력은 이 테이블에서 조회. 포트 레벨 요약은 on-the-fly 계산(별도 테이블 불필요).

신규 stock/app/holdings_intel.py (순수연산 중심, FastAPI 의존성 최소)

  • get_holdings() -> list[dict]portfolio 행 + 현재가(price_fetcher) + pnl_rate. KRX 여부 플래그(is_krx).
  • technical_posture(ctx_restricted, tickers) -> dict[ticker, score]ScreenContext.restrict(tickers)에 score 노드 실행 → 매수강도.
  • exit_rules(holding, prices_df, params) -> dict신규: 손절·MA이탈·모멘텀소멸·익절·클라이맥스 flag 산출 (§3).
  • decide_action(tech_score, exit_flags, pnl) -> (action, reasons)신규: 매수강도+exit 조합 → add/hold/trim/sell + 근거.
  • market_events(prices_df, flow, params) -> dict[ticker, list] — 급변(±N%)·거래량 Z-score·외인 순매도.
  • news_issues(tickers) -> dict[ticker, list] — news+news_sentiment 필터 → Claude Haiku 악재·심각도 요약(악재 있는 종목만).
  • portfolio_health(holdings, cash) -> dict — 종목 비중 집중도(HHI/최대비중)·시장 mix·현금 비중·총 손익.
  • compute_and_store(asof) -> dict — 위를 조합해 holdings_signals upsert (멱등).
  • build_holdings_brief(asof) -> dict — 브리핑/UI payload 조립(종목별 action+issues + portfolio_health + 추세).

API (stock)

메서드 경로 설명
GET /api/stock/holdings/intel 최신 브리핑 payload
GET /api/stock/holdings/intel/history?ticker=&days= 종목 시그널 추세
POST /api/stock/holdings/intel/run 수동 계산 트리거(BackgroundTask)

3. 매도/리스크 룰 & 이슈 (설정 가능 임계값 — 기본값 제시)

exit_flags (각 boolean + 값)

  • stop_loss: current < avg_price × (1 STOP_PCT) (기본 STOP_PCT=0.08, Minervini식)
  • ma50_break / ma200_break: 종가 < MA50 / MA200
  • momentum_loss: momentum/RS 노드 점수가 직전 대비 임계 하락 (or 음전환)
  • take_profit: pnl_rate ≥ TAKE_PCT (기본 25%) — 부분 익절 후보
  • climax: 거래량 급증(vol > avg×CLIMAX_VOL_X) + 종가 상단 꼬리 (분산 의심)

decide_action 매트릭스

  • tech_score 高 + exit_flags 無 → add(추가매수 후보)
  • exit_flags 無 (강건) → hold
  • ma50_break 또는 momentum_loss 또는 take_profit → trim(일부 축소)
  • stop_loss 또는 ma200_break → sell(청산 후보)
  • 각 결정에 trigger된 flag를 근거 텍스트로 동봉. (advisory — "제안")

issues

  • 시장이벤트 (기존 데이터): 일봉 ±EVENT_PCT% 급변 / 거래량 Z-score>임계 / naver flow 외인 순매도 N일 연속.
  • 뉴스이슈: 보유종목 최근 뉴스 + news_sentiment 음수 → Claude Haiku로 {type, severity(low/med/high), summary} 요약. 악재 있는 종목만 호출(비용 bounded).

4. 플로우 · 에이전트 · UI

  1. EOD 계산 (평일 16:40): 기존 스크리너/뉴스 잡과 동일하게 agent-office cron이 orchestrate_run_stock_holdings_eod()StockAgent.run_holdings_eod() → stock POST /api/stock/holdings/intel/runholdings_intel.compute_and_store(today) → holdings_signals upsert. 스크리너 snapshot 갱신(16:30) 직후라 일봉 준비됨.
  2. 아침 브리핑 (평일 08:30, agent-office StockAgent.run_holdings_brief): 저장된 최신 시그널 + 야간 갭(현재가) → 텔레그램 1통(종목별 액션 + 포트 건강 + 상위 이슈). AI 뉴스(08:00) 다음 슬롯.
  3. 장중 경량 가드 (평일 09:00~15:30, 30분 간격): 현재가로 손절선 이탈·급변(±N%)만 점검 → 발생 시 텔레그램 alert. throttle(종목·유형별 재발화 억제) + daily cap (로또 시그널 패턴 재활용).
  4. agent-office: service_proxy에 holdings intel 호출 추가 + StockAgent 메서드(run_holdings_brief / intraday_guard) + scheduler cron.
  5. UI (web-ui): stock/포트폴리오 페이지에 "보유종목 인텔리전스" 탭/섹션 통합 — 종목별 액션 카드(자세·exit flags·근거) + 포트 건강 위젯 + 이슈 피드 + 종목 시그널 추세(history).

5. 에러·성능·테스트·리스크

  • 멱등성: holdings_signals PRIMARY KEY(date,ticker) upsert → 재계산 안전.
  • 성능 (NAS Celeron): 보유종목만 restrict(소수 종목)이라 전체 스크리너 대비 매우 가벼움. LLM 이슈 요약은 악재 종목만(bounded). EOD 1회 + 장중 가드는 현재가만(경량).
  • graceful degrade: price_fetcher/KIS/news 실패 시 부분 데이터로 진행 + 경고 로그. KRX 외 종목은 기술분석 skip(뉴스·손익만). 텔레그램 실패는 로그만(job 성공 유지).
  • 테스트: exit_rules 각 flag, decide_action 매트릭스 전 분기, market_events 검출, portfolio_health 계산, holdings_signals 멱등, KRX 외 종목 graceful, 뉴스 0건 경로.
  • 리스크: ①기술적 시그널은 휴리스틱이지 보장 아님 → advisory 프레이밍·자동매매 없음 ②섹터 데이터 갭 → 시장·비중 집중도로 대체 ③snapshot 히스토리 의존 → plan에 lookback 확인 ④보유종목 출처는 portfolio 테이블(사용자/KIS 동기화) — 누락 시 빈 브리핑 graceful.

6. 결정 로그 (2026-05-31)

  1. 실행 수준 = advisory 전용 (KIS 실주문 미사용)
  2. 주기 = 일봉 EOD + 장중 경량 가드
  3. 범위 = 보유종목 + 포트 레벨
  4. 이슈 소스 = 기존 뉴스+감성+LLM + 급변·거래량·외인 이벤트

7. 스코프 밖 / 향후

  • 자동매매(승인후/완전자동), 인트라데이 분봉, DART 공시·실적 일정, 신규 매수후보 발굴(기존 16:30 스크리너가 담당), 교체(rotation) 제안 — 향후 사이클.
  • 인스타 에이전트(자율 카드 발급) — 다음 사이클.