Skip to main content

Screener, Regime & Intraday API

Discovery + context + level inputs for strategy R&D: the screener family (candidate discovery by technical/options/fundamental/compression filters), the market regime surface (2×3-grid context plus GEX / volatility / Greeks), the intraday levels & profile that intraday strategies key off (VWAP, Initial Balance, Opening Range, pivots, volume-profile HVN/LVN, compression), and trade outcome analytics. Base path /api/graph/v1; internal Go→Python plumbing under /api/internal/intraday. Auth as in the README.
Most intraday session/position/signal endpoints are the live trading surface, not backtesting — R&D mainly cares about the levels/profile, volume-nodes, compression, screener, regime, and outcomes reads. They’re all listed for completeness.

Screener & Regime

Screener endpoints filter stocks by technical, fundamental, options, and market-context criteria to surface high-conviction opportunities. Regime endpoints provide market microstructure context—gamma exposure (GEX), volatility regimes, and options Greeks—using a canonical 2×3 grid (BULL/NEUTRAL/BEAR × LOW/HIGH_VOL) that gates strategy selection.

POST /api/graph/v1/screener

Screen stocks using graph-native filters with optional relationship expansion. Returns paginated results with confluence scoring, technical indicators, and optional price levels, volume profile, and news. Request: ScreenerRequest (filters, include options, sort, pagination) Response: ScreenerResponse (stocks: [StockResult], metadata: ScreenerMetadata) Caching: 15s during market hours, 60s off-hours (Redis) Query target: <500ms with includes, <200ms without

Filter contract: fail closed, never silently dropped (data#1606)

ScreenerRequest.filters (Filters, api/app/models/screener.py) and its 13 sub-filter models (PriceFilter, VolumeFilter, OptionsFilter, TechnicalFilter, FundamentalFilter, ConfluenceFilter, PulseFilter, EarningsFilter, PriceEventFilter, DarkPoolFilter, ConvictionFilter, ThemeFilter, plus Filters itself) all set model_config = {"extra": "forbid"} — an unknown/misspelled filter key is a 422 at parse time, not a silently-ignored field. ScreenerRequest’s own envelope carries the same extra="forbid". Beyond typo-rejection, every filter leaf the caller explicitly sets must either compile into a graph predicate or the whole request is rejected — a filter that is accepted by the schema but never wired into the query builder used to return the unfiltered universe while claiming it was narrowed (the original data#1606 defect). Enforcement is at the shared boundary (GraphService.screen_stocks via assert_all_filters_compilable, api/app/services/screener/screener_filters.py), so it applies uniformly to the HTTP route, the natural-language screener, and internal callers like ThesisScreener — not just this endpoint. A request naming an unwired leaf gets 422:
As of this writing, six leaves are accepted by the schema but not yet wired into the compiler, and are therefore always rejected if explicitly set: patterns, technical.compression, technical.atr_compression_max, price_events.event_types, price_events.min_severity, price_events.days. Notably, filtering by pattern (the top-level patterns list, or technical.compression) has no working path yet even though the pattern registry itself already uses the current nr7id identifier (NR7 was renamed from nr7) — the vocabulary rename is not the blocker, the missing compiler wiring is. Pin-tested exhaustively in api/tests/unit/test_screener_filter_fail_closed.py (EXPECTED_COMPILED/EXPECTED_UNSUPPORTED), which fails closed itself: a newly-added Filters field that isn’t classified in either set breaks the test rather than rotting silently.

POST /api/graph/v1/options/screener

Screen stocks with options-centric defaults (IV percentile, chain OI, put/call ratios, pricing edges, Greeks alignment). Convenience wrapper over the base screener. Request: ScreenerRequest · Response: ScreenerResponse

POST /api/graph/v1/research/screener

Screen stocks by fundamental metrics (market cap, PE, PB, PS, EV/EBITDA, margins, ROE/ROA, debt ratios, dividend yield, FCF yield). Request: ResearchScreenerRequest (filters: ResearchScreenerFilters, sort, pagination) Response: ResearchScreenerResponse (results: [ResearchScreenerResult], total_matched, returned, offset, query_ms)

POST /api/graph/v1/compression/screener

Screen for compression patterns (NR7, inside days, VCP contractions, Bollinger Band squeezes) with ATR-based contraction scoring. Request: CompressionScreenerRequest (days, min_nr7_count, is_nr7_today, min_inside_day_count, compression_level, max_atr_compression_ratio, min_vcp_contractions, limit, offset) Response: CompressionScreenerResponse (results: [CompressionScreenerResult], total_count, lookback_days)

POST /api/graph/v1/screener/top-setups

Batch fetch top bullish and bearish setups in one call. Filters by ADV30 ≥$50M and Pulse bias; results cached in-memory. Request: TopSetupsRequest (limit: 1–20, default 5) Response: (inferred from handler) {"bullish": ScreenerResponse, "bearish": ScreenerResponse, "errors": [str] | null}

GET /api/graph/v1/screener/sector-summary

Sector conviction aggregates for heatmap display. Groups stocks by sector and returns median conviction, median net confluence, and top movers by conviction delta. Response: SectorSummaryResponse (sectors: [SectorSummary], total_stocks, query_ms) · Caching: 60s (Redis)

POST /api/graph/v1/screener/nl

Translate natural language queries into structured screener filters via LLM (e.g. “oversold tech with high volume”). Request: NLScreenerRequest (query: str, regime_context: dict | null) Response: NLScreenerResponse (filters: ScreenerRequest, explanation: str)

GET /api/graph/v1/regime/current

Current market regime + signal-strength context. Returns the dominant regime classification and which signal types perform well (win_rate ≥50%, profit_factor ≥1.0) in the current regime. Response: (inferred from handler) {"current_regime": str, "timestamp": str | null, "strong_signals": [dict], "weak_signals": [dict], "performance": [dict]}

GET /api/graph/v1/regime/summary

All symbols — compact GEX + vol regime snapshot. Index ETFs (SPY, QQQ, IWM) with latest GEX regime, gamma flip strike, pin strike, vol regime, ATM IV, IV rank, term structure. Response: RegimeSummaryResponse (symbols: [RegimeSummaryItem], scheduler_running: bool, last_computation: str | null)

GET /api/graph/v1/regime//gex

Latest GEX snapshot. Optional expiration (YYYY-MM-DD) to filter to one expiry; omit for aggregate. Params: symbol (path), expiration (query, optional) · Response: GEXSnapshotResponse

GET /api/graph/v1/regime//gex/history

GEX snapshot history (up to 90 days). Params: symbol (path), days (query 1–90, default 30). Response: [GEXSnapshotResponse]

GET /api/graph/v1/regime//vol

Latest volatility regime classification (e.g. “low-vol”, “high-vol”, “vol-expanding”). Params: symbol (path). Response: VolRegimeSnapshotResponse

GET /api/graph/v1/regime//vol/history

Vol regime history (up to 90 days). Params: symbol (path), days (query 1–90, default 30). Response: [VolRegimeSnapshotResponse]

GET /api/graph/v1/regime//vanna-charm

Vanna-charm Greeks curve across strikes. Params: symbol (path), expiration (query, optional). Response: VannaCharmResponse

GET /api/graph/v1/regime//auction-history

Downsampled GEX auction history + summary (regime transitions, average GEX, dominant regime, flip-strike range). Params: symbol (path), hours (query 1–168, default 72), resolution (query enum 1min/5min/15min/1h, default 5min). Response: AuctionHistoryResponse

GET /api/graph/v1/regime/transitions/performance

Regime transition performance matrix — win rates, average returns, recommended actions per transition. Params: lookback (query enum 90d/1y/5y, default 1y), signal_type (query, optional). Response: (inferred) {"transition_matrix": dict, "raw": [dict], "lookback": str}

Intraday levels, volume nodes, compression & outcomes

These power the intraday research toolkit — institutional-grade levels (VWAP, Initial Balance, Opening Range, pivots), volume-profile nodes (HVN/LVN), volatility compression (NR7, inside day, VCP), and trade outcome metrics. The session / position / signal endpoints are the live-trading surface (listed for completeness); the levels/profile, volume-nodes, compression, and outcomes reads are what R&D consumes.

Session management (live trading surface)

  • POST /api/graph/v1/intraday/{symbol}/session — start session. Body StartSessionRequest (mode: monitor|supervised|autonomous, trading_mode: paper|live). → IntradaySessionResponse
  • GET /api/graph/v1/intraday/{symbol}/session — get current session (trading_mode query, default paper). → IntradaySessionResponse
  • POST .../session/stop · .../session/halt · .../session/resume — stop/pause/resume. → IntradaySessionResponse
  • POST .../session/mode — change mode mid-session. Body ModeChangeRequest. → IntradaySessionResponse
  • GET /api/graph/v1/intraday/sessions — all active sessions. → AllSessionsResponse
  • POST /api/graph/v1/intraday/sessions/stop-all — kill-switch stop all. → AllSessionsResponse
  • POST /api/graph/v1/intraday/sessions/bulk-start — bulk start. Body BulkStartRequest (items:[], trading_mode). → (inferred) {created, already_active, errors, results}

Position management (live trading surface)

  • POST .../{symbol}/position/{position_id}/tighten-stop — Body TightenStopBody (stop_price>0).
  • POST .../position/{position_id}/close — close at market.
  • POST .../position/{position_id}/close-partial — Body PartialCloseBody (quantity>0).
  • POST .../position/{position_id}/breakeven — move stop to entry.
  • POST .../position/{position_id}/mark-closed — Body MarkClosedBody (exit_price>0); monitor-mode manual close.

Signal & exit actions, close phase (live trading surface)

  • POST .../{symbol}/signal/{signal_id}/approve|skip|dismiss — supervised/monitor signal actions.
  • POST .../{symbol}/exit/approve|skip — exit-recommendation actions (position_id query).
  • POST .../{symbol}/close-now — close phase (15:30–15:45 ET) immediate close (position_id, trading_mode query).
  • POST .../{symbol}/mark-closed — close-phase monitor-mode mark (position_id, trading_mode query; Body MarkClosedTimeStopBody).

Real-time stream

  • GET /api/graph/v1/intraday/{symbol}/stream — SSE event stream (signal, position_opened/closed, phase_change, level_update); 30s heartbeat; Last-Event-ID replay. Content-Type text/event-stream.

Intraday user profile (wizard persistence)

  • GET /api/graph/v1/user/intraday-profile/IntradayProfileResponse
  • PUT /api/graph/v1/user/intraday-profile/ — upsert (UpsertIntradayProfileRequest) → IntradayProfileResponse
  • PATCH /api/graph/v1/user/intraday-profile/ — partial update (PatchIntradayProfileRequest) → IntradayProfileResponse

Signal statistics

  • GET /api/graph/v1/intraday/signal-stats — per-signal-type backtest metrics + live outcome counts (30d). → {signal_types: [{signal_type, backtest, live}]}
  • GET /api/graph/v1/intraday/signal-stats/{signal_type}/detail — equity curve (cumulative R), P&L distribution, exit-reason breakdown, recent signals. → (inferred) {signal_type, backtest_metrics, equity_curve, distribution, exit_reasons, recent_signals}

Disclaimer & privilege controls

  • GET .../intraday/disclaimer/statusDisclaimerStatusResponse
  • POST .../intraday/disclaimer/acknowledge — Body DisclaimerAckRequest (immutable, audit-logged).
  • GET .../intraday/disclaimer/contentDisclaimerContentResponse (public).
  • POST .../intraday/kill-switch — cancel orders / close positions / stop sessions (5/min). Body KillSwitchRequest.
  • POST .../intraday/disable — kill-switch + revoke intraday access. Body DisableIntradayRequest.
  • GET .../intraday/privilege-events — paginated privilege-change audit log.

Internal (localhost only, Go → Python — no auth)

  • POST /api/internal/intraday/{symbol}/signal — signal intake. Body IncomingSignal.
  • POST /api/internal/intraday/{symbol}/levels — level-snapshot persistence. Body IncomingLevelSnapshot.
  • POST /api/internal/intraday/exit-notification — partial/stop/full exit notifications.
  • POST /api/internal/intraday/close-phase/{session_id} — trigger close phase (15:30 ET).

Volume nodes (HVN/LVN)

  • GET /api/graph/v1/volume-nodes/{symbol} — detect HVN/LVN. Query: trade_date, session_type (prior|developing, default prior), hvn_threshold (0–3σ, default 1.0), lvn_threshold (-3–0σ, default -1.0), min_buckets (1–10, default 2). → VolumeNodesResponse. (HVN = support/resistance; LVN = breakout zones. <200ms; 503 if prior-session data stale.)
  • GET /api/graph/v1/volume-nodes/{symbol}/context — nodes + full profile context (POC/VAH/VAL, strongest HVN/LVN). Same query params. → VolumeNodeContext

Compression patterns

  • GET /api/graph/v1/stocks/{symbol}/compression — daily compression history (ATR ratio, BB-width pct, NR7/inside-day, VCP contractions, score). days (1–365, default 30). → CompressionHistoryResponse
  • GET /api/graph/v1/stocks/{symbol}/compression/stats — aggregated stats. → CompressionStats
  • GET /api/graph/v1/stocks/{symbol}/compression/trend — recent-vs-earlier trend (days 5–90, default 20). → CompressionTrendResponse
  • GET /api/graph/v1/stocks/{symbol}/compression/nr7-count — convenience NR7 count. → int
  • POST /api/graph/v1/compression/screener — compression screen (see Screener above). → CompressionScreenerResponse

Trade outcomes & analytics

  • GET /api/graph/v1/outcomes/signals/performance — hit rates / avg return / Sharpe proxy grouped by group_by (conviction_tier|signal_type|regime|regime_dominant|market_phase|time_bucket). Query: min_date, max_date, variant. → {groups, effective_date_range, variant_dimension, mixed_variants}
  • GET /api/graph/v1/outcomes/signals/slippage — avg decision/market/total slippage (bps) by group.
  • GET /api/graph/v1/outcomes/signals/regime — hit rate / avg return / directional accuracy per regime (min_conviction).
  • GET /api/graph/v1/outcomes/signals/funnel — status distribution + top blocked/gated reasons.
  • GET /api/graph/v1/outcomes/signals/contracts — hit rate/slippage by delta bucket × DTE bucket.
  • GET /api/graph/v1/outcomes/debates/performance — debate-recommendation hit rate by verdict/strategy.
  • GET /api/graph/v1/outcomes/alpha — cross-layer alpha attribution (horizon eod/1d/3d/5d). → {sources:[{source, hit_rate, avg_return, sharpe_proxy, n}], ...}

Key schemas

Levels (intraday institutional levels)

The level set intraday strategies key off (VWAP, IB, OR, pivots, volume profile):

VolumeNode

CompressionScreenerResult

GEXSnapshotResponse

VolRegimeSnapshotResponse

RegimeSummaryItem

IntradaySessionResponse

IncomingLevelSnapshot / IncomingSignal (Go → Python plumbing)

Full per-schema field listings for everything referenced here are in openapi.json under components.schemas.