NEW: Live arbitrage across 10+ prediction markets.Arbitrage →
← Index
Prediction MarketsAug 27, 20268 min read

How to Build a Prediction Market Screener With an API

How to Build a Prediction Market Screener With an API

The Short Answer

Pull the catalog with GET /api/router/fetchMarkets, which searches all 15+ venues at once, then filter in your own code on the fields you care about: price band, days to resolution, venue, and liquidity read from fetchOrderBook. A screener answers "which markets are worth looking at", which is a different question from a scanner's "where do two venues disagree".

A screener narrows a few thousand live markets down to the handful worth your attention. It is the boring half of market tooling and the half people actually use daily, because the alternative is scrolling a venue's front page and calling it research.

The mechanics are simple. The judgement is in choosing filters that surface tradeable markets rather than merely interesting ones.

Key Takeaways

  • A screener filters the universe. A scanner compares venues. Different jobs, different endpoints.
  • /api/router/fetchMarkets searches 15+ venues in one call, so you filter across everything rather than per venue.
  • Price alone is a weak filter. Days to resolution and spread matter more for whether a market is worth entering.
  • The catalog does not carry liquidity. You have to read books for the shortlist, which is why you filter before you fetch.
  • Cache the catalog. It changes slowly; books change constantly.

Screener or Scanner

ScreenerScanner
QuestionWhich markets meet my criteria?Where do two venues disagree?
InputThe whole catalogMatched market pairs
EndpointfetchMarkets/v1/discrepancies, fetchArbitrage
OutputA watchlistCandidate trades

Build the screener first. A scanner without a shortlist is scanning noise.

Pulling the Catalog

import Predictefy from '@predictefy/sdk';

const client = new Predictefy({ apiKey: process.env.PREDICTEFY_API_KEY });

// One call, every supported venue.
const markets = await client.router.fetchMarkets({ limit: 500 });
What This Does

Searches across all 15+ venues in a single request and returns markets in one shape. The per-venue equivalent, client.kalshi.fetchMarkets(), is there when you deliberately want one venue, but the router is what makes a cross-venue screener a few lines rather than a few hundred.

The catalog changes slowly. Fetch it on a schedule, cache it, and run your filters against the cache. Re-pulling thousands of markets on every user keystroke wastes credits and adds latency for no benefit.

Filters That Earn Their Place

Four filters do most of the work. Price is the least useful of them, despite being the one everybody starts with.

function screen(markets, rules) {
  const now = Date.now();

  return markets.filter((m) => {
    const price = m.lastPrice;
    if (price == null) return false;

    // Ignore markets that have effectively already resolved.
    if (price < rules.minPrice || price > rules.maxPrice) return false;

    const days = (new Date(m.closeTime) - now) / 86_400_000;
    if (days < rules.minDays || days > rules.maxDays) return false;

    if (rules.venues.length && !rules.venues.includes(m.venue)) return false;

    return true;
  });
}
What This Does

Cuts the catalog to a shortlist without touching a single order book. The price band mostly serves to exclude markets trading near 1 or 99 cents, which are decided in all but name. The days filter is the one people forget: a market resolving in four months ties up capital differently from one resolving on Friday.

The Filter That Needs a Second Call

Liquidity is the filter that decides whether a market is tradeable, and it is not in the catalog. You have to read the book, which is why the cheap filters run first.

const withLiquidity = [];

for (const m of shortlist) {
  const book = await client.exchange(m.venue).fetchOrderBook({
    marketId: m.marketId
  });

  const bid = book.bids[0]?.price;
  const ask = book.asks[0]?.price;
  if (bid == null || ask == null) continue;

  const spread = ask - bid;
  if (spread <= rules.maxSpread) {
    withLiquidity.push({ ...m, bid, ask, spread });
  }
}
What This Does

Reads the top of book for each shortlisted market and keeps only those with a spread you would accept. Running this against a hundred markets rather than three thousand is the entire reason the cheap filters came first. For bulk work, fetchOrderBooks takes several markets in one request.

Spread is a better liquidity proxy than volume for this purpose. Volume tells you what happened; spread tells you what it would cost to get in and out right now.

Going Past the Top of Book

A tight spread on one contract says nothing about a hundred. If your screener feeds real trades, ask what your intended size would actually cost.

const quote = await client.exchange(m.venue).getExecutionPrice({
  marketId: m.marketId,
  side: 'buy',
  contracts: rules.size
});

// Slippage against the top of book, in cents.
const slip = quote.averagePrice - m.ask;
What This Does

Walks the book for your size and returns the average price you would pay. Comparing that against the top of book gives you slippage, which is the honest version of a liquidity score and a far better sort key than volume.

Sorting and Presenting

Sort by whatever you are optimizing for, but sort by something. A screener that returns an unordered list has moved the problem rather than solved it. Slippage ascending is a good default: the markets you can actually get in and out of, first.

Show the fields that drove the decision, not every field you have. Venue, price, spread, days to close and slippage is enough to act on. Anything more becomes a spreadsheet nobody reads.

Why the Router Endpoint Matters

Written per venue, a cross-venue screener means one client per venue, one pagination scheme per venue, one field naming convention per venue, and a normalization layer you maintain forever. Most people give up and screen one venue, which defeats the point: the best price for a given view is often on a venue you were not looking at.

Predictefy's router searches 15+ venues in one call and returns one shape, so the filtering code above never learns which venue a market came from. The API key is free to start with a monthly credit allowance, which is enough to run a real screener on a schedule.

Frequently Asked Questions

How do I build a prediction market screener?

Pull the catalog across venues, filter on price band, time to resolution and venue in your own code, then read order books for the shortlist to filter on spread. Predictefy's router searches 15+ venues in one call and returns one shape, so filtering is written once.

What is the difference between a screener and a scanner?

A screener filters the whole market universe down to a watchlist matching your criteria. A scanner compares matched markets across venues to find price disagreements. Different questions and different endpoints, though a scanner works better when it runs on a screened shortlist.

Which filters actually matter?

Time to resolution and spread matter more than price. Price mostly serves to exclude markets near 1 or 99 cents that are effectively decided. Spread tells you what entering and exiting costs right now, which volume does not, since volume describes the past.

Why can I not filter by liquidity directly?

Liquidity lives in the order book, not the market catalog, so it needs a second request per market. Run your cheap filters first and read books only for the shortlist. Predictefy also exposes a bulk order book endpoint for fetching several at once.

How often should a screener refresh?

Refresh the catalog on a schedule, since markets are added and closed slowly. Refresh books only for the shortlist you display, because those change constantly. Caching the catalog and re-reading only books is the difference between a cheap screener and an expensive one.

Conclusion

A screener is a filter chain with one expensive link. Order it correctly, cheap filters against a cached catalog first and book reads only for the survivors, and it runs comfortably on a free key.

The filters worth having are the ones about tradeability rather than interest: how wide is the spread, how long until it resolves, and what would your actual size cost. A market that looks compelling and cannot be entered at size is not a result, it is a distraction.

One housekeeping note: this is information, not financial advice. Endpoints and credit costs change, so confirm anything that matters against the current documentation.