How to Build an EtherFi Yield Tracker with CoinMarketCap API
CoinMarketCap API DIY

How to Build an EtherFi Yield Tracker with CoinMarketCap API

7m"
1 week ago

Build a production-aware restaking and LRT monitoring system using CoinMarketCap API to track EtherFi, ETHFI, eETH, weETH, and broader yield rotation signals.

How to Build an EtherFi Yield Tracker with CoinMarketCap API

Mục lục

Introduction

Restaking has become one of the most important DeFi narratives.

EtherFi sits at the center of that narrative through liquid restaking exposure and the ETHFI ecosystem.

But tracking EtherFi is not only about watching the ETHFI price.

A useful tracker should monitor:

  • ETHFI momentum
  • eETH / weETH market behavior
  • liquid restaking token activity
  • ETH beta
  • restaking sector strength
  • liquidity quality
  • market regime

CoinMarketCap API gives you the off-chain signal layer required to build this kind of tracker.

In this guide, you will build an EtherFi Yield Tracker with CoinMarketCap API, where:
  • CoinMarketCap powers the market intelligence layer
  • your system monitors restaking and LRT momentum
  • EtherFi-related assets become part of a broader yield rotation dashboard

This guide is educational and production-aware. It is not financial advice.

Why Use CoinMarketCap API for EtherFi Tracking?

Restaking assets behave differently from normal spot tokens.

They are influenced by:

  • ETH market conditions
  • liquid restaking demand
  • DeFi risk appetite
  • liquidity depth
  • protocol narratives
  • sector-wide capital rotation

CoinMarketCap API provides:

  • asset mapping
  • current quotes
  • categories
  • listings
  • historical quotes
  • market-pair liquidity context
  • Fear & Greed data
  • Altcoin Season data

This allows your tracker to move from:

“ETHFI price changed”

toward:

“capital is rotating into restaking and LRT assets”

System Architecture

CoinMarketCap API

├─ Cryptocurrency Map

├─ Quotes Latest

├─ Listings Latest

├─ Categories / Category

├─ Historical Quotes

├─ Market Pairs

├─ Fear & Greed

└─ Altcoin Season



EtherFi Yield Tracker



Restaking / LRT Momentum Score



Watchlist / Alerts / Dashboard

Important Architecture Clarification

CoinMarketCap API acts strictly as an off-chain Signal Layer for yield discovery, market sentiment, and liquidity estimation.

It is not a real-time, on-chain execution oracle or yield state machine.

Advanced decentralized strategies such as Pendle yield-stripping, LRT looping, or cross-chain messaging must validate exact smart contract reserves, staking caps, and on-chain slippage locally before execution to account for REST API cache delays.

Project Setup

import os
import time
import requests
import pandas as pd
import numpy as np

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: Map EtherFi and LRT Assets

Use CoinMarketCap IDs rather than symbols whenever possible.

Symbols can collide. IDs are stable.

Endpoint:

/v1/cryptocurrency/map

Use it to map assets such as:

  • ETHFI
  • eETH
  • weETH
  • stETH
  • ezETH
  • rsETH
  • ETH

Example

def map_assets(symbols="ETHFI,ETH"):
url = f"{CMC_BASE_URL}/v1/cryptocurrency/map"

params = {
"symbol": symbols
}

r = requests.get(
url,
headers=HEADERS,
params=params,
timeout=20
)

r.raise_for_status()

return r.json()["data"]

For tokens, the response may include a platform object containing the token contract address.

Native assets generally have platform = null.

Step 2: Fetch Quotes for ETHFI and LRT Assets

Endpoint:

/v3/cryptocurrency/quotes/latest

This endpoint supports batch requests with comma-separated IDs.

Example

def fetch_quotes(ids):
url = f"{CMC_BASE_URL}/v3/cryptocurrency/quotes/latest"

params = {
"id": ids
}

r = requests.get(
url,
headers=HEADERS,
params=params,
timeout=20
)

r.raise_for_status()

return r.json()["data"]

Step 3: Parse quote Correctly

In the real v3 API response, quote is a list of quote objects.

Do not parse it as a dictionary keyed by USD.

Incorrect:

usd = asset["quote"]["USD"]

Correct:

quotes = asset.get("quote", [])
usd = next((q for q in quotes if q.get("symbol") == "USD"), {})

Normalization Helper

def get_usd_quote(asset):
quotes = asset.get("quote", [])

return next(
(q for q in quotes if q.get("symbol") == "USD"),
{}
)

def normalize_asset(asset):
usd = get_usd_quote(asset)

return {
"id": asset.get("id"),
"symbol": asset.get("symbol"),
"name": asset.get("name"),
"price": usd.get("price"),
"volume_24h": usd.get("volume_24h") or 0,
"market_cap": usd.get("market_cap") or 0,
"fully_diluted_market_cap": usd.get("fully_diluted_market_cap") or 0,
"percent_change_1h": usd.get("percent_change_1h") or 0,
"percent_change_24h": usd.get("percent_change_24h") or 0,
"percent_change_7d": usd.get("percent_change_7d") or 0,
"tvl": usd.get("tvl"), "tvl_ratio": asset.get("tvl_ratio"),
"last_updated": asset.get("last_updated"),
}

Important:

  • tvl lives inside the USD quote object when available
  • tvl_ratio lives at the root asset level
  • both can return null

Treat TVL fields as optional enrichment.

Step 4: Discover Restaking Categories

Use categories to discover restaking and liquid staking sectors dynamically.

Endpoint:

/v1/cryptocurrency/categories

Do not hardcode category IDs. Fetch them dynamically.

Example

def fetch_categories():
url = f"{CMC_BASE_URL}/v1/cryptocurrency/categories"

r = requests.get(
url,
headers=HEADERS,
timeout=30
)

r.raise_for_status()

return r.json()["data"]

Find Restaking / LRT Categories

def find_restaking_categories(categories):

keywords = [
"restaking",
"liquid restaking",
"liquid staking",
"staking",
"yield",
]

matches = []

for category in categories:
searchable = " ".join([
str(category.get("name", "")),
str(category.get("title", "")),
str(category.get("description", "")),
]).lower()

if any(k in searchable for k in keywords):

matches.append({
"id": category.get("id"),
"name": category.get("name"),
"title": category.get("title"),
"num_tokens": category.get("num_tokens"),
"market_cap": category.get("market_cap"),
"volume": category.get("volume"),
"avg_price_change": category.get("avg_price_change"),
"market_cap_change": category.get("market_cap_change"),
})

return pd.DataFrame(matches)

Step 5: Fetch Tokens From a Category

Once you identify the correct restaking or liquid staking category, fetch the assets inside it.

Endpoint:

/v1/cryptocurrency/category

This endpoint returns category-level metrics and the underlying crypto assets.

Useful category fields include:

  • id
  • name
  • title
  • description
  • num_tokens
  • market_cap
  • volume
  • avg_price_change
  • market_cap_change

Example

def fetch_category(category_id):
url = f"{CMC_BASE_URL}/v1/cryptocurrency/category"

params = {
"id": category_id
}

r = requests.get(
url,
headers=HEADERS,
params=params,
timeout=30
)

r.raise_for_status()

return r.json()["data"]

Step 6: Use Listings for Yield Rotation

For a broader yield rotation screen, use:

/v3/cryptocurrency/listings/latest

A Basic-friendly approach is to pull a broad DeFi universe and filter locally.

def fetch_defi_universe(limit=500):
url = f"{CMC_BASE_URL}/v3/cryptocurrency/listings/latest"

params = {
"limit": limit,
"sort": "volume_24h",
"tag": "defi",
"aux": "tags"
}

r = requests.get(
url,
headers=HEADERS,
params=params,
timeout=30
)

r.raise_for_status()

return r.json()["data"]

This is often more efficient than repeatedly calling many category endpoints.

Use categories for clean sector discovery.

Use listings for large-scale rotation monitoring.

Step 7: Build an LRT Momentum Score

The tracker should measure restaking momentum, not just raw price change.

Useful inputs:

  • 24h volume
  • 24h price change
  • 7d price change
  • market cap
  • fully diluted market cap
  • TVL when available
  • ETH relative strength

Example

def lrt_momentum_score(asset):
volume = asset.get("volume_24h") or 0
p24h = asset.get("percent_change_24h") or 0
p7d = asset.get("percent_change_7d") or 0
market_cap = asset.get("market_cap") or 0
fdv = asset.get("fully_diluted_market_cap") or 0

volume_score = min(volume / 100_000_000, 1)
momentum_score = max(min(p24h / 20, 1), -1)
trend_score = max(min(p7d / 30, 1), -1)

dilution_penalty = 0
if market_cap > 0 and fdv > 0:
fdv_ratio = fdv / market_cap
if fdv_ratio > 5:
dilution_penalty = 0.2

return (
volume_score * 0.35 +
momentum_score * 0.30 +
trend_score * 0.25 -
dilution_penalty
)

For yield and restaking assets, monitor both market cap and fully diluted market cap. FDV can reveal future dilution risk.

Step 8: Add ETH Relative Strength

Restaking assets are ETH-linked.

A useful tracker should compare ETHFI or LRT tokens against ETH.

def relative_strength(asset_return, eth_return):
return asset_return - eth_return

Example:

ethfi_rs = relative_strength(
asset_return=12.5,
eth_return=3.0
)

A positive relative strength value suggests the asset is outperforming ETH.

This helps distinguish:

  • ETH market beta
  • restaking-specific momentum

Step 9: Add Market Regime Filters

Restaking demand changes with market regime.

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 interpretation:

  • altcoin_index > 75 → Altcoin Season
  • altcoin_index < 25 → Bitcoin Season

Step 10: Evaluate Liquidity Quality

For execution-quality context, use:

/v2/cryptocurrency/market-pairs/latest

This endpoint is useful for exchange-level market quality.

Useful fields:

  • effective_liquidity
  • market_score
  • market_reputation
  • depth_negative_two
  • depth_positive_two

Request enrichment fields through aux:

def fetch_market_pairs(asset_id):
url = f"{CMC_BASE_URL}/v2/cryptocurrency/market-pairs/latest"

params = {
"id": asset_id,
"limit": 100,
"aux": "effective_liquidity,market_score,market_reputation"
}

try:

r = requests.get(
url,
headers=HEADERS,
params=params,
timeout=30
)

r.raise_for_status()

return r.json()["data"]

except requests.HTTPError as e:
if e.response is not None and e.response.status_code == 403:
print("Market pairs unavailable on this plan")
return None

raise

Important plan warning:

This endpoint may return:

HTTP 403 Forbidden
Error 1006: Plan Not Authorized

on Basic plans.

Treat market-pair liquidity as optional enrichment.

Basic-friendly fallback:

  • continue using /v3/cryptocurrency/listings/latest
  • filter by volume_24h
  • filter by market_cap
  • mark exchange-level liquidity as unavailable

Depth and liquidity fields may also return null, especially for newer LRTs or DEX-only assets.

Parse defensively.

Step 11: Historical Backtesting

Use historical quotes for regime and relative strength analysis.

Endpoint:

/v3/cryptocurrency/quotes/historical

Useful intervals:

  • 1h
  • 4h
  • daily
def fetch_historical_quotes(asset_id, time_start, time_end, interval="daily"):
url = f"{CMC_BASE_URL}/v3/cryptocurrency/quotes/historical"

params = {
"id": asset_id,
"time_start": time_start,
"time_end": time_end,
"interval": interval,
}

r = requests.get(
url,
headers=HEADERS,
params=params,
timeout=30
)

r.raise_for_status()

return r.json()["data"]

Important:

  • historical cache updates roughly every 5 minutes
  • historical data costs 1 credit per 100 data points
  • deep history depends on plan tier
  • Basic access may be limited for longer backtests

Use historical data for bootstrap and backtesting, not fast polling.

Step 12: Paid Trending Endpoints

Paid endpoints can help detect narrative attention.

Examples:

/v1/cryptocurrency/trending/latest

/v1/cryptocurrency/trending/gainers-losers

/v1/cryptocurrency/trending/most-visited

/v1/community/trending/topic

/v1/community/trending/token

These endpoints can help identify:

  • search-volume momentum
  • retail attention
  • community narrative strength
  • restaking topic momentum

Paid plan warning:

HTTP 403 Forbidden
Error 1006: Plan Not Authorized

Basic-friendly fallback:

  • use /v3/cryptocurrency/listings/latest
  • sort by volume_24h
  • filter locally using tags and restaking-related assets

Step 13: Minimal End-to-End Flow

def run_etherfi_tracker(asset_ids):
raw_quotes = fetch_quotes(asset_ids)

normalized = [
normalize_asset(asset)
for asset in raw_quotes
]

df = pd.DataFrame(normalized)

df["lrt_score"] = df.apply(
lambda row: lrt_momentum_score(row.to_dict()),
axis=1
)

return df.sort_values(
"lrt_score",
ascending=False
)

Rate Limits and Polling

Recommended cadence:

  • quotes/latest → every 60 seconds
  • listings/latest → every 60 seconds
  • Fear & Greed → every 15 minutes
  • Altcoin Season → every 15 minutes
  • historical → bootstrap or backtesting only

Use local caching.

Use exponential backoff for HTTP 429.

def request_with_backoff(url, params=None):
failures = 0

while True:
try:
r = requests.get(
url,
headers=HEADERS,
params=params,
timeout=30
)

r.raise_for_status()

return r.json()

except requests.HTTPError as e:
if e.response is not None and e.response.status_code == 429:
failures += 1
time.sleep(min(60 * (2 ** failures), 900))
continue

raise

Common Mistakes

Parsing quote Incorrectly

In v3, quote is a list.

Correct:

quotes = asset.get("quote", [])
usd = next((q for q in quotes if q.get("symbol") == "USD"), {})

Incorrect:

usd = asset["quote"]["USD"]

Treating TVL Fields as Guaranteed

tvl and tvl_ratio can return null.

Use them as optional enrichment, not mandatory scoring inputs.

Ignoring FDV

Restaking governance tokens may have large future dilution.

Track both market_cap and fully_diluted_market_cap.

Overusing Historical Endpoints

Historical data is credit-intensive.

Use it for bootstrap and backtesting, not live loops.

Treating CMC as an Execution Oracle

CoinMarketCap is an off-chain signal layer.

Always validate real smart contract state before any on-chain execution.

Final Thoughts

EtherFi tracking is not just about ETHFI price.

A useful tracker should combine:

  • restaking category momentum
  • ETH relative strength
  • LRT liquidity
  • FDV risk
  • market regime
  • historical context

CoinMarketCap API gives you the market intelligence layer required to build that system.

The result is a cleaner and more production-aware restaking dashboard.

Next Steps

To improve the tracker:

  • add on-chain eETH / weETH supply data
  • compare LRTs against ETH
  • monitor Pendle PT/YT markets
  • add alerts for category momentum
  • add liquidity-quality thresholds
  • store historical snapshots locally

Better restaking intelligence leads to better yield decisions.

0 people liked this article