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)
| 필드 | 타입 | 필수 | 기본 | 설명 |
|---|---|---|---|---|
symbol | string (1–32) | Y | — | 자유 형식 (AAPL, BTC/USDT, KS:005930). 자산군은 AssetClass.from_symbol로 자동 추론 |
mode | quick|standard|full | N | standard | 분석 깊이 |
inline | bool | N | false | true 시 동기 실행 (mode=quick만 허용) |
priority | int (-1000–1000) | N | 0 | 큐 우선순위 (큐 모드에서만) |
응답 202 (AnalyzeResponse)
{
"report_id": "0c3a5b4f-1234-...",
"queue_id": 142,
"status": "queued"
}
- inline=true 시
queue_id=null,status는done/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_class | crypto|us_equity|kr_equity | — | 자산군 필터 |
symbol | string | — | 정확 일치 |
from | datetime (ISO) | — | requested_at >= from |
to | datetime (ISO) | — | requested_at <= to |
page | int (≥1) | 1 | 1-based |
size | int (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게이트로 일일 예산을 강제