Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Access CoinGecko crypto market data: spot prices, OHLC, trending coins, exchange listings, NFTs, and global stats.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
tools/coins.py
1#!/usr/bin/env python32"""3CoinGecko Coins Tools45Tools for fetching coin lists, market data, detailed coin info, and tickers.6"""78import os9from dotenv import load_dotenv10import json11import argparse12from typing import Dict, Any, Optional1314from core.http_client import proxied_get1516# Load environment variables17load_dotenv()181920def get_api_key() -> str:21"""Get CoinGecko API key from environment."""22api_key = os.getenv("COINGECKO_API_KEY")23if not api_key:24raise ValueError("COINGECKO_API_KEY environment variable is required")25return api_key262728def get_coins_list(include_platform: bool = False) -> Dict[str, Any]:29"""30Get all supported coins with id, symbol, name.3132Args:33include_platform: Include platform contract addresses3435Returns:36Dictionary with list of all coins37"""38api_key = get_api_key()3940url = "https://pro-api.coingecko.com/api/v3/coins/list"41headers = {"x-cg-pro-api-key": api_key}42params = {"include_platform": str(include_platform).lower()}4344response = proxied_get(url, headers=headers, params=params, timeout=30)45response.raise_for_status()46data = response.json()4748coins = []49for coin in data:50coin_data = {51"id": coin.get("id", ""),52"symbol": coin.get("symbol", "").upper(),53"name": coin.get("name", "")54}55if include_platform and "platforms" in coin:56coin_data["platforms"] = coin.get("platforms", {})57coins.append(coin_data)5859return {60"coins": coins,61"count": len(coins)62}636465def get_coins_markets(66vs_currency: str = "usd",67order: str = "market_cap_desc",68per_page: int = 100,69page: int = 1,70sparkline: bool = False,71price_change_percentage: str = "24h",72category: Optional[str] = None,73ids: Optional[str] = None74) -> Dict[str, Any]:75"""76Get market data for coins with sorting and pagination.7778Args:79vs_currency: Target currency (usd, eur, btc)80order: Sort order (market_cap_desc, volume_desc, price_change_24h_desc)81per_page: Results per page (max 250)82page: Page number83sparkline: Include 7-day sparkline data84price_change_percentage: Comma-separated time periods (1h, 24h, 7d, 14d, 30d, 200d, 1y)85category: Filter by category id86ids: Comma-separated coin ids to filter8788Returns:89Dictionary with market data for coins90"""91api_key = get_api_key()9293url = "https://pro-api.coingecko.com/api/v3/coins/markets"94headers = {"x-cg-pro-api-key": api_key}95params = {96"vs_currency": vs_currency,97"order": order,98"per_page": min(per_page, 250),99"page": page,100"sparkline": str(sparkline).lower(),101"price_change_percentage": price_change_percentage102}103if category:104params["category"] = category105if ids:106params["ids"] = ids107108response = proxied_get(url, headers=headers, params=params, timeout=30)109response.raise_for_status()110data = response.json()111112coins = []113for coin in data:114coin_data = {115"id": coin.get("id", ""),116"symbol": coin.get("symbol", "").upper(),117"name": coin.get("name", ""),118"image": coin.get("image"),119"current_price": coin.get("current_price"),120"market_cap": coin.get("market_cap"),121"market_cap_rank": coin.get("market_cap_rank"),122"fully_diluted_valuation": coin.get("fully_diluted_valuation"),123"total_volume": coin.get("total_volume"),124"high_24h": coin.get("high_24h"),125"low_24h": coin.get("low_24h"),126"price_change_24h": coin.get("price_change_24h"),127"price_change_percentage_24h": coin.get("price_change_percentage_24h"),128"market_cap_change_24h": coin.get("market_cap_change_24h"),129"market_cap_change_percentage_24h": coin.get("market_cap_change_percentage_24h"),130"circulating_supply": coin.get("circulating_supply"),131"total_supply": coin.get("total_supply"),132"max_supply": coin.get("max_supply"),133"ath": coin.get("ath"),134"ath_change_percentage": coin.get("ath_change_percentage"),135"ath_date": coin.get("ath_date"),136"atl": coin.get("atl"),137"atl_change_percentage": coin.get("atl_change_percentage"),138"atl_date": coin.get("atl_date"),139"last_updated": coin.get("last_updated")140}141# Add price change percentages if available142for key in coin:143if key.startswith("price_change_percentage_"):144coin_data[key] = coin.get(key)145if sparkline and "sparkline_in_7d" in coin:146coin_data["sparkline_in_7d"] = coin.get("sparkline_in_7d")147coins.append(coin_data)148149return {150"coins": coins,151"count": len(coins),152"vs_currency": vs_currency,153"order": order,154"page": page,155"per_page": per_page156}157158159def get_coin_data(160coin_id: str,161localization: bool = False,162tickers: bool = False,163market_data: bool = True,164community_data: bool = False,165developer_data: bool = False,166sparkline: bool = False167) -> Dict[str, Any]:168"""169Get full coin metadata including description, links, ATH, ATL, market data.170171Args:172coin_id: CoinGecko coin id173localization: Include localized languages174tickers: Include tickers data175market_data: Include market data176community_data: Include community data177developer_data: Include developer data178sparkline: Include sparkline 7 days data179180Returns:181Dictionary with comprehensive coin data182"""183api_key = get_api_key()184185url = f"https://pro-api.coingecko.com/api/v3/coins/{coin_id}"186headers = {"x-cg-pro-api-key": api_key}187params = {188"localization": str(localization).lower(),189"tickers": str(tickers).lower(),190"market_data": str(market_data).lower(),191"community_data": str(community_data).lower(),192"developer_data": str(developer_data).lower(),193"sparkline": str(sparkline).lower()194}195196response = proxied_get(url, headers=headers, params=params, timeout=30)197response.raise_for_status()198data = response.json()199200result = {201"id": data.get("id", ""),202"symbol": data.get("symbol", "").upper(),203"name": data.get("name", ""),204"asset_platform_id": data.get("asset_platform_id"),205"platforms": data.get("platforms", {}),206"block_time_in_minutes": data.get("block_time_in_minutes"),207"hashing_algorithm": data.get("hashing_algorithm"),208"categories": data.get("categories", []),209"description": data.get("description", {}).get("en", ""),210"links": {211"homepage": data.get("links", {}).get("homepage", []),212"blockchain_site": data.get("links", {}).get("blockchain_site", []),213"official_forum_url": data.get("links", {}).get("official_forum_url", []),214"chat_url": data.get("links", {}).get("chat_url", []),215"announcement_url": data.get("links", {}).get("announcement_url", []),216"twitter_screen_name": data.get("links", {}).get("twitter_screen_name"),217"facebook_username": data.get("links", {}).get("facebook_username"),218"telegram_channel_identifier": data.get("links", {}).get("telegram_channel_identifier"),219"subreddit_url": data.get("links", {}).get("subreddit_url"),220"repos_url": data.get("links", {}).get("repos_url", {})221},222"image": data.get("image", {}),223"country_origin": data.get("country_origin"),224"genesis_date": data.get("genesis_date"),225"sentiment_votes_up_percentage": data.get("sentiment_votes_up_percentage"),226"sentiment_votes_down_percentage": data.get("sentiment_votes_down_percentage"),227"market_cap_rank": data.get("market_cap_rank"),228"coingecko_rank": data.get("coingecko_rank"),229"coingecko_score": data.get("coingecko_score"),230"developer_score": data.get("developer_score"),231"community_score": data.get("community_score"),232"liquidity_score": data.get("liquidity_score"),233"public_interest_score": data.get("public_interest_score"),234"last_updated": data.get("last_updated")235}236237if market_data and "market_data" in data:238md = data["market_data"]239result["market_data"] = {240"current_price": md.get("current_price", {}),241"total_value_locked": md.get("total_value_locked"),242"mcap_to_tvl_ratio": md.get("mcap_to_tvl_ratio"),243"fdv_to_tvl_ratio": md.get("fdv_to_tvl_ratio"),244"roi": md.get("roi"),245"ath": md.get("ath", {}),246"ath_change_percentage": md.get("ath_change_percentage", {}),247"ath_date": md.get("ath_date", {}),248"atl": md.get("atl", {}),249"atl_change_percentage": md.get("atl_change_percentage", {}),250"atl_date": md.get("atl_date", {}),251"market_cap": md.get("market_cap", {}),252"market_cap_rank": md.get("market_cap_rank"),253"fully_diluted_valuation": md.get("fully_diluted_valuation", {}),254"total_volume": md.get("total_volume", {}),255"high_24h": md.get("high_24h", {}),256"low_24h": md.get("low_24h", {}),257"price_change_24h": md.get("price_change_24h"),258"price_change_percentage_24h": md.get("price_change_percentage_24h"),259"price_change_percentage_7d": md.get("price_change_percentage_7d"),260"price_change_percentage_14d": md.get("price_change_percentage_14d"),261"price_change_percentage_30d": md.get("price_change_percentage_30d"),262"price_change_percentage_60d": md.get("price_change_percentage_60d"),263"price_change_percentage_200d": md.get("price_change_percentage_200d"),264"price_change_percentage_1y": md.get("price_change_percentage_1y"),265"market_cap_change_24h": md.get("market_cap_change_24h"),266"market_cap_change_percentage_24h": md.get("market_cap_change_percentage_24h"),267"total_supply": md.get("total_supply"),268"max_supply": md.get("max_supply"),269"circulating_supply": md.get("circulating_supply")270}271272if tickers and "tickers" in data:273result["tickers"] = data["tickers"]274275if community_data and "community_data" in data:276result["community_data"] = data["community_data"]277278if developer_data and "developer_data" in data:279result["developer_data"] = data["developer_data"]280281return result282283284def get_coin_tickers(285coin_id: str,286exchange_ids: Optional[str] = None,287include_exchange_logo: bool = False,288page: int = 1,289order: str = "volume_desc",290depth: bool = False291) -> Dict[str, Any]:292"""293Get all trading pairs/tickers for a coin across exchanges.294295Args:296coin_id: CoinGecko coin id297exchange_ids: Comma-separated exchange ids to filter298include_exchange_logo: Include exchange logo299page: Page number300order: Sort order (trust_score_desc, trust_score_asc, volume_desc, volume_asc)301depth: Include order book depth (cost_to_move_up_usd, cost_to_move_down_usd)302303Returns:304Dictionary with tickers for the coin305"""306api_key = get_api_key()307308url = f"https://pro-api.coingecko.com/api/v3/coins/{coin_id}/tickers"309headers = {"x-cg-pro-api-key": api_key}310params = {311"include_exchange_logo": str(include_exchange_logo).lower(),312"page": page,313"order": order,314"depth": str(depth).lower()315}316if exchange_ids:317params["exchange_ids"] = exchange_ids318319response = proxied_get(url, headers=headers, params=params, timeout=30)320response.raise_for_status()321data = response.json()322323tickers = []324for ticker in data.get("tickers", []):325ticker_data = {326"base": ticker.get("base", ""),327"target": ticker.get("target", ""),328"market": {329"name": ticker.get("market", {}).get("name", ""),330"identifier": ticker.get("market", {}).get("identifier", ""),331"has_trading_incentive": ticker.get("market", {}).get("has_trading_incentive")332},333"last": ticker.get("last"),334"volume": ticker.get("volume"),335"converted_last": ticker.get("converted_last", {}),336"converted_volume": ticker.get("converted_volume", {}),337"trust_score": ticker.get("trust_score"),338"bid_ask_spread_percentage": ticker.get("bid_ask_spread_percentage"),339"timestamp": ticker.get("timestamp"),340"last_traded_at": ticker.get("last_traded_at"),341"last_fetch_at": ticker.get("last_fetch_at"),342"is_anomaly": ticker.get("is_anomaly"),343"is_stale": ticker.get("is_stale"),344"trade_url": ticker.get("trade_url"),345"token_info_url": ticker.get("token_info_url"),346"coin_id": ticker.get("coin_id"),347"target_coin_id": ticker.get("target_coin_id")348}349if include_exchange_logo:350ticker_data["market"]["logo"] = ticker.get("market", {}).get("logo")351if depth:352ticker_data["cost_to_move_up_usd"] = ticker.get("cost_to_move_up_usd")353ticker_data["cost_to_move_down_usd"] = ticker.get("cost_to_move_down_usd")354tickers.append(ticker_data)355356return {357"name": data.get("name", ""),358"tickers": tickers,359"count": len(tickers),360"page": page361}362363364def main():365"""CLI interface for coins tools."""366parser = argparse.ArgumentParser(367description="CoinGecko Coins Tools",368formatter_class=argparse.RawDescriptionHelpFormatter369)370371subparsers = parser.add_subparsers(dest="command")372373# List command374list_parser = subparsers.add_parser("list", help="Get all supported coins")375list_parser.add_argument("--platforms", action="store_true", help="Include platform addresses")376377# Markets command378markets_parser = subparsers.add_parser("markets", help="Get market data for coins")379markets_parser.add_argument("--currency", default="usd")380markets_parser.add_argument("--order", default="market_cap_desc")381markets_parser.add_argument("--per-page", type=int, default=100)382markets_parser.add_argument("--page", type=int, default=1)383markets_parser.add_argument("--category", help="Filter by category")384markets_parser.add_argument("--ids", help="Filter by coin ids (comma-separated)")385386# Data command387data_parser = subparsers.add_parser("data", help="Get detailed coin data")388data_parser.add_argument("coin_id", help="CoinGecko coin ID")389data_parser.add_argument("--tickers", action="store_true", help="Include tickers")390data_parser.add_argument("--community", action="store_true", help="Include community data")391data_parser.add_argument("--developer", action="store_true", help="Include developer data")392393# Tickers command394tickers_parser = subparsers.add_parser("tickers", help="Get coin tickers")395tickers_parser.add_argument("coin_id", help="CoinGecko coin ID")396tickers_parser.add_argument("--exchanges", help="Filter by exchange ids")397tickers_parser.add_argument("--page", type=int, default=1)398tickers_parser.add_argument("--order", default="volume_desc")399400args = parser.parse_args()401402try:403if args.command == "list":404result = get_coins_list(args.platforms)405elif args.command == "markets":406result = get_coins_markets(407vs_currency=args.currency,408order=args.order,409per_page=args.per_page,410page=args.page,411category=args.category,412ids=args.ids413)414elif args.command == "data":415result = get_coin_data(416coin_id=args.coin_id,417tickers=args.tickers,418community_data=args.community,419developer_data=args.developer420)421elif args.command == "tickers":422result = get_coin_tickers(423coin_id=args.coin_id,424exchange_ids=args.exchanges,425page=args.page,426order=args.order427)428else:429parser.print_help()430return 0431432print(json.dumps(result, indent=2, ensure_ascii=False))433return 0434435except Exception as e:436print(json.dumps({"error": str(e)}, indent=2))437return 1438439440if __name__ == "__main__":441exit(main())442