Crypto API Rate Limiting: Best Practices for Trading Bots
If you're building a crypto trading bot, you've hit rate limits. CoinGecko's 30 req/min, Binance's 1200/min with burst limits, and every other API has its own rules. Here's how to handle them properly.
The Problem
Most bot developers hit rate limits because they:
Solution 1: Smart Caching
Most market data doesn't change meaningfully every second. Cache aggressively:
``python
import time
import requests
class CachedAPI:
def __init__(self):
self._cache = {}
def get(self, url, ttl_seconds=60):
now = time.time()
if url in self._cache:
data, ts = self._cache[url]
if now - ts < ttl_seconds:
return data
resp = requests.get(url, timeout=10)
resp.raise_for_status()
data = resp.json()
self._cache[url] = (data, now)
return data
api = CachedAPI()
Regime changes slowly — cache for 5 minutes
regime = api.get("https://getregime.com/api/v1/market/regime", ttl_seconds=300)
Prices change faster — cache for 30 seconds
overview = api.get("https://getregime.com/api/v1/market/overview", ttl_seconds=30)
`
Solution 2: Exponential Backoff
When you do hit a rate limit, back off exponentially:
`python
import time
import requests
def fetch_with_backoff(url, max_retries=3):
for attempt in range(max_retries):
resp = requests.get(url, timeout=10)
if resp.status_code == 429:
wait = (2 * attempt) 1 # 1s, 2s, 4s
retry_after = resp.headers.get('Retry-After', wait)
print(f"Rate limited. Waiting {retry_after}s...")
time.sleep(float(retry_after))
continue
resp.raise_for_status()
return resp.json()
raise Exception("Max retries exceeded")
`
Solution 3: Read the Rate Limit Headers
Good APIs tell you exactly where you stand:
`python
resp = requests.get("https://getregime.com/api/v1/market/regime",
headers={"Authorization": "Bearer YOUR_KEY"})
limit = resp.headers.get("X-RateLimit-Limit") # e.g., 120
remaining = resp.headers.get("X-RateLimit-Remaining") # e.g., 85
reset = resp.headers.get("X-RateLimit-Reset") # seconds until reset
Also check for upgrade hints when approaching the limit
upgrade_hint = resp.headers.get("X-Upgrade-Hint")
if upgrade_hint:
print(f"Approaching limit: {upgrade_hint}")
`
Solution 4: Multi-Source Failover
Don't depend on a single API:
`python
SOURCES = [
{"url": "https://getregime.com/api/v1/market/overview", "name": "Regime"},
{"url": "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd", "name": "CoinGecko"},
]
def get_btc_price():
for source in SOURCES:
try:
resp = requests.get(source["url"], timeout=5)
if resp.ok:
data = resp.json()
if source["name"] == "Regime":
return data["btc"]["price"]
elif source["name"] == "CoinGecko":
return data["bitcoin"]["usd"]
except:
continue
raise Exception("All sources failed")
`
Rate Limits by API
| API | Free Limit | Paid Limit | Notes |
|---|---|---|---|
| Regime | 10 RPM / 500/day | 120 RPM / 10K/day (Pro) | Headers included |
| Binance | 1200 req/min | Same | Weight-based system |
| CoinGecko | 30 req/min | 500 req/min (Pro) | 429 common at peak |
| CryptoCompare | 100K/month | 2M/month | Monthly quota |
| Messari | 20 req/min | 100 req/min | Per-endpoint limits |
Key Takeaways
Cache everything — most data doesn't change faster than your cache TTL
Use regime for decisions, price feeds for execution — you don't need real-time regime (it changes every few hours, not seconds)
Read rate limit headers — they tell you exactly when to slow down
Build failover — no single API is 100% reliable
Start with the free tier:
curl https://getregime.com/api/v1/market/regime`
Full docs: getregime.com/quickstart