[STK8-02] ML: 단기/중기/장기 horizon 예측 endpoint 추가

작업 내용 (설계 의도)

/portfolio-forecast/{symbol} 엔드포인트를 신설한다. 기존 build_prediction(5일 고정)을 확장하여 단기(14일), 중기(56일), 장기(182일) 예측을 주 단위로 집계하여 반환한다. 각 horizon마다 WeeklyForecastPoint 배열과 SellRecommendation(최고 예상 주차 + 가격)을 산출한다.

sigma 확산은 sigma × sqrt(d) 적용으로 장기 불확실성을 표현한다. 응답에 "⚠️ 기술적 모멘텀 기반 참고 시그널" 경고를 포함한다.

다이어그램

처리 흐름

sequenceDiagram
    participant A as Aggregator
    participant ML as FastAPI
    participant TC as TossClient
    A->>ML: GET /portfolio-forecast/{symbol}
    ML->>TC: get_closes(symbol, 60)
    TC-->>ML: closes[]
    ML->>ML: build_portfolio_forecast(closes, horizons=[14,56,182])
    ML-->>A: PortfolioForecastResult {short, mid, long}

클래스 의존

flowchart LR
    route["/portfolio-forecast/{symbol}"] --> build_portfolio_forecast
    build_portfolio_forecast --> build_prediction
    build_portfolio_forecast --> aggregate_weekly
    build_portfolio_forecast --> pick_sell_recommendation

테스트 케이스

  • 단기 응답에 weekly_points 2개(2주), 중기 8개(8주), 장기 26개(26주)가 반환된다
  • 각 WeeklyForecastPoint에 week, price, upper, lower 필드가 있다
  • SellRecommendation에 week, estimated_price, rationale 필드가 있다
  • 종가 데이터 5개 미만이면 422 오류가 반환된다
  • 알 수 없는 종목이면 404가 반환된다
  • 장기 upper − lower 범위가 단기보다 넓다 (sigma 확산 검증)
  • sell_week는 해당 horizon에서 predicted price가 최고인 주차다