본문으로 건너뛰기

Equity Analyze — /api/equity/{analyze,reports}

LLM 멀티 에이전트가 단일 종목을 분석하고 결과를 영속화하는 라우트입니다. 모든 라우트는 Authorization: Bearer <JWT> 필요.

공통

  • 베이스 경로: /api/equity
  • Feature flag: FEATURE_LLM_ANALYSIS 또는 FEATURE_EQUITY_ANALYSIS 중 하나가 ON
  • Rate limit: 분석은 사용자별 분당 5회 (token bucket)
  • 멀티유저 격리: WHERE user_id = current_user.id. 다른 user 보고서 접근 시 일관되게 404

POST /api/equity/analyze

분석 요청 제출. 큐 모드(기본) 또는 inline 모드(quick만 허용) 지원.

요청 (AnalyzeRequest)

필드타입필수기본설명
symbolstring (1–32)Y자유 형식 (AAPL, BTC/USDT, KS:005930). 자산군은 AssetClass.from_symbol로 자동 추론
modequick|standard|fullNstandard분석 깊이
inlineboolNfalsetrue 시 동기 실행 (mode=quick만 허용)
priorityint (-1000–1000)N0큐 우선순위 (큐 모드에서만)

응답 202 (AnalyzeResponse)

{
"report_id": "0c3a5b4f-1234-...",
"queue_id": 142,
"status": "queued"
}
  • inline=true 시 queue_id=null, statusdone/partial/failed 중 하나

에러

  • 400 — inline=true + mode != quick
  • 422 — INVALID_SYMBOL (등록되지 않은 심볼)
  • 429 — Rate limit 초과
  • 503 — FEATURE_DISABLED, 또는 inline 모드 미설정

cURL

curl -X POST http://localhost:8000/api/equity/analyze \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"symbol": "AAPL",
"mode": "standard",
"inline": false,
"priority": 0
}'

TypeScript

import { api } from '@/api/client';

const res = await api.post<{
report_id: string;
queue_id: number | null;
status: 'queued' | 'running' | 'done' | 'partial' | 'failed';
}>('/api/equity/analyze', {
symbol: 'AAPL',
mode: 'standard',
});

GET /api/equity/reports

호출자의 보고서 목록 (페이지네이션).

Query 파라미터

파라미터타입기본설명
asset_classcrypto|us_equity|kr_equity자산군 필터
symbolstring정확 일치
fromdatetime (ISO)requested_at >= from
todatetime (ISO)requested_at <= to
pageint (≥1)11-based
sizeint (1–100)20페이지 크기

응답 200 (ReportListResponse)

{
"items": [
{
"report_id": "0c3a5b4f-...",
"asset_class": "us_equity",
"symbol": "AAPL",
"mode": "standard",
"status": "done",
"score": 0.72,
"decision": "buy",
"confidence": 0.72,
"cost_usd": 0.0123,
"started_at": "2026-04-26T10:11:12Z",
"completed_at": "2026-04-26T10:11:53Z"
}
],
"total": 87,
"page": 1,
"size": 20
}

cURL

curl -H "Authorization: Bearer $JWT" \
"http://localhost:8000/api/equity/reports?asset_class=us_equity&page=1&size=20"

GET /api/equity/reports/{report_id}

단일 보고서 상세.

응답 200 (ReportDetail)

{
"report_id": "0c3a5b4f-...",
"asset_class": "us_equity",
"symbol": "AAPL",
"mode": "standard",
"status": "done",
"score": 0.72,
"decision": "buy",
"confidence": 0.72,
"cost_usd": 0.0123,
"started_at": "2026-04-26T10:11:12Z",
"completed_at": "2026-04-26T10:11:53Z",
"dashboard_md": "## 분석 요약 ...",
"technical_output": { "signal": "buy", "confidence": 0.7, "reasoning": "..." },
"intel_output": { "signal": "hold", "confidence": 0.5, "reasoning": "..." },
"risk_output": { "risk_level": "low", "veto_buy": false, "flags": [] },
"decision_output": {
"signal": "buy",
"ideal_buy": 188.20,
"secondary_buy": 184.50,
"stop_loss": 179.00,
"take_profit": 205.00,
"currency": "USD"
},
"error_message": null
}

에러

  • 404 — REPORT_NOT_FOUND (또는 다른 user 소유)

cURL

curl -H "Authorization: Bearer $JWT" \
http://localhost:8000/api/equity/reports/0c3a5b4f-1234-...

GET /api/equity/reports/{report_id}/traces

각 에이전트의 단계별 추론 trace.

응답 200 (TraceListResponse)

{
"report_id": "0c3a5b4f-...",
"items": [
{
"agent_name": "technical",
"step_index": 0,
"role": "assistant",
"content": "MA5/MA10 골든크로스 + 거래량 1.4x...",
"tokens_input": 1024,
"tokens_output": 512,
"latency_ms": 4823,
"created_at": "2026-04-26T10:11:18Z"
}
]
}

content는 구조화된 reasoning이 있으면 그것을, 없으면 raw_text를 fallback으로 사용합니다.

에러

  • 404 — 보고서 없음

cURL

curl -H "Authorization: Bearer $JWT" \
http://localhost:8000/api/equity/reports/0c3a5b4f-.../traces

DELETE /api/equity/reports/{report_id}

보고서를 cascade 삭제 (traces + queue rows 포함).

응답 204

본문 없음.

에러

  • 404 — 보고서 없음

cURL

curl -X DELETE -H "Authorization: Bearer $JWT" \
http://localhost:8000/api/equity/reports/0c3a5b4f-...

멀티유저 격리

  • _resolve_owned_report()user_id 필터를 강제 적용
  • 다른 user 보고서에 접근 시 모두 404 (403이 아닌 404로 리소스 존재 노출 방지)

비고

  • 큐 모드는 analysis_request_queue 테이블에 row를 적재하고 P2-06 워커가 picking
  • inline 모드는 app.state.equity_orchestrator_factory가 등록된 환경에서만 동작 (테스트/특수 환경)
  • 비용은 cost_usd 필드에 누적되며 LLM_BUDGET_EXCEEDED 게이트로 일일 예산을 강제