종목 추천 TDD

Background

PRD 참조. 시그널 파이프라인을 재사용해 후보군을 스코어링·랭킹하고 진입가·시점을 제안한다. 백테스트로 유효성을 검증한다. ml/ 서비스(:8000)에 모듈 추가.

Overview

  • 신규 모듈: recommendation.py, backtest.py. 신규 엔드포인트: GET /recommendations, GET /backtest/{symbol}.
  • 신규 BE는 없음 — 알림 등록은 POST /api/v1/alerts 재사용.

Terminology

PRD를 따른다.

Define Problem

AS-IS

  • 단일 종목 시그널만 존재. 후보 선정·검증 없음.

TO-BE

  • 후보 병렬 스코어링 → 필터·랭킹 → 진입 제안, 워크포워드 백테스트.

Possible Solutions

방안 비교

방안설명채택미채택 사유
후보 병렬 스코어링ThreadPoolExecutor(5)로 시그널 동시 계산
순차 스코어링후보 N개를 직렬 호출claude 호출이 느려 직렬 시 응답 지연 큼
진입가=현재가 고정단순추격매수 위험. 지지/되돌림 기반이 정보량↑
감성 포함 백테스트과거 시점 감성 복원과거 헤드라인 시계열 API 없음(룩어헤드·복원 불가)

Detail Design

추천 흐름

후보 = watchlist(BE GET /api/v1/watchlist, timeout 5s, 실패 시 []) ∪ CURATED_SYMBOLS
점수 = ThreadPoolExecutor(max_workers=5) → _safe_signal(symbol)  # 실패 종목 제외
필터 = composite_score > 0.15
랭킹 = 내림차순, 상위 limit
각 종목 = suggest_entry()

suggest_entry 규칙

조건entry_pricetiming
current ≤ MA20current”즉시 분할 매수 고려”
current > MA20max(MA20, recent_low)“눌림목(되돌림) 대기”
composite ≥ 0.5(위 진입가 유지)접두사 “강세 — “

백테스트 (워크포워드)

warmup = 20 (초기 스킵)
for t in [20, len-horizon-1]:
    momentum = score(prices[0:t+1])      # 룩어헤드 없음
    ret = (prices[t+horizon] - prices[t]) / prices[t]
overall_win_rate  = 양수 ret 비율 (전체)
signal_win_rate   = 양수 ret 비율 (momentum > 0.15 구간)
edge = signal_avg_return - overall_avg_return
note: 뉴스 감성 미포함 — 기술 모멘텀만 검증

Sequence Diagram — 추천

sequenceDiagram
    participant C as Client
    participant M as main.py
    participant BE as backend watchlist
    participant P as ThreadPool
    participant R as recommendation
    C->>M: GET /recommendations?limit
    M->>BE: GET /api/v1/watchlist (graceful)
    BE-->>M: symbols (또는 실패→[])
    M->>P: _safe_signal(symbol) ×N 병렬
    P-->>M: signals
    M->>R: rank(filter>0.15, sort, top-N)
    M->>R: suggest_entry(each)
    M-->>C: recommendations[]

ERD

영속 스토리지 없음. watchlist는 BE에서 조회, 시세·캔들은 토스에서 조회.

Testing Plan

  • recommendation.py: 진입가 규칙(current ≤ MA20 → 즉시 매수 / current > MA20 → 눌림목 대기), 강세 접두사(composite ≥ 0.5), 필터(> 0.15) 및 내림차순 정렬 검증
  • backtest.py: 워크포워드 룩어헤드 배제 확인, 승률(overall/signal) 및 edge 계산 정합성 검증
  • main.py (통합): watchlist 조회 실패 시 큐레이션만으로 정상 추천 반환 검증
  • 외부 호출(claude·토스 API·BE watchlist)은 pytest mocking으로 처리
  • edge 음수·samples=0 등 엣지케이스 포함

Release Scenario

  1. 시그널 서비스에 모듈·엔드포인트 추가 후 재기동.
  2. BACKEND_BASE_URL로 BE watchlist 연동(없어도 graceful).
  3. 롤백: /recommendations·/backtest 라우터 비활성. 알림 등록은 기존 API라 영향 없음.

Observability

관측 포인트방법임계 / 조건
병렬 스코어링 실패 종목로그 WARN skipped symbol={symbol} reason={e}실패율 > 50% 시 추천 결과 0건 위험
BE watchlist 조회 실패로그 WARN watchlist fetch failed, using curated only매 요청마다 발생하면 BE 연동 점검
/recommendations 응답 시간로그 응답 ms> 10s 시 ThreadPool 병목 의심
/backtest samples=0로그 INFO backtest samples=0 symbol={symbol}lookback 파라미터·데이터 부족 여부 확인
edge < 0결과 note에 한계 노출 (이미 명시)운영 알림 불필요, 데이터 투명 공개 목적

FE 영향 분석

  • RecommendationCard(진입가 자동 알림: targetPrice=entry, direction=BELOW), BacktestSummary.
  • 추천/백테스트는 ML 직접 호출, 알림 등록은 BE POST /api/v1/alerts 재사용.

Project Information

항목내용
담당자biuea
일정2026-06-19 착수
티켓 수7개 (STK3-01 ~ STK3-07)
신규 BE없음 (기존 API 재사용)
신규 ML 모듈recommendation.py, backtest.py
신규 엔드포인트GET /recommendations, GET /backtest/{symbol}

Document History

날짜변경 내용작성자
2026-06-19최초 작성 (Background~Release Scenario)biuea
2026-06-19Observability 상세화, Project Information·Document History 추가biuea
2026-06-21스킬 포맷 통일 (클래스 역할 표 제거, Testing Plan bullet 변환, Phase 표현 제거)biuea

관련 문서