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/coin_historical_chart_range_by_id.py
1#!/usr/bin/env python32"""3CoinGecko Coin Historical Chart Data within Time Range Tool45This tool provides access to the CoinGecko Pro API /coins/{id}/market-chart/range endpoint,6which returns historical chart data for a specific coin by its id or symbol within a time range.78API Reference: https://docs.coingecko.com/reference/coins-id-market-chart-range910Usage Example:11from tools.coin_historical_chart_range_by_id import get_coin_historical_chart_range1213# Using symbol14data = get_coin_historical_chart_range('BTC', vs_currency='usd', from_timestamp=1672531200, to_timestamp=1672617600)1516# Using ID17data = get_coin_historical_chart_range('bitcoin', vs_currency='usd', from_timestamp=1672531200, to_timestamp=1672617600)18print(data)1920Returns:21dict with keys: 'prices', 'market_caps', 'total_volumes'22"""2324import os25from dotenv import load_dotenv26import time27import argparse28import json2930from core.http_client import proxied_get31try:32from .utils import parse_flexible_time, split_time_range, merge_market_chart_data, get_days_difference, search_coin_by_name33except ImportError:34from utils import parse_flexible_time, split_time_range, merge_market_chart_data, get_days_difference, search_coin_by_name353637# MCP Tool Schema38MCP_TOOL_SCHEMA = {39"name": "get_coin_historical_chart_range_by_id",40"title": "CoinGecko Historical Chart Range",41"description": "Retrieve historical chart data (prices, market caps, total volumes) for a specific cryptocurrency within a custom time range. Automatically determines optimal data granularity based on the time range. Will return a lot of data, use with caution.",42"inputSchema": {43"$schema": "https://json-schema.org/draft/2020-12/schema",44"type": "object",45"properties": {46"coin_id": {47"type": "string",48"minLength": 1,49"description": "The coin id (e.g., 'bitcoin') or symbol (e.g., 'BTC')"50},51"vs_currency": {52"type": "string",53"default": "usd",54"description": "The target currency (e.g., 'usd')"55},56"from_timestamp": {57"type": ["string", "integer", "number"],58"description": "Start time - supports Unix timestamp (1640995200), ISO date ('2023-01-01' or '2023-01-01 10:30:00'), or natural language ('2 weeks ago', 'last month', 'yesterday')"59},60"to_timestamp": {61"type": ["string", "integer", "number"],62"description": "End time - same formats as from_timestamp"63}64},65"required": ["coin_id", "from_timestamp", "to_timestamp"],66"additionalProperties": False67},68"outputSchema": {69"$schema": "https://json-schema.org/draft/2020-12/schema",70"type": "object",71"properties": {72"prices": {73"type": "array",74"items": {75"type": "array",76"items": [77{"type": "number", "description": "Unix timestamp in milliseconds"},78{"type": "number", "description": "Price in the specified vs_currency"}79],80"minItems": 2,81"maxItems": 282},83"description": "Array of [timestamp_ms, price] pairs showing coin price at each time point"84},85"market_caps": {86"type": "array",87"items": {88"type": "array",89"items": [90{"type": "number", "description": "Unix timestamp in milliseconds"},91{"type": "number", "description": "Market capitalization at this timestamp"}92],93"minItems": 2,94"maxItems": 295},96"description": "Array of [timestamp_ms, market_cap] pairs showing market capitalization"97},98"total_volumes": {99"type": "array",100"items": {101"type": "array",102"items": [103{"type": "number", "description": "Unix timestamp in milliseconds"},104{"type": "number", "description": "Total trading volume"}105],106"minItems": 2,107"maxItems": 2108},109"description": "Array of [timestamp_ms, volume] pairs showing trading volume"110}111},112"required": ["prices", "market_caps", "total_volumes"],113"additionalProperties": False114},115"annotations": {116"path": "tools/coingecko/coin_historical_chart_range_by_id.py",117"function": "get_coin_historical_chart_range_by_id",118"examples": [119{120"name": "basic_auto_interval",121"arguments": {122"coin_id": "BTC",123"from_timestamp": "30 days ago",124"to_timestamp": "today"125}126},127{128"name": "large_range_splitting",129"arguments": {130"coin_id": "BTC",131"from_timestamp": "2023-01-01",132"to_timestamp": "2023-12-31"133}134}135]136}137}138139140141# Load environment variables from project root directory142project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../..'))143load_dotenv(os.path.join(project_root, '.env'))144145def get_coin_historical_chart_range_by_id(coin_id, vs_currency='usd', from_timestamp=None, to_timestamp=None):146"""147Fetch historical chart data for a specific coin by its id or symbol within a time range from CoinGecko.148Automatically handles data splitting for large time ranges based on interval limits and flexible time input parsing.149150Args:151coin_id (str): The coin id (e.g., 'bitcoin') or symbol (e.g., 'BTC')152vs_currency (str): The target currency (e.g., 'usd')153from_timestamp (Union[str, int, float]): Start time - supports:154- Unix timestamp (1640995200)155- ISO date ('2023-01-01' or '2023-01-01 10:30:00')156- Natural language ('2 weeks ago', 'last month', 'yesterday')157to_timestamp (Union[str, int, float]): End time - same formats as from_timestamp158159Returns:160dict: Historical chart data with keys: 'prices', 'market_caps', 'total_volumes'161Automatically merges data from multiple API calls if needed for large ranges162163Raises:164ConnectionError: If API request fails after retries165ValueError: If parameters are invalid or time range exceeds interval limits166167Data Limitations (based on official CoinGecko API):168- Auto granularity: 1 day = 5-min, 1-90 days = hourly, >90 days = daily169- Cache frequency: 1 day = 30s, 2-90 days = 30min, >90 days = 12h170171Examples:172>>> # Get last 30 days of data173>>> data = get_coin_historical_chart_range_by_id('BTC', 'usd', '30 days ago', 'today')174175>>> # Get data for specific date range176>>> data = get_coin_historical_chart_range_by_id('ETH', 'usd', '2023-01-01', '2023-03-31')177178>>> # Large range with automatic splitting179>>> data = get_coin_historical_chart_range_by_id('BTC', 'usd', '2023-01-01', '2023-12-31')180"""181if not coin_id:182raise ValueError("coin_id parameter is required")183184if not from_timestamp or not to_timestamp:185raise ValueError("Both from_timestamp and to_timestamp are required")186187# Convert symbol to ID if needed188coin_result = search_coin_by_name(coin_id)189if not coin_result:190raise ValueError(f"Could not find coin with symbol or name: {coin_id}")191actual_coin_id = coin_result['id']192193# Parse flexible time inputs194from_ts = parse_flexible_time(from_timestamp)195to_ts = parse_flexible_time(to_timestamp)196197if from_ts >= to_ts:198raise ValueError("from_timestamp must be earlier than to_timestamp")199200# Determine splitting strategy based on time range201days_diff = get_days_difference(from_ts, to_ts)202203# For better granularity, split at 90 days to maintain hourly data when possible204if days_diff <= 90:205return _fetch_single_range(actual_coin_id, vs_currency, from_ts, to_ts)206else:207return _fetch_with_splitting(actual_coin_id, vs_currency, from_ts, to_ts, max_days=90)208209210def _fetch_single_range(coin_id, vs_currency, from_timestamp, to_timestamp):211"""Fetch historical chart data for a single time range."""212url = f"https://pro-api.coingecko.com/api/v3/coins/{coin_id}/market_chart/range"213params = {214'vs_currency': vs_currency,215'from': from_timestamp,216'to': to_timestamp217}218219headers = {"x-cg-pro-api-key": os.getenv("COINGECKO_API_KEY")}220221if not headers["x-cg-pro-api-key"]:222raise ValueError("COINGECKO_API_KEY environment variable is required")223224for attempt in range(3):225try:226resp = proxied_get(url, params=params, headers=headers, timeout=15)227resp.raise_for_status()228return resp.json()229except Exception as e:230if attempt == 2: # Last attempt231raise ConnectionError(f"API request failed after retries: {e}")232time.sleep(1)233234235def _fetch_with_splitting(coin_id, vs_currency, from_ts, to_ts, max_days):236"""Fetch historical chart data with automatic splitting for large ranges."""237time_chunks = split_time_range(from_ts, to_ts, max_days=max_days)238data_chunks = []239240for chunk_start, chunk_end in time_chunks:241chunk_data = _fetch_single_range(coin_id, vs_currency, chunk_start, chunk_end)242data_chunks.append(chunk_data)243# Small delay between requests to be respectful to the API244time.sleep(0.5)245246# Merge all chunks247return merge_market_chart_data(data_chunks)248249def main():250"""Main CLI function."""251parser = argparse.ArgumentParser(252description="Fetch historical chart data within a time range for a specific coin from CoinGecko API.",253epilog="""INPUT:254--coin_id: Coin ID/symbol (bitcoin, BTC, ethereum, ETH)255--from_timestamp: Start time ("30 days ago", "2023-01-01", timestamp)256--to_timestamp: End time ("today", "2023-12-31", timestamp)257--vs_currency: Target currency (default: usd)258259OUTPUT:260JSON array of price and volume data:261[{"timestamp": 1640995200, "price": 46300.45, "market_cap": 874500000000,262"total_volume": 34500000000}]263264EXAMPLE:265python coin_historical_chart_range_by_id.py --coin_id BTC --from_timestamp "30 days ago" --to_timestamp "today"266python coin_historical_chart_range_by_id.py --coin_id ethereum --from_timestamp "2023-01-01" --to_timestamp "2023-06-30"267""",268formatter_class=argparse.RawDescriptionHelpFormatter269)270271# MCP Schema query options272parser.add_argument('--schema', action='store_true',273help='Output complete MCP tool schema (JSON)')274parser.add_argument('--name', action='store_true',275help='Output tool name from schema')276parser.add_argument('--title', action='store_true',277help='Output tool title from schema')278parser.add_argument('--description', action='store_true',279help='Output tool description from schema')280parser.add_argument('--inputSchema', action='store_true',281help='Output input schema')282parser.add_argument('--outputSchema', action='store_true',283help='Output output schema')284parser.add_argument('--annotations', action='store_true',285help='Output annotations from schema')286287# Tool functionality options288parser.add_argument('--coin_id', type=str, help='Coin id (e.g., bitcoin) or symbol (e.g., BTC)')289parser.add_argument('--vs_currency', type=str, default='usd', help='Target currency (default: usd)')290parser.add_argument('--from_timestamp', type=str,291help='Start time - supports: Unix timestamp, ISO date (2023-01-01), natural language ("2 weeks ago", "last month")')292parser.add_argument('--to_timestamp', type=str,293help='End time - same formats as from_timestamp')294295args = parser.parse_args()296297# Handle MCP schema queries first298if args.schema:299print(json.dumps(MCP_TOOL_SCHEMA, indent=2, sort_keys=True))300return301elif args.name:302print(MCP_TOOL_SCHEMA["name"])303return304elif args.title:305print(MCP_TOOL_SCHEMA["title"])306return307elif args.description:308print(MCP_TOOL_SCHEMA["description"])309return310elif args.inputSchema:311print(json.dumps(MCP_TOOL_SCHEMA["inputSchema"], indent=2, sort_keys=True))312return313elif args.outputSchema:314print(json.dumps(MCP_TOOL_SCHEMA["outputSchema"], indent=2, sort_keys=True))315return316elif args.annotations:317print(json.dumps(MCP_TOOL_SCHEMA["annotations"], indent=2, sort_keys=True))318return319320# Check required arguments only if not showing example321if not args.coin_id:322parser.error("--coin_id is required")323if not args.from_timestamp:324parser.error("--from_timestamp is required")325if not args.to_timestamp:326parser.error("--to_timestamp is required")327328try:329# Call the main function to fetch historical chart data using the provided arguments330data = get_coin_historical_chart_range_by_id(331coin_id=args.coin_id,332vs_currency=args.vs_currency,333from_timestamp=args.from_timestamp,334to_timestamp=args.to_timestamp335)336337# Print the result as pretty-formatted JSON338print(json.dumps(data, ensure_ascii=False, indent=2))339340except Exception as e:341# Print error message if the API call fails342print(f"Failed to fetch historical chart data: {e}")343344345if __name__ == "__main__":346main()