crypto-data
SKILL.md
Crypto Data Skill
Free crypto market data using public APIs. No paid MCP server required.
API Sources
| Data | Source | Rate Limit | Auth |
|---|---|---|---|
| Fear & Greed Index | Alternative.me | Unlimited | None |
| Trending Coins | CoinGecko | 10-30/min | Optional |
| Market Data | CoinGecko | 10-30/min | Optional |
| Coin Prices | CoinGecko | 10-30/min | Optional |
Fear & Greed Index
From Alternative.me (always free, no auth):
async function get_fear_greed_index() {
// Fetch from Alternative.me (free, no rate limit)
const response = await fetch('https://api.alternative.me/fng/')
const data = await response.json()
// Response format:
// {
// "data": [{
// "value": "25",
// "value_classification": "Extreme Fear",
// "timestamp": "1706745600",
// "time_until_update": "43200"
// }]
// }
const fng = data.data[0]
return {
value: parseInt(fng.value), // 0-100
classification: fng.value_classification, // "Extreme Fear", "Fear", "Neutral", "Greed", "Extreme Greed"
timestamp: parseInt(fng.timestamp) * 1000, // Unix ms
next_update_in: parseInt(fng.time_until_update) // Seconds
}
}
// Historical Fear & Greed (last N days)
async function get_fear_greed_history(days = 30) {
const response = await fetch(`https://api.alternative.me/fng/?limit=${days}`)
const data = await response.json()
return data.data.map(d => ({
value: parseInt(d.value),
classification: d.value_classification,
date: new Date(parseInt(d.timestamp) * 1000).toISOString().slice(0, 10)
}))
}
Classification Thresholds
| Value | Classification | Trading Signal |
|---|---|---|
| 0-24 | Extreme Fear | Strong Buy (contrarian) |
| 25-44 | Fear | Buy |
| 45-55 | Neutral | Hold |
| 56-75 | Greed | Sell |
| 76-100 | Extreme Greed | Strong Sell (contrarian) |
Trending Coins
From CoinGecko (free tier):
async function get_trending_coins() {
// CoinGecko free API (no auth, 10-30 calls/min)
const response = await fetch('https://api.coingecko.com/api/v3/search/trending')
const data = await response.json()
// Response contains top 15 trending coins
return data.coins.map(c => ({
id: c.item.id, // "bitcoin"
symbol: c.item.symbol, // "BTC"
name: c.item.name, // "Bitcoin"
market_cap_rank: c.item.market_cap_rank,
price_btc: c.item.price_btc,
score: c.item.score // Trending score (0 = most trending)
}))
}
Market Data (Top Coins)
async function get_market_data(vs_currency = 'usd', per_page = 100) {
const url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=${vs_currency}&order=market_cap_desc&per_page=${per_page}&page=1&sparkline=false&price_change_percentage=1h,24h,7d`
const response = await fetch(url)
const data = await response.json()
return data.map(coin => ({
id: coin.id,
symbol: coin.symbol.toUpperCase(),
name: coin.name,
current_price: coin.current_price,
market_cap: coin.market_cap,
market_cap_rank: coin.market_cap_rank,
total_volume: coin.total_volume,
high_24h: coin.high_24h,
low_24h: coin.low_24h,
price_change_24h: coin.price_change_percentage_24h,
price_change_7d: coin.price_change_percentage_7d_in_currency,
ath: coin.ath,
ath_change_percentage: coin.ath_change_percentage
}))
}
Simple Price Query
async function get_coin_prices(coin_ids, vs_currencies = 'usd') {
// coin_ids: comma-separated, e.g., "bitcoin,ethereum,solana"
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coin_ids}&vs_currencies=${vs_currencies}&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true`
const response = await fetch(url)
return await response.json()
// Response:
// {
// "bitcoin": {
// "usd": 67187.34,
// "usd_market_cap": 1317802988326.25,
// "usd_24h_vol": 28000000000,
// "usd_24h_change": 3.64
// },
// "ethereum": { ... }
// }
}
Global Market Data
async function get_global_market_data() {
const response = await fetch('https://api.coingecko.com/api/v3/global')
const data = await response.json()
return {
total_market_cap_usd: data.data.total_market_cap.usd,
total_volume_24h_usd: data.data.total_volume.usd,
btc_dominance: data.data.market_cap_percentage.btc,
eth_dominance: data.data.market_cap_percentage.eth,
active_cryptocurrencies: data.data.active_cryptocurrencies,
market_cap_change_24h: data.data.market_cap_change_percentage_24h_usd
}
}
Coin ID Mapping
Common Hyperliquid symbols to CoinGecko IDs:
const COINGECKO_IDS = {
'BTC': 'bitcoin',
'ETH': 'ethereum',
'SOL': 'solana',
'AVAX': 'avalanche-2',
'MATIC': 'matic-network',
'ARB': 'arbitrum',
'OP': 'optimism',
'LINK': 'chainlink',
'UNI': 'uniswap',
'AAVE': 'aave',
'DOGE': 'dogecoin',
'SHIB': 'shiba-inu',
'PEPE': 'pepe',
'WIF': 'dogwifcoin',
'BONK': 'bonk',
'SUI': 'sui',
'APT': 'aptos',
'SEI': 'sei-network',
'INJ': 'injective-protocol',
'TIA': 'celestia',
'JUP': 'jupiter-exchange-solana',
'ONDO': 'ondo-finance',
'RENDER': 'render-token',
'FET': 'fetch-ai',
'NEAR': 'near',
'ATOM': 'cosmos',
'DOT': 'polkadot',
'ADA': 'cardano',
'XRP': 'ripple',
'LTC': 'litecoin',
'BCH': 'bitcoin-cash'
}
function get_coingecko_id(symbol) {
return COINGECKO_IDS[symbol.toUpperCase()] || symbol.toLowerCase()
}
Combined Sentiment Function
For trading agents, combine Fear & Greed with market data:
async function get_market_sentiment() {
// Parallel fetch for efficiency
const [fng, global_data, trending] = await Promise.all([
get_fear_greed_index(),
get_global_market_data(),
get_trending_coins()
])
// Calculate composite sentiment
let sentiment_score = 50 // Neutral base
// Fear & Greed contribution (40%)
if (fng.value <= 25) sentiment_score += 20 // Extreme fear = bullish
else if (fng.value <= 40) sentiment_score += 10
else if (fng.value >= 75) sentiment_score -= 20 // Extreme greed = bearish
else if (fng.value >= 60) sentiment_score -= 10
// Market trend contribution (30%)
if (global_data.market_cap_change_24h > 3) sentiment_score += 15
else if (global_data.market_cap_change_24h > 1) sentiment_score += 8
else if (global_data.market_cap_change_24h < -3) sentiment_score -= 15
else if (global_data.market_cap_change_24h < -1) sentiment_score -= 8
// BTC dominance contribution (30%) - rising = risk-off, falling = risk-on
// (Handled separately based on trading strategy)
return {
fear_greed: fng,
global: global_data,
trending: trending.slice(0, 5),
sentiment_score: Math.max(0, Math.min(100, sentiment_score)),
direction: sentiment_score >= 60 ? 'BULLISH' : sentiment_score <= 40 ? 'BEARISH' : 'NEUTRAL'
}
}
Rate Limit Handling
// Simple rate limiter for CoinGecko
const RATE_LIMIT = {
calls: 0,
reset_time: Date.now() + 60000,
max_calls: 25 // Stay under 30/min limit
}
async function rate_limited_fetch(url) {
// Reset counter every minute
if (Date.now() > RATE_LIMIT.reset_time) {
RATE_LIMIT.calls = 0
RATE_LIMIT.reset_time = Date.now() + 60000
}
// Check limit
if (RATE_LIMIT.calls >= RATE_LIMIT.max_calls) {
const wait = RATE_LIMIT.reset_time - Date.now()
await new Promise(r => setTimeout(r, wait))
RATE_LIMIT.calls = 0
RATE_LIMIT.reset_time = Date.now() + 60000
}
RATE_LIMIT.calls++
return fetch(url)
}
Error Handling
async function safe_fetch(url, default_value = null) {
try {
const response = await fetch(url)
if (!response.ok) {
if (response.status === 429) {
// Rate limited - wait and retry
await new Promise(r => setTimeout(r, 60000))
return safe_fetch(url, default_value)
}
throw new Error(`HTTP ${response.status}`)
}
return await response.json()
} catch (error) {
console.error(`Fetch error: ${error.message}`)
return default_value
}
}
Usage in Trading Agent
// In your scan loop:
async function get_sentiment_for_trade(coin, chat_id) {
// Get Fear & Greed (free, unlimited)
const fng = await get_fear_greed_index()
// Get coin-specific data
const coin_id = get_coingecko_id(coin)
const price_data = await get_coin_prices(coin_id)
// Get global context
const global_data = await get_global_market_data()
return {
fear_greed: fng.value,
fear_greed_signal: fng.value <= 30 ? 'BUY' : fng.value >= 70 ? 'SELL' : 'NEUTRAL',
coin_24h_change: price_data[coin_id]?.usd_24h_change || 0,
market_24h_change: global_data.market_cap_change_24h,
btc_dominance: global_data.btc_dominance
}
}