Get Premarket Scan History
get_premarket_scan_historyBacktest premarket screens by scanning historical market-wide data for a past date: RVOL-ranked tickers with filters for market cap, price, float, and volume.
Instructions
Historical MARKET-WIDE premarket scan for a single PAST trade date. For the requested ET date, returns every ticker with that day's premarket (default) session volume and its relative volume (RVOL) vs the trailing 30-day same-session baseline — the SAME RVOL math as get_rvol_history, but across the whole market for one date instead of one ticker across many dates. Filter by RVOL, market cap, price, and float to backtest screens like "sub-$500M tickers with premarket RVOL > 5 on 2026-07-20" in one call. Rows are ranked by RVOL descending. A future or non-trading date returns an empty list with an explanatory reason (not an error). Every row also reports "baselineState" (why its RVOL is or is not null), "advRatio" (volume ÷ trailing 30-session average FULL-DAY volume) and "advDays"; set includeNoHistory=true to surface high-volume tickers that have no computable RVOL at all, such as first-session new listings. Each row ALSO publishes the RVOL denominator itself as "baselineVolume" (shares) plus a "baselineThin" flag (true when that denominator is under 200 shares): a 90x RVOL off a 1-share baseline is arithmetically correct and analytically worthless. That is almost entirely an asOfTime-basis effect (0.1% of full-session rows vs ~38% at the 04:30 cutoff, falling to ~9% by 09:15) and it skews to LIQUID LARGE CAPS that simply do not trade early, NOT to microcaps. Screen it out with minBaselineVolume and/or minSessionVolume. The response "meta" also reports asOfApplied / asOfIgnored / asOfIgnoredReason, so a time-of-day request that could not be honoured is visible instead of quietly returning full-session numbers. A price / market-cap / float filter can only be applied to a ticker company_screener_data holds a value for, so a just-renamed or just-listed symbol cannot be rated against it. Those rows are NEVER silently dropped: "meta.unscreened" always reports their count, the filter families involved and the tickers, and includeUnscreened=true returns them in "rows" tagged with "unscreenedFilters". Treat that tag as NOT MEASURED — the value is unknown, not out of range. Charged per your API tier.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| date | Yes | REQUIRED past ET trade date to scan (YYYY-MM-DD). Future/non-trade dates return an empty list. | |
| limit | No | Max rows to return (1–200, default 50). Rows are ranked by RVOL desc. | |
| offset | No | Pagination offset (default 0). | |
| minRvol | No | Minimum RVOL (day session volume ÷ trailing 30-day baseline). Drops rows whose baseline is not yet warm. | |
| session | No | Session bucket to scan (default premarket). "all" = full extended day. | |
| asOfTime | No | Optional TRUE time-of-day premarket basis. Any HH:MM ET premarket time; snapped to the nearest 15-minute grid cutoff (04:00–09:15, ties resolve to the earlier cutoff). When set, RVOL is cumulative premarket volume known BY that cutoff ÷ the trailing baselineDays (default 30) average of the SAME cutoff — a real time-of-day comparison, not the full 04:00–09:30 session. Each returned row carries a "basis" field: "asof-0700" (the snapped cutoff actually used) when a precomputed row exists, else "full-session" (automatic per-row fallback — the as-of series is forward-looking and may be sparse). Only applies to a premarket scan. Omit for full-session premarket volume. CHECK "meta.asOfApplied" (the SNAPPED cutoff actually used, or null) and "meta.asOfIgnored" / "meta.asOfIgnoredReason" ("date-not-covered" — the as-of grid has not been computed for this date, so the numbers are full-session; "non-premarket-session" — asOfTime only applies to a premarket scan; "unparseable"). Coverage is a set with HOLES that grows as the backfill runs, so do NOT assume any cutover date — read the meta per request. An unhonoured asOfTime is never an error, so this is the only reliable check. ALSO NOTE: this basis is where near-zero RVOL baselines come from — pair it with minBaselineVolume (see "baselineThin"). | |
| maxFloat | No | Maximum public float (shares). | |
| maxPrice | No | Maximum latest price in USD. | |
| minFloat | No | Minimum public float (shares). | |
| minPrice | No | Minimum latest price in USD. | |
| baselineDays | No | Rolling RVOL baseline window, in trading rows (same-session days). Default 30; values outside 20-250 are clamped. This is the DENOMINATOR window: every RVOL in the response is that period's volume divided by the average of the trailing N same-session (or same-cutoff) days, excluding the day itself. A SHORTER window tracks recent regime changes faster and is noisier; a LONGER one is smoother and slower to react. The warm-up lookback scales with it automatically, so a wide window is never under-filled into an inflated ratio; the minimum-warm-days gate (20 prior sessions) does NOT scale down, so at the 30-row default a ticker needs 20 of its last 30 sessions populated before rvol is non-null. Omit for the standard 30-day baseline; pass 90 for the pre-2026-09 window. | |
| maxMarketCap | No | Maximum market cap in USD (e.g. 500000000 for sub-$500M). | |
| minMarketCap | No | Minimum market cap in USD (market_cap_computed = price × shares outstanding). | |
| includeNoHistory | No | Also return the cohort minRvol structurally hides: tickers with NO computable RVOL. Two kinds, told apart by each row's "baselineState" — "no-history" (a new listing with no prior trading history at all, so RVOL is meaningless rather than merely missing; e.g. a stock that printed 20M shares on its first-ever session) and "no-cutoff-history" (an established ticker that simply never traded at this cutoff before — a genuine wake-up). Both come back with rvol=null and are ALWAYS ranked BELOW every real-RVOL row, ordered among themselves by "advRatio". Use "advRatio" (volume ÷ trailing 30-session average FULL-DAY volume, null when no full-day denominator exists) and "advDays" (its sample size) to size them — it is NOT an RVOL and is not comparable to one. Inert unless minRvol is set. Default false. | |
| minSessionVolume | No | Minimum RVOL NUMERATOR in shares — the scanned session's own volume. Answers "did enough actually trade to be worth acting on?", where minBaselineVolume answers "is the comparison meaningful at all?". USE BOTH IF YOU MEAN BOTH: neither subsumes the other (a 1,000-share floor here cuts thin-baseline rows from ~26% to ~3%, yet a name with an 860-share baseline and 11.8M shares traded passes this and fails a baseline floor). | |
| includeUnscreened | No | Also return rows that could not be RATED against the price / market-cap / float bounds above, because company_screener_data holds no value for them — typically a symbol renamed or listed within the last day (the source is an FMP screener that lags a rename by ~a day). Each such row carries "unscreenedFilters" naming the families that could not be applied, and the matching value field is null. READ THAT AS NOT MEASURED — never as "matched" or "did not match". Default false, in which case those rows are excluded from "rows" but are STILL reported in meta.unscreened (count / columns / tickers), so they are never silently dropped. Inert unless a price, market-cap or float filter is supplied. | |
| minBaselineVolume | No | Minimum RVOL DENOMINATOR in shares. Drops rows whose "baselineVolume" is below it, plus every row that has no baseline at all. This is the direct fix for a huge RVOL computed against a near-zero baseline (e.g. 102 shares ÷ a 1.2-share baseline = 87x on a $10B company that just does not trade at 04:30). Try 200 to match the "baselineThin" flag, or higher for a stricter screen. Does NOT change any RVOL — it only removes rows. Note it also excludes the includeNoHistory cohort, which by definition has no denominator. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| data | No |