extracted from a production trading system. handles rate limits gracefully.
🛡️ Why this library?
dexscreener's api is free and powerful, but:
- 429s kill your app if you don't handle them
- no python client exists that handles rate limits properly
- concurrent requests for the same token waste your quota
this library solves all three:
from dexscreener import DexScreenerClient
async with DexScreenerClient() as client:
pairs = await client.get_token_pairs("solana", "So11111111111111111111111111111111111111112")
for pair in pairs:
print(f"{pair.base_token_symbol}: ${pair.price_usd} | liq: ${pair.liquidity_usd}")
429s → automatic exponential backoff (3s → 6s → 12s).
duplicate requests → deduplicated into one HTTP call.
results → cached with configurable TTL.
📦 Install
pip install dexscreener-python
requires python 3.11+
⚡ Features
| any chain | solana, ethereum, base, bsc, arbitrum — anything dexscreener supports |
| adaptive rate limiting | token bucket that backs off on 429 and recovers after success |
| global 429 cooldown | one 429 pauses ALL requests briefly (prevents request storms) |
| response cache | configurable TTL per endpoint. concurrent calls share one request. |
| batch support | fetch up to 30 tokens in a single request |
| typed data | DexPairData dataclass with computed properties (buy/sell ratio, age, etc.) |
🔧 Usage
💰 Token Pairs
pairs = await client.get_token_pairs("solana", token_address)
best_pair = pairs[0]
print(f"Price: ${best_pair.price_usd}")
print(f"Liquidity: ${best_pair.liquidity_usd}")
print(f"24h Volume: ${best_pair.volume_24h}")
print(f"Buy/Sell 5m: {best_pair.buy_sell_ratio_5m:.2f}")
print(f"Age: {best_pair.pair_age_seconds // 3600}h")
💵 Token Price
price = await client.get_token_price("solana", token_address)
print(f"${price}")
📦 Batch Fetch (up to 30 tokens)
data = await client.get_tokens_batch("solana", [addr1, addr2, addr3])
for addr, pair in data.items():
print(f"{pair.base_token_symbol}: ${pair.price_usd}")
🔍 Search
results = await client.search_pairs("BONK")
for pair in results:
print(f"{pair.base_token_symbol} on {pair.dex_id}: ${pair.price_usd}")
🚀 Boosted Tokens
boosted = await client.get_boosted_tokens("solana")
🎯 Specific Pair
pair = await client.get_pair_by_address("solana", pair_address)
print(f"{pair.dex_id}: ${pair.price_usd}")
📋 DexPairData
all methods return DexPairData objects with these fields:
chain_id | str | chain identifier |
dex_id | str | dex identifier (raydium, uniswap_v3, etc.) |
pair_address | str | pair contract address |
base_token_address | str | base token mint/address |
base_token_symbol | str | token symbol |
price_usd | Decimal | current price in USD |
price_native | Decimal | price in native token (SOL, ETH, etc.) |
liquidity_usd | Decimal | total liquidity in USD |
volume_5m / 1h / 6h / 24h | Decimal | volume by timeframe |
price_change_5m / 1h / 6h / 24h | Decimal | price change % |
buys_5m / 1h / 24h | int | buy transactions |
sells_5m / 1h / 24h | int | sell transactions |
pair_created_at | int | unix timestamp (ms) |
computed properties:
buy_sell_ratio_5m | buy/sell ratio over 5 minutes (>1 = more buying) |
buy_sell_ratio_1h | buy/sell ratio over 1 hour |
has_liquidity | True if liquidity > $1000 |
pair_age_seconds | pair age in seconds |
⚙️ Configuration
client = DexScreenerClient(
rate_limit=5.0,
cache_ttl=8.0,
)
🆚 Comparison
| Rate limiting | ✅ adaptive token bucket | ❌ manual |
| 429 retry | ✅ exponential backoff | ❌ crash |
| Global cooldown | ✅ one 429 pauses all | ❌ per-request only |
| Response cache | ✅ TTL + dedup | ❌ manual |
| Typed data | ✅ DexPairData dataclass | ❌ raw dicts |
| Batch support | ✅ up to 30 tokens | ❌ manual loop |
| Async | ✅ native | depends |
License
MIT
📦 Also by JinUltimate1995