Build a stock screener

A screener is one question asked of every ticker at once — exactly the shape of the computed table. The screener you'd otherwise assemble from a feed, a warehouse, and indicator math is a single SQL call.

The recipe

1. Write the screen

A SQL WHERE clause over 421+ named signals and fundamentals — here: above the 200-day average, under 20× earnings, over $1B market cap, largest first.

curl -s -X POST https://api.tickerbot.io/v2/scan \
  -H "Authorization: Bearer $TICKERBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "q": "above_sma_200 AND pe_ratio < 20 AND market_cap > 1e9",
        "order": "market_cap", "dir": "desc", "limit": 50,
        "columns": "ticker,price,pe_ratio,market_cap,rsi_14" }'

Columns span the full schema, plus custom signals you define once and reference by name.

2. Screen the past

The same call with asof answers as of any past moment — the market as it stood, delisted tickers included.

curl -s -X POST "https://api.tickerbot.io/v2/scan" \
  -H "Authorization: Bearer $TICKERBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "q": "above_sma_200 AND pe_ratio < 20 AND market_cap > 1e9",
        "asof": "2026-01-15" }'

3. Make it push

Subscribe the same q and the screen stops being something you poll — a webhook fires whenever the match set changes.

curl -s -X POST https://api.tickerbot.io/v2/scan/subscribe \
  -H "Authorization: Bearer $TICKERBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "q": "above_sma_200 AND pe_ratio < 20 AND market_cap > 1e9",
        "target_url": "https://your-app.example.com/hook" }'

4. Use the rows

Rows arrive finished — the columns you asked for, in the order you asked for them, nothing left to compute.

const res = await fetch('https://api.tickerbot.io/v2/scan', {
  method: 'POST',
  headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ q: userQuery, order: sortCol, dir: sortDir, limit: 50 }),
})
const { results } = await res.json()

// results: [ { ticker: "AAPL", price: 231.4, pe_ratio: 18.2, ... }, ... ]

Endpoints used

EndpointRole in this build
POST /v2/scanThe screen itself: q, order, dir, limit, columns; live or ?asof=
POST /v2/scan/subscribeThe same screen as a push: fires when the match set changes
GET /v2/tickers/{ticker}The detail view: everything about one ticker in one row
POST /v2/universesSaved ticker lists: scope any screen with universe=
POST /v2/signalsDefine a missing signal once, screen on it by name

More guides