Repository navigation
API
The app serves a JSON REST API plus one SSE stream. Every response body is a documented Pydantic model; this page walks through what each endpoint returns. Base URL when running locally: http://127.0.0.1:8000.
Run history and portfolio writes are scoped to an anonymous X-Client-ID header (the browser generates and stores one); without it, listings return empty.
| Method | Route | Purpose |
|---|---|---|
POST |
/api/analyze |
Start an analysis run for one or more tickers; incognito: true starts a market-only run (unattributed, nothing persisted, no portfolio access, no trading) |
GET |
/api/discover |
Rank liquid growth companies with a research-grounded momentum score and return up to five candidates |
GET |
/api/runs |
List saved analysis runs, newest first |
DELETE |
/api/runs |
Clear the current browser's finished run history |
GET |
/api/runs/{run_id} |
Read run status and complete results |
GET |
/api/runs/{run_id}/events |
Stream live progress over SSE |
POST |
/api/runs/{run_id}/cancel |
Cancel a running analysis, keeping finished ticker results (repeated requests are harmless) |
POST |
/api/runs/{run_id}/discard |
Forget an incognito run (sent when its page closes): cancels it if still running and drops the in-memory copy; persisted runs are refused |
POST |
/api/runs/{run_id}/chat |
Ask the portfolio manager follow-up questions about one ticker of a run |
GET |
/api/broker/status |
Alpaca paper connection state (configured, enabled, caps); never carries credentials |
GET |
/api/broker/account |
Mapped paper account snapshot (equity, cash, buying power, status); 503 with a setup hint when unconfigured. The paper account IS the portfolio: the manager and risk gate read their holdings from it |
GET |
/api/broker/positions |
Open paper positions with live P&L |
POST |
/api/broker/orders |
Place one paper order (run_id, ticker, side, notional, confirm: true); all guard rails run server-side |
GET |
/api/broker/orders |
Orders this app placed, newest first; non-terminal rows reconcile against Alpaca on read |
DELETE |
/api/broker/orders/{client_order_id} |
Cancel a non-terminal order; 422 passes through when it can no longer be canceled |
GET |
/api/broker/equity |
Paper-account equity timeseries ({dates, equity}) for the performance card |
GET |
/api/broker/performance |
Per filled order: return since fill and alpha vs SPY over the same window |
GET |
/api/broker/sync |
Last reconciliation sweep (checked_at, in_sync, reconciled, drift): open orders at the broker this app did not place; backs the portfolio page's out-of-sync banner, refreshed at most once a minute |
GET |
/api/price-history/{ticker} |
Six months of daily closes ({dates, closes}) for the price-context chart |
GET |
/api/health |
Check configuration and provider status |
curl -X POST http://localhost:8000/api/analyze \
-H "Content-Type: application/json" \
-d '{"tickers":["NVDA","AMD"],"outlook":"short_term","depth":"medium"}'The response is {run_id, tickers}; connect to /api/runs/{run_id}/events for progress, then read /api/runs/{run_id} for results.
Each ticker's entry in GET /api/runs/{run_id} (and in the ticker_completed SSE event's analysis field) carries:
Decision and trust state
-
decision,confidence: the final risk-adjusted call and its evidence strength. -
manager_decision,manager_confidence: the manager's own pre-gate call, preserved so a gate override renders asManager: BUY -> Final: HOLD. -
manager_probability: the manager's stated probability of beating SPY over the decision-memory horizon (P1.1's frozen success event); absent for HOLD. -
would_upgrade_if,would_downgrade_if: structured conditions for a different call, labeled as conditions, not alerts. -
data_quality: a server-computed object with the data timestamp, expected/available/failed/skipped analysts, an outlook-specific staleness flag, and provider fallbacks. -
providers,source_references: which provider produced each input, plus safe links to the underlying news articles and social threads.
Forecast
-
forecast_price_5d,forecast_change_5d_pct,forecast_method(timegpt-1or the local trend fit). -
forecast_band_pct: the ±1σ five-day move implied by the stock's own volatility, andforecast_z: the forecast as a multiple of that band. The manager prompt and the risk gate both consume this assessment.
Evidence
-
market,technical,fundamental,news,sentiment,forecast: oneAgentResultper researcher (signal, confidence, summary); which ones ran depends on the depth tier. -
bull,bear: the debate transcript (absent at Fast depth, which skips the debate). -
judge: the debate judge's calibrated bull/bear strengths and verdict (Max depth only). Old runs may still carry the deprecatedbull_rebuttal/bear_rebuttalfields.
Risk and cost
-
suggested_size_usd: the volatility-scaled position size. -
risk_flags: why a BUY was downgraded or confidence capped, if it was. -
token_usage: summed LLM tokens for this ticker's run. -
cost_estimate: the estimated model cost (see Architecture), with per-role model breakdown and an honestcost unknownstate for unpriced models.
Memory
-
past_decisions: graded prior calls on this ticker with realized return, SPY alpha, and a one-line verdict each. -
previous: a compact snapshot of the earlier completed call on this ticker (run id, decision, evidence strength, analyst signals, forecast, data age, risk flags), or absent on a first analysis. -
what_changed: one deterministic line per compared dimension versusprevious(decision, evidence strength, analyst signals, 5-day forecast, data freshness, risk flags). Structured field diffs only, never an LLM; empty withoutprevious.
GET /api/runs/{run_id}/events streams text/event-stream with JSON messages of the form {"type": ..., "ticker": ..., ...}:
| Event | When | Payload highlights |
|---|---|---|
ticker_started |
a ticker's analysis begins | ticker |
ticker_data |
market data fetched |
price, company_name, sources
|
agent_started / agent_completed / agent_failed
|
per-agent lifecycle |
agent, duration_s, signal, confidence, tokens
|
agent_token |
live reasoning chunk (only with STREAM_REASONING=1, live runs only) |
agent, text, truncated
|
ticker_completed |
one ticker finished | full analysis object, decision, confidence
|
ticker_failed |
a ticker aborted (e.g. market data failure) | error |
analysis_completed |
terminal event, always emitted exactly once, including after cancellation |
status, duration_s
|
GET /api/discover?outlook=short_term returns the five ticker symbols, the screen thresholds, the ranking method, cache status, and cache_ttl_seconds (3,600). The screen snapshot is cached in memory for an hour; failed or incomplete snapshots are never cached.
POST /api/runs/{run_id}/chat takes {ticker, messages} (up to 20 turns, 2,000 chars each) and returns {ticker, answer, mock_mode}. The manager persona answers grounded in that run's research; failed tickers return 409, missing runs 404, and oversized history 422. On an incognito run the dossier is built without a portfolio lookup, so the chat knows only the market research; a discarded incognito run 404s like any missing run.