Tutorial

How To Build A Crypto Market Screener

Vortex APIUpdated 3 August 2026 · 9 min read
Vortex

A market screener answers a question that a plain price list cannot: which assets match my criteria right now? Large caps with unusual volume, micro caps up more than 10% today, DeFi tokens above a price floor. Traders use screeners to surface opportunities, and analysts use them to filter noise.

The Vortex listings endpoint supports this natively. Instead of fetching everything and filtering in your own code, you push the filters into the API request and get back only what matches. This guide builds a reusable screener function and shows several real screens on top of it.

Architecture

The flow is short, and the important decision sits in the middle: push filters into the API request rather than fetching broadly and narrowing in your own code.

  1. User defines screen criteria
  2. Backend builds listings/latest params server-side
  3. CMC API returns filtered, sorted list server-side
  4. Backend applies any additional local filters
  5. Frontend renders results

Server-side filtering via API parameters is more efficient than fetching everything and filtering locally. Use API params for primary filters, and local logic only for criteria the API does not support natively, such as tag filtering beyond defi and filesharing.

The endpoint

GET/v1/cryptocurrency/listings/latestFiltered, sorted market listing

Building the screener

One function wraps the endpoint. Every filter is optional, so callers pass only the criteria that matter for a given screen, and local_tags handles the tags the API cannot filter natively.

python
import os
import requests

HEADERS = {
    "Accept": "application/json",
    "X-CMC_PRO_API_KEY": os.getenv("CMC_API_KEY"),
}

def screen(
    sort="market_cap",
    sort_dir="desc",
    limit=100,
    price_min=None,
    price_max=None,
    market_cap_min=None,
    market_cap_max=None,
    volume_24h_min=None,
    volume_24h_max=None,
    percent_change_24h_min=None,
    percent_change_24h_max=None,
    cryptocurrency_type="all",
    tag="all",
    convert="USD",
    local_tags=None,  # list of tags to match locally
):
    params = {
        "sort": sort,
        "sort_dir": sort_dir,
        "limit": str(limit),
        "convert": convert,
        "cryptocurrency_type": cryptocurrency_type,
        "tag": tag,
        "aux": "cmc_rank,date_added,tags,circulating_supply,max_supply",
    }

    if price_min is not None: params["price_min"] = str(price_min)
    if price_max is not None: params["price_max"] = str(price_max)
    if market_cap_min is not None: params["market_cap_min"] = str(market_cap_min)
    if market_cap_max is not None: params["market_cap_max"] = str(market_cap_max)
    if volume_24h_min is not None: params["volume_24h_min"] = str(volume_24h_min)
    if volume_24h_max is not None: params["volume_24h_max"] = str(volume_24h_max)
    if percent_change_24h_min is not None: params["percent_change_24h_min"] = str(percent_change_24h_min)
    if percent_change_24h_max is not None: params["percent_change_24h_max"] = str(percent_change_24h_max)

    response = requests.get(
        "https://pro-api.vortex.com/v1/cryptocurrency/listings/latest",
        headers=HEADERS,
        params=params,
    )
    response.raise_for_status()
    assets = response.json()["data"]

    # Local tag filtering for tags beyond "defi"/"filesharing"
    if local_tags:
        tag_set = set(local_tags)
        assets = [a for a in assets if tag_set & set(a.get("tags") or [])]

    return assets

Example screens

Each screen is one call to screen() with a different set of criteria.

Screen Primary criteria Local step
Top gainers, large caps $500M+ market cap, $10M+ volume, sorted by 24h change None
Momentum Up 5%+ today, $1M+ volume Filter positive 7d
DeFi by TVL ratio tag=defi, top 100 by market cap Sort by tvl_ratio
Micro caps with volume $10M to $100M cap, $500K+ volume None
Layer-2 tokens Broad fetch of 200 Match layer-2 tag

Top gainers, large caps only

python
results = screen(
    sort="percent_change_24h",
    sort_dir="desc",
    market_cap_min=500_000_000,  # $500M+ market cap
    volume_24h_min=10_000_000,   # $10M+ daily volume
    limit=20,
)

Momentum screen, positive 24h and 7d

python
results = screen(
    sort="percent_change_24h",
    sort_dir="desc",
    percent_change_24h_min=5,     # up 5%+ today
    volume_24h_min=1_000_000,     # minimum liquidity
    limit=50,
)

# Filter 7d locally, not a native API param
results = [
    a for a in results
    if (a["quote"]["USD"].get("percent_change_7d") or 0) > 0
]

DeFi tokens by TVL ratio

python
results = screen(tag="defi", sort="market_cap", sort_dir="desc", limit=100)

# Sort locally by tvl_ratio, assets with high TVL relative to market cap
results_with_tvl = [a for a in results if a.get("tvl_ratio") is not None]
results_with_tvl.sort(key=lambda a: a.get("tvl_ratio") or 0, reverse=True)

Micro caps with volume

python
results = screen(
    market_cap_min=10_000_000,    # $10M minimum
    market_cap_max=100_000_000,   # $100M maximum
    volume_24h_min=500_000,       # active trading
    sort="volume_24h",
    sort_dir="desc",
    limit=50,
)

Layer-2 tokens, local tag filter

python
results = screen(limit=200, local_tags=["layer-2"])

Rendering results

A single formatter prints any screen as an aligned table:

python
def print_screen(results, convert="USD"):
    print(
        f"{'Rank':<6} {'Symbol':<8} {'Price':>12} {'24h':>8} "
        f"{'7d':>8} {'MCap':>15} {'Vol':>15}"
    )
    print("-" * 80)
    for asset in results:
        usd = asset["quote"][convert]
        print(
            f"#{asset['cmc_rank']:<5} "
            f"{asset['symbol']:<8} "
            f"${usd['price']:>11,.4f} "
            f"{(usd.get('percent_change_24h') or 0):>+7.2f}% "
            f"{(usd.get('percent_change_7d') or 0):>+7.2f}% "
            f"${usd['market_cap']:>14,.0f} "
            f"${usd['volume_24h']:>14,.0f}"
        )

Credit cost

Each listings call costs 1 credit for up to 200 assets. A screener making 10 calls per hour costs 10 credits per hour. Cache results for 60 seconds between refreshes, since the underlying data updates every 60 seconds.

Common mistakes

Fetching everything and filtering locally

The API supports server-side filtering for price, market cap, volume and percent change. Use it. Fetching 5,000 assets to find 20 is wasteful.

Passing unsupported tag values

Only all, defi and filesharing are valid for the tag parameter. For any other tag, fetch a broader set and filter the tags array locally.

Not caching

Screener results do not change faster than once per minute. Cache the response and serve refreshes from the cache.

FAQ

Which endpoint powers a crypto market screener?

GET /v1/cryptocurrency/listings/latest. It accepts sort and filter parameters so the API returns only assets matching your criteria, rather than a full list you narrow afterwards.

Should I filter server-side or locally?

Server-side wherever the API supports it: price, market cap, volume and 24-hour percent change. Use local logic only for criteria without a native parameter, such as 7-day change, tvl_ratio sorting, or tags beyond defi and filesharing.

How much does running a screener cost?

1 credit per call for up to 200 assets. A screener refreshing 10 times an hour costs 10 credits per hour, and caching for 60 seconds keeps that predictable.

How often should screener results refresh?

No faster than once per minute. The underlying data updates every 60 seconds, so cache the response and serve intermediate requests from the cache.

Can I screen by tags like layer-2 or NFT?

Not through the tag parameter, which accepts only all, defi and filesharing. Fetch a broader set with aux including tags, then match against each asset's tags array locally.

Can I screen on 7-day percent change?

Not as a request filter. Screen on 24-hour change server-side, then filter the returned set on percent_change_7d from each asset's quote object.

Build your first screen

Push your filters into the request, cache for 60 seconds, and let the API do the narrowing before the data reaches your code.