Build a production-aware perpetuals trading system that uses CoinMarketCap API for market signals and dYdX for long and short execution.
Introduction
Perpetual trading is not only about placing orders quickly.
It is about choosing the right market, direction, and risk level before execution.
dYdX provides perpetual trading infrastructure for long and short positions, order management, and leveraged exposure. CoinMarketCap API provides the market intelligence layer that helps decide what to trade and when.
- CoinMarketCap API powers market selection and signal generation
- dYdX handles perpetual trade execution
- your system applies regime, momentum, and risk filters before placing trades
This guide is educational. It is not financial advice.
Why Combine CoinMarketCap and dYdX?
A dYdX bot needs more than an execution connection.
It needs a decision engine.
CoinMarketCap API provides:
- price and volume data
- momentum metrics
- market-wide screening
- Fear & Greed context
- Altcoin Season context
- historical snapshots for backtesting
dYdX provides:
- perpetual markets
- long and short execution
- market, limit, stop, and take-profit order types
- position management
CoinMarketCap decides the signal. dYdX executes the position.
System Architecture
CoinMarketCap API (Signal Layer)
├─ Quotes Latest
├─ Listings Latest
├─ Fear & Greed
├─ Altcoin Season Index
├─ Historical Quotes
↓
Signal Engine
↓
Long / Short / No Trade
↓
dYdX (Execution Layer)
├─ Market Orders
├─ Limit Orders
├─ Stop Loss
├─ Take Profit
Important:
CoinMarketCap is not an execution feed. It provides structured market context. dYdX handles account state, orders, positions, and fills.
Project Setup
import os
import time
import requests
import pandas as pd
CMC_API_KEY = os.getenv("CMC_API_KEY")
CMC_BASE_URL = "https://pro-api.coinmarketcap.com"
HEADERS = {
"Accept": "application/json",
"X-CMC_PRO_API_KEY": CMC_API_KEY,
}
Step 1: Fetch Core Market Quotes
Use CoinMarketCap quotes to pull the assets you want to trade on dYdX.
Endpoint:
/v3/cryptocurrency/quotes/latest
Example:
def fetch_quotes(ids="1,1027,5426"):
url = f"{CMC_BASE_URL}/v3/cryptocurrency/quotes/latest"
params = {
"id": ids # BTC, ETH, SOL
}
r = requests.get(url, headers=HEADERS, params=params, timeout=15)
r.raise_for_status()
return r.json()["data"]
This endpoint supports batch requests using comma-separated CoinMarketCap IDs.
The quote field in v3 responses is a list of currency objects. Find the USD entry by matching on symbol:
quotes = asset.get("quote", [])usd = next((q for q in quotes if q.get("symbol") == "USD"), {})
Useful fields inside the USD object:
- price
- volume_24h
- percent_change_1h
- percent_change_24h
- percent_change_7d
- market_cap
Step 2: Flatten quote -> USD
Do not read price or momentum fields from the top level.
Flatten the quote object before generating signals.
def normalize_asset(asset):
quotes = asset.get("quote", [])
usd = next((q for q in quotes if q.get("symbol") == "USD"), {})
return {
"id": asset.get("id"),
"symbol": asset.get("symbol"),
"price": usd.get("price"),
"volume_24h": usd.get("volume_24h"),
"percent_change_1h": usd.get("percent_change_1h"),
"percent_change_24h": usd.get("percent_change_24h"),
"percent_change_7d": usd.get("percent_change_7d"),
"market_cap": usd.get("market_cap"),
"fully_diluted_market_cap": usd.get("fully_diluted_market_cap"),
}
Some values can be null, especially for illiquid or newly listed assets. Always parse defensively.
Step 3: Build a Momentum Signal
Directional perpetual trading needs a clear long, short, or no-trade bias.
def momentum_signal(asset):
p1h = asset.get("percent_change_1h") or 0
p24h = asset.get("percent_change_24h") or 0
p7d = asset.get("percent_change_7d") or 0
volume = asset.get("volume_24h") or 0
if volume < 50_000_000:
return "NO_TRADE"
if p1h > 1 and p24h > 3 and p7d > 0:
return "LONG"
if p1h < -1 and p24h < -3 and p7d < 0:
return "SHORT"
return "NO_TRADE"
This is a simple educational signal.
In production, you should tune thresholds per market and test them historically.
Step 4: Screen Markets with Listings
Use listings to scan a wider universe of assets.
Endpoint:
/v3/cryptocurrency/listings/latest
Example:
def fetch_screened_assets(limit=200):
url = f"{CMC_BASE_URL}/v3/cryptocurrency/listings/latest"
params = {
"limit": limit,
"sort": "volume_24h",
"market_cap_min": 500_000_000,
"volume_24h_min": 50_000_000,
}
r = requests.get(url, headers=HEADERS, params=params, timeout=15)
r.raise_for_status()
return r.json()["data"]
Supported filters include:
- market_cap_min
- volume_24h_min
- percent_change_24h_min
Supported sorts include:
- volume_24h
- market_cap
- percent_change_24h
The maximum limit is 5000.
Listings works on the Basic plan and costs 1 credit plus 1 credit for every 200 assets returned.
Step 5: Add Market Regime Filters
Perpetuals are sensitive to market regime.
A long signal during Risk-Off conditions should be treated differently from a long signal during Risk-On conditions.
Fear & Greed
Endpoint:
/v3/fear-and-greed/latest
def fetch_fear_greed():
url = f"{CMC_BASE_URL}/v3/fear-and-greed/latest"
r = requests.get(url, headers=HEADERS, timeout=15)
r.raise_for_status()
data = r.json()["data"]
return {
"value": data["value"],
"classification": data["value_classification"],
"update_time": data["update_time"],
}
Altcoin Season Index
Endpoint:
/v1/altcoin-season-index/latest
def fetch_altcoin_index():
url = f"{CMC_BASE_URL}/v1/altcoin-season-index/latest"
r = requests.get(url, headers=HEADERS, timeout=15)
r.raise_for_status()
return r.json()["data"]["altcoin_index"]
Official thresholds:
- altcoin_index > 75 → Altcoin Season
- altcoin_index < 25 → Bitcoin Season
Step 6: Combine Signal and Regime
Use market context to control position aggression.
def regime_filter(signal, fear_greed_value, altcoin_index):
if signal == "NO_TRADE":
return "NO_TRADE"
if fear_greed_value < 25 and signal == "LONG":
return "REDUCED_LONG"
if fear_greed_value > 85 and signal == "LONG":
return "CAUTIOUS_LONG"
if altcoin_index < 25 and signal != "BTC_LONG":
return "REDUCE_ALT_EXPOSURE"
return signal
The goal is not to predict perfectly. The goal is to avoid taking high-risk trades when macro conditions are weak or overheated.
Step 7: Add Production Momentum Discovery (Paid Feature)
Endpoint:
/v1/cryptocurrency/trending/gainers-losers
This endpoint can help detect fast rotation and sharp directional moves.
It requires a paid plan.
HTTP 403 Forbidden
Error 1006: Plan Not Authorized
Fallback for Basic plans:
Use /v3/cryptocurrency/listings/latest with:
params = {
"sort": "percent_change_24h",
"volume_24h_min": 50_000_000,
}
Trending updates every 10 minutes.
Step 8: Generate Trade Intent
The output of the CoinMarketCap layer should be an execution intent, not an order.
def generate_trade_intent(asset, fear_greed, altcoin_index):
normalized = normalize_asset(asset)
signal = momentum_signal(normalized)
filtered_signal = regime_filter(signal, fear_greed["value"], altcoin_index)
return {
"symbol": normalized["symbol"],
"signal": filtered_signal,
"price": normalized["price"],
"volume_24h": normalized["volume_24h"],
}
Example output:
{
"symbol": "ETH",
"signal": "LONG",
"price": 3200,
"volume_24h": 18500000000,
}
Your dYdX execution layer can then map the signal to:
- market order
- limit order
- stop loss
- take profit
- position size
- leverage
Step 9: Execute on dYdX
CoinMarketCap does not execute trades.
dYdX handles execution.
A dYdX integration should:
- connect to dYdX using the official SDK or API
- map the CoinMarketCap asset to the matching dYdX perpetual market
- check account balances and open positions
- place an order if the signal passes risk checks
- attach stop loss and take profit rules
Common order types on dYdX include:
- market orders
- limit orders
- stop market orders
- stop limit orders
- take profit market orders
- take profit limit orders
Use CoinMarketCap for the decision layer and dYdX for order placement.
Step 10: Backtest Your Signals
For momentum backtests, use:
/v3/cryptocurrency/quotes/historical
This endpoint supports intervals such as:
- 5m
- 15m
- 1h
- daily
For OHLCV candlestick systems, use:
/v2/cryptocurrency/ohlcv/historical
OHLCV is better when your strategy depends on exact open, high, low, and close candles.
Historical data costs 1 credit per 100 data points returned. Avoid calling historical endpoints inside a tight polling loop.
Production pattern:
- load historical data once at startup
- store it locally
- update live state with quotes/latest
Rate Limit Strategy
Recommended polling:
- Quotes/latest → 30 to 60 seconds
- Listings/latest → 30 to 60 seconds
- Fear & Greed → 15 minutes
- Altcoin Season → 15 minutes
- Trending → 10 minutes
Best practices:
- batch quote requests with comma-separated IDs
- cache macro signals
- use exponential backoff for HTTP 429
- avoid polling historical endpoints repeatedly
def safe_get(url, params=None, timeout=15):
for attempt in range(5):
try:
r = requests.get(url, headers=HEADERS, params=params, timeout=timeout)
r.raise_for_status()
return r.json()
except requests.HTTPError as e:
if e.response is not None and e.response.status_code == 429:
time.sleep(2 ** attempt)
continue
raise
Common Mistakes
Ignoring quote -> USD Nesting
Treating CoinMarketCap as an Execution Feed
CoinMarketCap generates signals. dYdX executes trades.
Polling Too Aggressively
Quotes and listings update every 60 seconds. Macro indicators update every 15 minutes.
Overusing Historical Endpoints
Historical data is credit-intensive. Load it once and cache it.
Ignoring Null Fields
Some assets may have missing volume_24h or percent_change_* values. Parse defensively.
Skipping Regime Filters
Perpetual leverage magnifies losses. Momentum signals should be filtered by market conditions.
Minimal End-to-End Flow
quotes = fetch_quotes("1,1027,5426")
fear_greed = fetch_fear_greed()
alt_index = fetch_altcoin_index()
for asset_id, asset in quotes.items():
intent = generate_trade_intent(asset, fear_greed, alt_index)
if intent["signal"] != "NO_TRADE":
print("Trade intent:", intent)
This produces trade intent objects that can be consumed by a dYdX execution module.
Final Thoughts
A strong dYdX bot needs more than an order function.
It needs a market-aware decision layer.
CoinMarketCap API provides the signals, screening, sentiment, and historical data needed to build that layer.
dYdX provides the execution environment for perpetual trades.
Together, they let you build a structured perpetual trading system that is selective, risk-aware, and production-ready.
Next Steps
- map CoinMarketCap IDs to dYdX markets
- add position sizing rules
- connect to the dYdX SDK
- backtest signal thresholds
- add stop loss and take profit logic
- log all signals and execution outcomes
Better signals lead to better perpetual trading decisions.
