How To Build A Crypto Market Screener
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.
- User defines screen criteria
- Backend builds
listings/latestparams server-side - CMC API returns filtered, sorted list server-side
- Backend applies any additional local filters
- 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
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.
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
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
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
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
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
results = screen(limit=200, local_tags=["layer-2"])
Rendering results
A single formatter prints any screen as an aligned table:
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.



