[STK7-02] ML — 호재 테마 연관 종목 추천

작업 내용 (설계 의도)

변경 사항

최근 관심종목 뉴스 헤드라인에서 우세 테마를 추출하고, 정적 매핑(THEME_MAPPING)을 기반으로 연관 종목 체인을 추천하는 GET /theme-recommendations 엔드포인트를 신규 추가한다.

v1은 정적 JSON 매핑으로 구현한다. 키워드 기반 테마 추출 + 정적 종목 매핑으로 빠른 응답을 보장한다.

정적 테마 매핑 초기 목록:

테마 키키워드대표 연관 종목 (symbol)
AI_SERVERAI, GPU, 데이터센터, 엔비디아, NVDANVDA, AMD, 000660, 005930
PHYSICAL_AI피지컬AI, 로봇, 자율주행, humanoid005380, 012330, 003620, TSLA
SEMICONDUCTOR반도체, 파운드리, HBM, TSMC005930, 000660, TSM, AMAT
SECONDARY_BATTERY2차전지, 배터리, 전기차, LFP373220, 086520, 247540, TSLA
BIO_PHARMA바이오, 신약, 임상, FDA068270, 207940, 326030

응답 구조

[
  {
    "theme": "AI_SERVER",
    "reason": "AI 서버 수요 급증 관련 뉴스 감지",
    "stocks": [
      {"symbol": "NVDA", "name": "NVIDIA", "relation": "AI GPU 핵심 공급자"},
      {"symbol": "000660", "name": "SK하이닉스", "relation": "HBM 메모리 공급"}
    ]
  }
]

다이어그램

처리 흐름

sequenceDiagram
    participant C as Client
    participant ML as main.py
    participant TH as theme_chain.py
    participant BE as BE /api/v1/watchlist/news

    C->>ML: GET /theme-recommendations
    ML->>BE: GET /api/v1/watchlist (관심종목 목록)
    BE-->>ML: [{symbol, ...}]
    ML->>BE: GET /api/v1/watchlist/{symbol}/news (헤드라인)
    BE-->>ML: headlines[]
    ML->>TH: extract_theme(headlines)
    TH-->>ML: matched_themes[]
    ML->>TH: get_related_stocks(theme)
    TH-->>ML: [{symbol, name, relation}]
    ML-->>C: [{theme, reason, stocks}]

클래스 의존

flowchart LR
    main["main.py\n/theme-recommendations"] --> theme_chain["theme_chain.py"]
    theme_chain --> THEME_MAPPING["THEME_MAPPING (dict)"]
    theme_chain --> extract_theme["extract_theme()"]
    theme_chain --> get_related_stocks["get_related_stocks()"]

테스트 케이스

  • extract_theme(["AI 서버 수요 급증, 엔비디아 어닝 서프라이즈"])["AI_SERVER"] 반환된다
  • extract_theme([])[] 반환된다 (빈 헤드라인)
  • extract_theme(["일반 경제 뉴스"])[] 반환된다 (매핑 키워드 없음)
  • get_related_stocks("AI_SERVER") → 1종목 이상 반환된다
  • get_related_stocks("UNKNOWN_THEME")[] 반환된다
  • 복수 테마 감지 시 confidence 높은 순으로 정렬된다
  • GET /theme-recommendations 정상 응답 → 200, [{theme, reason, stocks}] 형식 준수
  • 관심종목 없거나 헤드라인 없을 때 → 200, [] 반환 (graceful)
  • 관심종목 BE 호출 실패 시 → 200, [] 반환 (graceful, 에러 전파 금지)