Market scanner · discovery, not lookup

Scan the whole market. Get back a ranked shortlist.

One POST /v1/scan call scans US stocks, ETFs and crypto for the tickers currently in a given regime or printing a chart/candlestick pattern — ranked by the measured base rate, and every rate comes with the pattern-free baseline for that market, timeframe and horizon, plus a cluster-robust 95% CI. Your agent stops analyzing one ticker at a time, and it reads each number against the right reference instead of a made-up one.

POST /v1/scan$0.02REST + MCPx402 + Stripe

TL;DR — The screener is patternfetch's flagship discovery endpoint. Pass optional filters — assetClass, regime, pattern, tf, minLift, minBaseRate, limit — and POST /v1/scan returns a ranked shortlist of tickers, ordered by the measured base rate and shipped with the pattern-free baseline for the same market, timeframe and horizon plus a cluster-robust 95% CI. Same discipline as the brief: a rate is only meaningful against its baseline, and we publish both. Also available as the patternfetch_scan MCP tool.

Lookup vs. discovery

Most market-data APIs — patternfetch's own /v1/brief included — are lookup: you already know the ticker, and you ask for its current state. That's the right tool once you have a candidate. But an agent screening the market has the opposite problem: it doesn't know which tickers to look at yet. Calling /v1/brief on hundreds of symbols to find the handful that matter is slow, token-heavy and expensive.

Lookup — one ticker at a time

"What's the state of AAPL on the 1d?" → one brief. To find candidates you'd loop /v1/brief over the whole universe yourself, then sort — many calls, many tokens, your own ranking logic.

Discovery — the screener

"Which US stocks and crypto are in an uptrend printing a double_bottom, best base rate first?" → one /v1/scan call returns the ranked shortlist. Then call /v1/brief only on the names that survived.

That's the whole pitch: the scanner turns lookup into discovery, so your model narrows the universe in one call instead of being handed one ticker at a time — and it ranks by measured numbers, each next to its baseline, not by a confident-sounding label.

How it works

  1. A curated universe. An evidence-backed set of liquid US large-caps, core & sector ETFs, and major crypto pairs is scanned so every result is a name with enough history to measure — and enough history to compute its pattern-free baseline.
  2. Precomputed, not live. Scanning the whole universe live (a fetch + full analysis per ticker) would be slow and hammer upstream sources. Instead the universe is scanned offline on a schedule and each ticker's current-signal row is stored, so a scan is served from memory — fast and cheap.
  3. Filter. Your optional filters narrow the universe by asset class, regime, pattern, timeframe and a minimum base rate.
  4. Rank by the measured base rate. Survivors are ordered by the top pattern's backtested directional base rate (with its cluster-robust 95% CI, sample size and the pattern-free baseline for the same market, timeframe and horizon) — the same evidence the brief attaches to a pattern — then by geometric confidence, then timeframe, then symbol.
  5. Act on the shortlist. Take the ranked rows and call /v1/brief on the top names for the full picture before your agent does anything.

The filters

Every field is optional; an absent field puts no constraint on that axis. A filter-less POST /v1/scan returns the top of the universe, ranked.

FilterTypeMeaning
assetClass"stock" | "crypto" | "all"Restrict to US stocks/ETFs, crypto pairs, or all. Default all.
regime"up" | "down" | "range"Only tickers whose current regime trend matches — uptrend, downtrend, or sideways/chop.
patternstringRequire the ticker's top pattern to be this one: double_bottom, double_top, head_and_shoulders, bullish_engulfing, bearish_engulfing, hammer.
tfstringOne of 1m 5m 15m 30m 1h 4h 1d 1w. The universe is currently precomputed at 1d.
minLift−1..1The drift-free filter — prefer this one. Drop tickers whose top pattern doesn't beat its own pattern-free baseline by at least this many rate points. 0.02 = 2pp of measured lift; 0 = at or above baseline. Rows with no baseline in the evidence table are always excluded — absence of a lift is not a lift of 0.
minBaseRate0..1Drop tickers whose top-pattern backtested base rate is below this floor. Careful: a raw base rate isn't comparable across bullish and bearish rows. Kept for existing consumers — see minLift.
limitint 1..500Max rows returned. Default 50.

Which floor should you screen on? minBaseRate asks how often a pattern resolved in its direction. minLift asks how much of that the pattern was responsible for. On the daily US stock table a bullish pattern starts about 16pp ahead of a bearish one before either carries any information, so a base-rate floor is mostly a drift filter in a signal's clothing. minLift is the floor that survives that objection — and it returns very little, which is the honest result rather than a broken filter.

Example — request & response

Ask for US stocks and crypto in an uptrend with at least a 55% base rate, top 20:

Request
curl -X POST https://patternfetch.com/v1/scan \
  -H "Authorization: Bearer pf_…" \
  -H "Content-Type: application/json" \
  -d '{ "assetClass": "all",
        "regime": "up",
        "minBaseRate": 0.55,
        "limit": 20 }'
Response — ranked shortlist
{
  "asOf": "2026-07-05",
  "tfs": ["1d"],
  "universe": 137,
  "count": 2,
  "results": [
    { "sym":"AAPL","tf":"1d","assetClass":"stock",
      "regime":"up","pattern":"double_bottom",
      "baseRate":0.58,"ci95":0.03,"n":300,
      "scope":"US stocks & ETFs","confidence":0.72,
      "baseline":0.5784,"lift":0.0016,"liftCi95":0.026,
      "liftReading":"indistinguishable-from-baseline" },
    { "sym":"BTC/USDT","tf":"1d","assetClass":"crypto",
      "regime":"up","pattern":"bullish_engulfing",
      "baseRate":0.56,"ci95":0.04,"n":180,
      "scope":"major crypto pairs","confidence":0.69,
      "baseline":0.5412,"lift":0.0188,"liftCi95":0.041,
      "liftReading":"indistinguishable-from-baseline" }
  ],
  "note":"Precomputed current-state scan ranked by
          impersonal historical base rate. Discovery,
          not a prediction or a buy/sell signal.",
  "disclaimer":"… informational only, not advice …"
}

Each row carries sym, tf, assetClass, regime, pattern, baseRate (the ranking key), ci95, n (sample size), scope (the corpus the rate was measured over) and geometric confidence — plus the drift-free block baseline, lift, liftCi95 and liftReading. The envelope's universe and asOf tell you how many tickers were scanned and when. See it live →

The drift-free screen

Note what the two rows above actually say: both clear a 55% base rate, and neither is distinguishable from its own baseline. That is the failure mode a base-rate floor cannot see. Screen on minLift instead and the filter asks the harder question:

Request — patterns that beat their own baseline by 2pp+
curl -X POST https://patternfetch.com/v1/scan \
  -H "Authorization: Bearer pf_…" \
  -H "Content-Type: application/json" \
  -d '{ "assetClass": "all",
        "regime": "up",
        "minLift": 0.02,
        "limit": 20 }'
Response — usually a very short list
{
  "asOf": "2026-07-05",
  "tfs": ["1d"],
  "universe": 137,
  "count": 0,
  "results": [],
  "note":"Precomputed current-state scan ranked by
          impersonal historical base rate. Discovery,
          not a prediction or a buy/sell signal.",
  "disclaimer":"… informational only, not advice …"
}

An empty shortlist is a result, not a broken filter. Across the 105 pattern/market/timeframe buckets we backtested, three clear an uncorrected interval — fewer than the ~5.3 that chance alone would produce, and on US stocks it is 0 of 60. minLift is the parameter that lets your agent act on that instead of on drift. Read the full study →

How results are ranked

The whole feature is "ranked by the measured base rate", so ordering is deterministic and evidence-first:

KeyDirectionWhy
baseRatedescHow often that exact pattern + timeframe + confidence band historically resolved in its own direction, with no lookahead. Read it against the scope's pattern-free baseline, returned with every row.
confidencedescGeometric fit score (0..1) — breaks ties between equal base rates.
tf then symascStable, attributable ordering for same-strength rows.

Tickers whose top pattern has no sufficiently-powered evidence bucket carry baseRate: null and rank last — the scanner never invents a number it can't back with history.

One caveat the ranking itself can't fix: base rates are not comparable across asset classes. US stocks and ETFs drift upward, so a bullish daily bucket starts from a 57.8% pattern-free baseline over 10 bars, while the same bucket in crypto starts from about 49.3%. A 56% crypto row and a 56% stock row are therefore not the same finding. Compare each row to the baseline for its own scope, which is why the baseline travels with the row.

We measure where others assert

A confident-looking chart pattern is not the same as a pattern that carries information. Every other screener ranks by how cleanly a shape matches, and published pattern statistics usually quote a hit rate with nothing to compare it against — the same bearish engulfing is quoted at 57%, 75.76% and 79% by three widely-cited sources, none of which publishes a baseline or an interval. patternfetch measures instead. Every base rate ships with the pattern-free baseline for the same market, timeframe and horizon: over 10 bars on the daily, US stocks and ETFs close up 57.8% of the time with no pattern involved, crypto about 49.3%. Measured that way, three of the 105 buckets we tested clear an uncorrected interval — fewer than the ~5.3 chance alone would produce, and none of the three survives correction; on US stocks and ETFs it is 0 of 60 — daily bullish engulfing is +0.4pp (±2.6pp, n=11,535), hammer −0.1pp (±2.7pp, n=5,600). That is the point: numbers your model can rank on without inventing significance that isn't there.

Over MCP

The screener is also the patternfetch_scan tool on the patternfetch MCP server — same optional filters, same ranked output. Point any MCP client (Claude, Cursor, Smithery, an OpenAI agent over a bridge) at https://patternfetch.com/mcp; tool discovery is free and a call is billed like the REST route.

# one line — OAuth mints a free-tier key, nothing to paste
claude mcp add --transport http patternfetch https://patternfetch.com/mcp

Then your agent can call patternfetch_scan with, e.g., {"assetClass":"crypto","pattern":"double_top","limit":10} and reason over the ranked shortlist. See the MCP docs.

Pricing & free tier

① A scan is $0.02 per call — the same pay-per-call model as every endpoint. ② No-signup demo & free key: the wider API has a keyless demo and a free key with a $3.00 starter credit, no card. ③ Pay as you go: settle with Stripe or with x402 (USDC on Base, no account) so an agent can fund itself. ④ Credits never expire. Full pricing →

FAQ

What is the patternfetch screener?
A market scanner: one POST /v1/scan call scans a universe of US stocks, ETFs and crypto pairs and returns the tickers currently in a given regime or printing a chart/candlestick pattern, ranked by the measured base rate and shown against the pattern-free baseline for that market, timeframe and horizon, with a cluster-robust 95% CI. It turns lookup into discovery — ask which tickers match your criteria right now, get a ranked shortlist back.
How are scan results ranked?
By the top pattern's measured base rate (descending), then geometric confidence, then timeframe, then symbol. Each row also carries the pattern-free baseline for its scope, so a 56% crypto row and a 56% stock row are not read as the same finding. Tickers with no sufficiently-powered evidence bucket carry a null base rate and rank last.
What filters can I pass?
All optional: assetClass (stock/crypto/all), regime (up/down/range), pattern (e.g. double_bottom), tf (a timeframe; universe precomputed at 1d), minLift (−1..1 in rate points), minBaseRate (0..1), and limit (1..500, default 50). Prefer minLift: a raw base rate isn't comparable across bullish and bearish rows, so a base-rate floor mostly returns bullish patterns in a rising market before any of them carries information. A filter-less scan returns the top of the universe, ranked.
How much does a scan cost?
$0.02 per call. Pay with x402 (USDC on Base, no account) so an agent can pay autonomously, or by card via Stripe. The wider API also has a free no-signup demo and a free key with a $3.00 starter credit.
Is the scanner available over MCP?
Yes — as the patternfetch_scan tool on the MCP server (https://patternfetch.com/mcp), with the same filters and ranked output. tools/list is free; a tools/call is billed like the REST endpoint.
Is a scan result investment advice?
No. It's impersonal, algorithmic market data for informational purposes only. Base rates are gross historical directional frequencies, to be read against the pattern-free baseline returned with them — across the 105 buckets measured to date, three clear an uncorrected interval by a margin distinguishable from zero, fewer than the ~5.3 that chance alone would produce, and none of the three survives correcting for 105 comparisons; on US stocks and ETFs it is 0 of 60. They are not predictions or buy/sell signals; past results do not guarantee future results. Not advice, not personalized, non-executing. See the disclaimer.

Keep reading