nmime

crypto-data

Free crypto market data APIs for trading agents. Provides Fear & Greed Index, trending coins, market data, and coin prices using CoinGecko (free tier) and Alternative.me APIs. No API key required for basic usage.

nmime 1 Actualitzat fa 8 mesos
GitHub

Instal·la

npx skillscat add nmime/infra-skills/crypto-data

Instal·la des del registre de SkillsCat.

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
  }
}