
Coingecko
- 7.7k installs
- 18 repo stars
- Updated July 27, 2026
- starchild-ai-agent/official-skills
coingecko is an agent skill that |.
About
| --- name: coingecko version: 2.0.4 description: | Crypto spot prices, OHLC charts, market discovery, and global stats. Use when looking up coin prices, market caps, trending coins, sector rankings, or comparing tokens (e.g. BTC price, ETH chart, top gainers). delivery: script metadata: starchild: emoji: 🦎 skillKey: coingecko requires: env: - COINGECKO_API_KEY user-invocable: false disable-model-invocation: false --- ## Script Usage Script-mode skill - read this file, then invoke from a `bash` block: ```bash python3 - <<'EOF' import sys, json sys.path.insert(0, "/data/workspace/skills/coingecko") from exports import coin_price, cg_trending, cg_global print(coin_price(coin_ids="bitcoin,ethereum")) print(cg_trending()) EOF ``` Read `exports.py` for the full list of available functions. Common ones: `coin_price`, `coin_ohlc`, `coin_chart`, `cg_trending`, `cg_top_gainers_losers`, `cg_new_coins`, `cg_global`, `cg_global_defi`, `cg_categories`, `cg_derivatives`, `cg_coins_markets`, `cg_coin_data`, `cg_coin_tickers`, `cg_search`, `cg_token_price`, `cg_coin_by_contract`. # CoinGecko Skill ## Function Reference (signatures) All public functions are in `exports.py`. `coin_id` is the Coin
- ❌ `web_search` / `web_fetch` - ALL data is available via native CoinGecko tools above. NEVER use web_search for crypto
- ❌ `bash` for data processing - CoinGecko tools return clean data. No bash needed.
- ❌ **NEVER answer with training data** - all prices, rankings, OHLC are stale. CALL THE TOOL.
- Prices: always use `$` sign → `$66,697`
- Percentages: always use `%` → `+4.2%`
Coingecko by the numbers
- 7,730 all-time installs (skills.sh)
- +63 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #98 of 1,881 Marketing & SEO skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
coingecko capabilities & compatibility
- Capabilities
- ❌ `web_search` / `web_fetch` — all data is avail · ❌ `bash` for data processing — coingecko tools r · ❌ **never answer with training data** — all pric · prices: always use `$` sign → `$66,697` · percentages: always use `%` → `+4.2%`
- Use cases
- documentation
What coingecko says it does
--- name: coingecko version: 2.0.4 description: | Crypto spot prices, OHLC charts, market discovery, and global stats.
Use when looking up coin prices, market caps, trending coins, sector rankings, or comparing tokens (e.g.
# CoinGecko Skill ## Function Reference (signatures) All public functions are in `exports.py`.
`bitcoin`, `ethereum`) — use `cg_search(query)` first if unsure.
npx skills add https://github.com/starchild-ai-agent/official-skills --skill coingeckoAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 7.7k |
|---|---|
| repo stars | ★ 18 |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | starchild-ai-agent/official-skills ↗ |
What problem does coingecko solve for developers using this skill?
|
Who is it for?
Developers who need coingecko patterns described in the cached skill documentation.
Skip if: Skip when docs are empty or the task is outside the skill's documented scope.
When should I use this skill?
|
What you get
Actionable workflows and conventions from SKILL.md for coingecko.
- Registered agent market-data tools
- Live price and chart responses
- Trending and exchange discovery results
Files
Script Usage
Script-mode skill — read this file, then invoke from a bash block:
python3 - <<'EOF'
import sys, json
sys.path.insert(0, "/data/workspace/skills/coingecko")
from exports import coin_price, cg_trending, cg_global
print(coin_price(coin_ids="bitcoin,ethereum"))
print(cg_trending())
EOFRead exports.py for the full list of available functions. Common ones: coin_price, coin_ohlc, coin_chart, cg_trending, cg_top_gainers_losers, cg_new_coins, cg_global, cg_global_defi, cg_categories, cg_derivatives, cg_coins_markets, cg_coin_data, cg_coin_tickers, cg_search, cg_token_price, cg_coin_by_contract.
CoinGecko Skill
Function Reference (signatures)
All public functions are in exports.py. coin_id is the CoinGecko id (e.g. bitcoin, ethereum) — use cg_search(query) first if unsure. vs_currency defaults to usd.
Prices & Charts
| Function | Description |
|---|---|
coin_price(coin_ids, timestamps=None, vs_currency='usd') | Current or historical price. coin_ids = comma-string like "bitcoin,ethereum". timestamps = list of unix ts for historical (default: now). |
coin_ohlc(coin_id, days=30, vs_currency='usd') | OHLC bars for last N days. Returns list of [ts, o, h, l, c]. Granularity auto-selected: 1d=30min, 7-30d=4h, 30d+=4h. |
coin_chart(coin_id, days=30, vs_currency='usd') | Price + market_cap + total_volume timeseries. Returns {prices, market_caps, total_volumes} (each list of [ts, val]). |
Discovery
| Function | Description |
|---|---|
cg_trending() | Trending coins, NFTs, categories (last 24h). |
cg_top_gainers_losers(vs_currency='usd', duration='24h') | Top gainers/losers. duration = 1h/24h/7d/14d/30d/60d/1y. |
cg_new_coins() | Recently listed coins. |
cg_search(query) | Search coins/exchanges/categories by name. |
Market Data
| Function | Description |
|---|---|
cg_global() | Global crypto market: total market_cap, volume, dominance. |
cg_global_defi() | Global DeFi: TVL, dominance, top protocols. |
cg_coins_markets(vs_currency='usd', order='market_cap_desc', per_page=100, page=1, sparkline=False, price_change_percentage='24h', category=None, ids=None) | Top coins with full market data. |
cg_coin_data(coin_id, localization=False, tickers=False, market_data=True, community_data=False, developer_data=False, sparkline=False) | Detailed data for one coin. |
cg_coin_tickers(coin_id, exchange_ids=None, include_exchange_logo=False, page=1, order='volume_desc', depth=False) | Where a coin trades + volumes. |
cg_coins_list(include_platform=False) | All coin ids/symbols (for resolving). |
Categories / Derivatives / NFTs
| Function | Description |
|---|---|
cg_categories(order='market_cap_desc') | Top categories with market_cap and volume. |
cg_categories_list() | Just category ids/names. |
cg_derivatives(include_tickers='unexpired') | Derivatives tickers across exchanges. |
cg_derivatives_exchanges(order='open_interest_btc_desc', per_page=50) | Derivatives exchange rankings. |
cg_nfts_list(order='market_cap_usd_desc', per_page=100, page=1) | Top NFT collections. |
cg_nft(nft_id) | NFT collection detail. |
cg_nft_by_contract(asset_platform, contract_address) | NFT by contract address. |
Exchanges
| Function | Description |
|---|---|
cg_exchanges(per_page=100, page=1) | Exchange rankings. |
cg_exchange(exchange_id) | One exchange's detail. |
cg_exchange_tickers(exchange_id, ...) | Tickers on an exchange. |
cg_exchange_volume_chart(exchange_id, days=30) | Exchange volume history. |
Contracts / Tokens (by platform)
| Function | Description |
|---|---|
cg_token_price(platform, contract_addresses, vs_currencies='usd', include_market_cap=False, include_24hr_vol=False, include_24hr_change=False, include_last_updated_at=False) | Price by contract address on a platform. |
cg_coin_by_contract(platform, contract_address) | Coin metadata by contract. |
cg_asset_platforms(filter=None) | Supported chains. |
cg_vs_currencies() | Supported quote currencies. |
cg_exchange_rates() | BTC-denominated rates for fiat/major coins. |
🚫 CRITICAL: STOP — READ THIS BEFORE CALLING ANY TOOL
The #1 error is calling Coinglass tools instead of CoinGecko tools. They have similar names but are COMPLETELY DIFFERENT systems.
WRONG → RIGHT Tool Substitution Table
| ❌ NEVER call this | ✅ Call this instead | How to tell them apart |
|---|---|---|
cg_coins_market_data | `cg_coins_markets` | market_data=Coinglass derivatives. markets=CoinGecko spot. |
cg_ohlc_history | `coin_ohlc` | ohlc_history=Coinglass futures candles. coin_ohlc=CoinGecko spot candles. |
cg_pair_market_data | `cg_coin_tickers` | pair_market_data=Coinglass futures pair. coin_tickers=CoinGecko spot pairs. |
cg_supported_exchanges | `cg_exchanges` | supported_exchanges=Coinglass futures. exchanges=CoinGecko spot. |
cg_taker_exchanges | `cg_exchange` | taker=Coinglass volume. exchange=CoinGecko exchange info. |
cg_aggregated_taker_volume | `cg_coin_tickers` | taker_volume=Coinglass. coin_tickers=CoinGecko volume across exchanges. |
defillama_chains | `cg_global_defi` | For DeFi stats from CoinGecko, use cg_global_defi(). |
Also FORBIDDEN:
- ❌
web_search/web_fetch— ALL data is available via native CoinGecko tools above. NEVER use web_search for crypto market data. - ❌
bashfor data processing — CoinGecko tools return clean data. No bash needed. - ❌ NEVER answer with training data — all prices, rankings, OHLC are stale. CALL THE TOOL.
⚠️ MANDATORY TOOL CALLS — You MUST call a tool before answering these
| Request type | You MUST call | Why |
|---|---|---|
| K线 / OHLC / candlestick / open high low close | coin_ohlc(coin_id, days) | Price data is real-time; training data is stale |
| 走势图 / price chart / 价格趋势 | coin_chart(coin_id, days) | Same reason |
| 当前价格 / price right now | coin_price(coin_ids) | Training data has no live prices |
DO NOT return any numeric market data (prices, OHLC values, percentages) without calling a tool first.
⚡ Question → Tool Map (match first keyword, call immediately)
| Question keyword | Tool to call | Example |
|---|---|---|
| 价格 / price / 多少钱 (single coin) | coin_price(coin_id) | coin_price(coin_ids="bitcoin") |
| K线 / OHLC / candlestick / 蜡烛图 | coin_ohlc(coin_id, days) | coin_ohlc(coin_id="ethereum", days=7) |
| 走势 / trend / price chart / 价格历史 | coin_chart(coin_id, days) | coin_chart(coin_id="solana", days=30) |
| 热门 / trending / 趋势币 | cg_trending() | cg_trending() |
| 涨幅最大 / 跌幅最大 / gainers / losers | cg_top_gainers_losers() | cg_top_gainers_losers() |
| 新币 / 新上线 / new coins / recently added | cg_new_coins() | cg_new_coins() |
| 总市值 / BTC市占率 / global / 晨报 / 市场概况 | cg_global() | cg_global() |
| DeFi总市值 / DeFi TVL / DeFi dominance | cg_global_defi() | cg_global_defi() |
| 板块 / sector / category / L1 / L2 / Meme / AI coins | cg_categories() | cg_categories() |
| 板块内个币 / Meme前10 / AI币排名 / DeFi币排名 | cg_coins_markets(category=X) | cg_coins_markets(category="meme-token", per_page=10) |
| 市值排名 / top 10 / ranking / 前10币 | cg_coins_markets(per_page=N) | cg_coins_markets(per_page=10) |
| ATH / 历史最高 / 社区 / dev / 研究 / fundamentals | cg_coin_data(coin_id) | cg_coin_data(coin_id="solana", community_data=True) |
| 对比两个币 / compare / XX vs YY | cg_coin_data() × 2 | call once per coin |
| NFT排名 / NFT市场 / floor price / top NFTs | cg_nfts_list() | cg_nfts_list() |
| 某个NFT (BAYC/Punks/Azuki) | cg_nft(nft_id) | cg_nft(nft_id="bored-ape-yacht-club") |
| 交易所详情 / Binance详情 / exchange data | cg_exchange(exchange_id) | cg_exchange(exchange_id="binance") |
| 交易所列表 / exchange ranking | cg_exchanges() | cg_exchanges() |
| 交易对 / trading pairs / 流动性分布 | cg_coin_tickers(coin_id) | cg_coin_tickers(coin_id="bitcoin") |
| 交易所交易量趋势 / volume chart | cg_exchange_volume_chart(exchange_id) | cg_exchange_volume_chart(exchange_id="binance", days=30) |
| 合约地址价格 / token price on-chain | cg_token_price(platform, contract) | cg_token_price(platform="ethereum", contract_addresses="0xa0b...") |
| 搜索币 / 找币 / coin lookup / search | cg_search(query) | cg_search(query="pepe") |
| 永续合约交易所 / derivatives exchange / OI排名 | cg_derivatives_exchanges() | cg_derivatives_exchanges() |
| 合约ticker / perpetual / funding / basis | cg_derivatives() | cg_derivatives() |
| 交易所对比 + 永续交易所 | cg_exchanges() + cg_derivatives_exchanges() | both calls |
🌳 Decision Tree
How many coins?
├─ ONE coin
│ ├─ Just price? → coin_price()
│ ├─ ATH/community/dev/deep? → cg_coin_data()
│ ├─ OHLC candles? → coin_ohlc()
│ ├─ Price trend? → coin_chart()
│ └─ Unknown ID? → cg_search() first
├─ MULTIPLE coins / ranking
│ ├─ Sector aggregate (板块总市值)? → cg_categories()
│ ├─ Sector individual (Meme前10)? → cg_coins_markets(category=X)
│ └─ General ranking? → cg_coins_markets(per_page=N)
├─ NFTs → cg_nfts_list() or cg_nft(nft_id)
├─ Exchange → cg_exchange(id) or cg_exchanges()
├─ Global → cg_global() or cg_global_defi()
└─ Token by contract → cg_token_price()Common Category IDs
meme-token, artificial-intelligence, layer-1, layer-2, decentralized-finance-defi, gaming, real-world-assets-rwa
Output Formatting
- Prices: always use
$sign →$66,697 - Percentages: always use
%→+4.2% - NFT floor in ETH: show USD too →
5.17 ETH ($10,534)
Important Notes
- CoinGecko uses slug IDs: "bitcoin", "ethereum", "solana". Symbols (BTC, ETH, SOL) auto-resolve.
- If unsure about a coin ID →
cg_search(query="coin name")first. - Most questions need only 1-2 tool calls. Do NOT chain 3+ calls.
Common Issues
coin_price failed with invalid ID
Solution: Use cg_search(query="coin name") to find the correct CoinGecko ID first, or use the symbol directly (e.g., 'COMP').
---
"""
CoinGecko Extension - Crypto Market Data Tools
Provides comprehensive crypto market data including:
- Price data, charts, OHLC candles
- Market discovery (trending, top gainers/losers, new coins)
- Coin information and tickers
- Exchange data
- NFT collections
- Global market stats
Environment Variables Required:
- COINGECKO_API_KEY: CoinGecko Pro API key
Usage:
This extension is auto-loaded by the ExtensionLoader.
Tools are available to agents configured with these tools in agents.yaml.
"""
import os
import sys
import logging
from typing import List
try:
from core.tool import ToolRegistry
except Exception:
ToolRegistry = None # Standalone script usage
logger = logging.getLogger(__name__)
# Add local tools directory to path for imports
TOOLS_DIR = os.path.join(os.path.dirname(__file__), 'tools')
if TOOLS_DIR not in sys.path:
sys.path.insert(0, TOOLS_DIR)
def register(api) -> List[str]:
"""
Extension entry point - register all CoinGecko tools.
Args:
api: ExtensionApi instance with registry and config
Returns:
List of registered tool names
"""
registered = []
try:
from .coingecko import (
# Original tools (11)
CoinPriceTool,
CoinOHLCTool,
CoinChartTool,
CoinGeckoTrendingTool,
CoinGeckoTopGainersLosersTool,
CoinGeckoNewCoinsTool,
CoinGeckoGlobalTool,
CoinGeckoGlobalDefiTool,
CoinGeckoDerivativesTool,
CoinGeckoDerivativesExchangesTool,
CoinGeckoCategoriesjTool,
# New coin data tools (4)
CoinGeckoCoinsListTool,
CoinGeckoCoinsMarketsTool,
CoinGeckoCoinDataTool,
CoinGeckoCoinTickersTool,
# New exchange tools (4)
CoinGeckoExchangesTool,
CoinGeckoExchangeTool,
CoinGeckoExchangeTickersTool,
CoinGeckoExchangeVolumeChartTool,
# New NFT tools (3)
CoinGeckoNFTsListTool,
CoinGeckoNFTTool,
CoinGeckoNFTByContractTool,
# New infrastructure tools (4)
CoinGeckoAssetPlatformsTool,
CoinGeckoExchangeRatesTool,
CoinGeckoVsCurrenciesTool,
CoinGeckoCategoriesListTool,
# New search tool (1)
CoinGeckoSearchTool,
# New contract tools (2)
CoinGeckoTokenPriceTool,
CoinGeckoCoinByContractTool,
)
# Register original tools
api.register_tool(CoinPriceTool())
api.register_tool(CoinOHLCTool())
api.register_tool(CoinChartTool())
api.register_tool(CoinGeckoTrendingTool())
api.register_tool(CoinGeckoTopGainersLosersTool())
api.register_tool(CoinGeckoNewCoinsTool())
api.register_tool(CoinGeckoGlobalTool())
api.register_tool(CoinGeckoGlobalDefiTool())
api.register_tool(CoinGeckoDerivativesTool())
api.register_tool(CoinGeckoDerivativesExchangesTool())
api.register_tool(CoinGeckoCategoriesjTool())
# Register new coin data tools
api.register_tool(CoinGeckoCoinsListTool())
api.register_tool(CoinGeckoCoinsMarketsTool())
api.register_tool(CoinGeckoCoinDataTool())
api.register_tool(CoinGeckoCoinTickersTool())
# Register new exchange tools
api.register_tool(CoinGeckoExchangesTool())
api.register_tool(CoinGeckoExchangeTool())
api.register_tool(CoinGeckoExchangeTickersTool())
api.register_tool(CoinGeckoExchangeVolumeChartTool())
# Register new NFT tools
api.register_tool(CoinGeckoNFTsListTool())
api.register_tool(CoinGeckoNFTTool())
api.register_tool(CoinGeckoNFTByContractTool())
# Register new infrastructure tools
api.register_tool(CoinGeckoAssetPlatformsTool())
api.register_tool(CoinGeckoExchangeRatesTool())
api.register_tool(CoinGeckoVsCurrenciesTool())
api.register_tool(CoinGeckoCategoriesListTool())
# Register new search tool
api.register_tool(CoinGeckoSearchTool())
# Register new contract tools
api.register_tool(CoinGeckoTokenPriceTool())
api.register_tool(CoinGeckoCoinByContractTool())
registered.extend([
# Original (11)
"coin_price",
"coin_ohlc",
"coin_chart",
"cg_trending",
"cg_top_gainers_losers",
"cg_new_coins",
"cg_global",
"cg_global_defi",
"cg_derivatives",
"cg_derivatives_exchanges",
"cg_categories",
# New coin data (4)
"cg_coins_list",
"cg_coins_markets",
"cg_coin_data",
"cg_coin_tickers",
# New exchanges (4)
"cg_exchanges",
"cg_exchange",
"cg_exchange_tickers",
"cg_exchange_volume_chart",
# New NFTs (3)
"cg_nfts_list",
"cg_nft",
"cg_nft_by_contract",
# New infrastructure (4)
"cg_asset_platforms",
"cg_exchange_rates",
"cg_vs_currencies",
"cg_categories_list",
# New search (1)
"cg_search",
# New contracts (2)
"cg_token_price",
"cg_coin_by_contract",
])
logger.info("Registered CoinGecko tools (29 tools)")
except Exception as e:
logger.warning(f"Failed to load CoinGecko tools: {e}")
return registered
# Extension metadata
EXTENSION_INFO = {
"name": "coingecko",
"version": "1.0.0",
"description": "CoinGecko crypto market data tools",
"tools": [
# Price & Chart (3)
"coin_price",
"coin_ohlc",
"coin_chart",
# Market Discovery (3)
"cg_trending",
"cg_top_gainers_losers",
"cg_new_coins",
# Global & Categories (3)
"cg_global",
"cg_global_defi",
"cg_categories",
# Derivatives (2)
"cg_derivatives",
"cg_derivatives_exchanges",
# Coin Data (4)
"cg_coins_list",
"cg_coins_markets",
"cg_coin_data",
"cg_coin_tickers",
# Exchanges (4)
"cg_exchanges",
"cg_exchange",
"cg_exchange_tickers",
"cg_exchange_volume_chart",
# NFTs (3)
"cg_nfts_list",
"cg_nft",
"cg_nft_by_contract",
# Infrastructure (5)
"cg_asset_platforms",
"cg_exchange_rates",
"cg_vs_currencies",
"cg_categories_list",
"cg_search",
# Contracts (2)
"cg_token_price",
"cg_coin_by_contract",
],
"env_vars": [
"COINGECKO_API_KEY",
],
}
"""
CoinGecko Tool Wrappers
Wraps tools from /tools/coingecko/ for use in Agent framework.
Provides price data, charts, market discovery, global stats, derivatives,
exchanges, NFTs, infrastructure, search, and contract lookups.
"""
import asyncio
import logging
from typing import List, Optional
from core.tool import BaseTool, ToolContext, ToolResult
logger = logging.getLogger(__name__)
# Import original tools from local tools directory
try:
from .tools.coin_prices import get_coin_prices_at_timestamps
from .tools.coin_ohlc_range_by_id import get_coin_ohlc_range_by_id
from .tools.coin_historical_chart_range_by_id import get_coin_historical_chart_range_by_id
from .tools.market_discovery import (
get_trending,
get_top_gainers_losers,
get_new_coins,
)
from .tools.global_data import (
get_global,
get_global_defi,
)
from .tools.derivatives import (
get_derivatives,
get_derivatives_exchanges,
get_categories,
)
# New imports for expanded API coverage
from .tools.coins import (
get_coins_list,
get_coins_markets,
get_coin_data,
get_coin_tickers,
)
from .tools.exchanges import (
get_exchanges,
get_exchange,
get_exchange_tickers,
get_exchange_volume_chart,
)
from .tools.nfts import (
get_nfts_list,
get_nft,
get_nft_by_contract,
)
from .tools.infrastructure import (
get_asset_platforms,
get_exchange_rates,
get_vs_currencies,
get_categories_list,
)
from .tools.search import search
from .tools.contracts import (
get_token_price,
get_coin_by_contract,
)
COINGECKO_AVAILABLE = True
except ImportError as e:
logger.warning(f"CoinGecko tools not available: {e}")
COINGECKO_AVAILABLE = False
class CoinPriceTool(BaseTool):
"""
Get cryptocurrency prices at specific timestamps.
Supports current price ("now") and historical prices.
Accepts coin IDs (bitcoin, ethereum) or symbols (BTC, ETH).
"""
@property
def name(self) -> str:
return "coin_price"
@property
def description(self) -> str:
return """Get cryptocurrency prices. Supports current ("now") and historical prices.
If unsure about the coin ID, first use cg_search to find the correct ID.
Examples:
- Get BTC current price: coin_price(coin_ids="bitcoin")
- Get multiple coins: coin_price(coin_ids="BTC,ETH,SOL")
- Get historical price: coin_price(coin_ids="bitcoin", timestamps=["2024-01-01"])"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"coin_ids": {
"type": "string",
"description": "Coin ID or symbol (bitcoin, BTC) or comma-separated list (BTC,ETH,SOL)"
},
"timestamps": {
"type": "array",
"items": {"type": "string"},
"description": "List of timestamps. Use 'now' for current price, or date strings like '2024-01-01'",
"default": ["now"]
},
"vs_currency": {
"type": "string",
"description": "Target currency (usd, eur, btc)",
"default": "usd"
}
},
"required": ["coin_ids"]
}
async def execute(
self,
ctx: ToolContext,
coin_ids: str,
timestamps: Optional[List[str]] = None,
vs_currency: str = "usd"
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available. Check if /tools/coingecko exists."
)
try:
result = await asyncio.to_thread(
get_coin_prices_at_timestamps,
coin_ids=coin_ids,
timestamps=timestamps or ["now"],
vs_currency=vs_currency
)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinOHLCTool(BaseTool):
"""
Get OHLC (candlestick) data for a cryptocurrency.
"""
@property
def name(self) -> str:
return "coin_ohlc"
@property
def description(self) -> str:
return """Get OHLC candlestick data for technical analysis.
Examples:
- Get BTC daily OHLC for last 30 days: coin_ohlc(coin_id="bitcoin", days=30)
- Get ETH 4h candles: coin_ohlc(coin_id="ethereum", days=7)"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"coin_id": {
"type": "string",
"description": "CoinGecko coin ID (bitcoin, ethereum, solana)"
},
"days": {
"type": "integer",
"description": "Number of days (1, 7, 14, 30, 90, 180, 365)",
"default": 30
},
"vs_currency": {
"type": "string",
"description": "Target currency",
"default": "usd"
}
},
"required": ["coin_id"]
}
async def execute(
self,
ctx: ToolContext,
coin_id: str,
days: int = 30,
vs_currency: str = "usd"
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
import time
to_timestamp = int(time.time())
from_timestamp = to_timestamp - (days * 24 * 60 * 60)
result = await asyncio.to_thread(
get_coin_ohlc_range_by_id,
coin_id=coin_id,
from_timestamp=from_timestamp,
to_timestamp=to_timestamp
)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinChartTool(BaseTool):
"""
Get historical price chart data for a cryptocurrency.
"""
@property
def name(self) -> str:
return "coin_chart"
@property
def description(self) -> str:
return """Get historical price chart data (prices, market caps, volumes).
Examples:
- Get BTC 30-day chart: coin_chart(coin_id="bitcoin", days=30)
- Get ETH 7-day chart: coin_chart(coin_id="ethereum", days=7)"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"coin_id": {
"type": "string",
"description": "CoinGecko coin ID"
},
"days": {
"type": "integer",
"description": "Number of days of data",
"default": 30
},
"vs_currency": {
"type": "string",
"default": "usd"
}
},
"required": ["coin_id"]
}
async def execute(
self,
ctx: ToolContext,
coin_id: str,
days: int = 30,
vs_currency: str = "usd"
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
import time
to_timestamp = int(time.time())
from_timestamp = to_timestamp - (days * 24 * 60 * 60)
result = await asyncio.to_thread(
get_coin_historical_chart_range_by_id,
coin_id=coin_id,
vs_currency=vs_currency,
from_timestamp=from_timestamp,
to_timestamp=to_timestamp
)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== Market Discovery Tools ====================
class CoinGeckoTrendingTool(BaseTool):
"""
Get trending coins based on user search data.
"""
@property
def name(self) -> str:
return "cg_trending"
@property
def description(self) -> str:
return """Get trending coins in the last 24 hours based on user search data.
Also returns trending NFTs and categories.
Examples:
- Get trending: cg_trending()"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {}
}
async def execute(self, ctx: ToolContext) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_trending)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoTopGainersLosersTool(BaseTool):
"""
Get top gainers and losers by price change.
"""
@property
def name(self) -> str:
return "cg_top_gainers_losers"
@property
def description(self) -> str:
return """Get top 30 gainers and losers by price change percentage.
Examples:
- Get 24h movers: cg_top_gainers_losers()
- Get 7d movers: cg_top_gainers_losers(duration="7d")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"vs_currency": {
"type": "string",
"description": "Target currency",
"default": "usd"
},
"duration": {
"type": "string",
"description": "Time duration: 1h, 24h, 7d, 14d, 30d, 60d, 1y",
"default": "24h"
}
}
}
async def execute(
self,
ctx: ToolContext,
vs_currency: str = "usd",
duration: str = "24h"
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_top_gainers_losers, vs_currency, duration)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoNewCoinsTool(BaseTool):
"""
Get recently added coins.
"""
@property
def name(self) -> str:
return "cg_new_coins"
@property
def description(self) -> str:
return """Get recently added coins to CoinGecko.
Examples:
- Get new coins: cg_new_coins()"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {}
}
async def execute(self, ctx: ToolContext) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_new_coins)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== Global Data Tools ====================
class CoinGeckoGlobalTool(BaseTool):
"""
Get global cryptocurrency market statistics.
"""
@property
def name(self) -> str:
return "cg_global"
@property
def description(self) -> str:
return """Get global cryptocurrency market statistics.
Returns total market cap, volume, BTC dominance, and more.
Examples:
- Get global stats: cg_global()"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {}
}
async def execute(self, ctx: ToolContext) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_global)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoGlobalDefiTool(BaseTool):
"""
Get global DeFi market statistics.
"""
@property
def name(self) -> str:
return "cg_global_defi"
@property
def description(self) -> str:
return """Get global DeFi market statistics.
Returns DeFi market cap, TVL, DeFi dominance.
Examples:
- Get DeFi stats: cg_global_defi()"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {}
}
async def execute(self, ctx: ToolContext) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_global_defi)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== Derivatives Tools ====================
class CoinGeckoDerivativesTool(BaseTool):
"""
Get all derivatives tickers.
"""
@property
def name(self) -> str:
return "cg_derivatives"
@property
def description(self) -> str:
return """Get all derivatives tickers (perpetuals, futures).
Includes funding rates, open interest, spread, basis.
Examples:
- Get all derivatives: cg_derivatives()
- Get unexpired only: cg_derivatives(include_tickers="unexpired")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"include_tickers": {
"type": "string",
"description": "Filter: all or unexpired",
"default": "unexpired"
}
}
}
async def execute(
self,
ctx: ToolContext,
include_tickers: str = "unexpired"
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_derivatives, include_tickers)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoDerivativesExchangesTool(BaseTool):
"""
Get derivatives exchanges with rankings.
"""
@property
def name(self) -> str:
return "cg_derivatives_exchanges"
@property
def description(self) -> str:
return """Get list of derivatives exchanges with ranking.
Sorted by open interest or volume.
Examples:
- Get exchanges by OI: cg_derivatives_exchanges()
- Get exchanges by volume: cg_derivatives_exchanges(order="trade_volume_24h_btc_desc")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"order": {
"type": "string",
"description": "Sort order",
"default": "open_interest_btc_desc"
},
"per_page": {
"type": "integer",
"description": "Results per page (max 100)",
"default": 50
}
}
}
async def execute(
self,
ctx: ToolContext,
order: str = "open_interest_btc_desc",
per_page: int = 50
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_derivatives_exchanges, order, per_page)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoCategoriesjTool(BaseTool):
"""
Get coin categories with market data.
"""
@property
def name(self) -> str:
return "cg_categories"
@property
def description(self) -> str:
return """Get coin categories with market data (DeFi, L1, L2, Memes, etc.).
See sector performance and top coins in each category.
Examples:
- Get categories by market cap: cg_categories()
- Get categories by 24h change: cg_categories(order="market_cap_change_24h_desc")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"order": {
"type": "string",
"description": "Sort order: market_cap_desc, market_cap_change_24h_desc, etc.",
"default": "market_cap_desc"
}
}
}
async def execute(
self,
ctx: ToolContext,
order: str = "market_cap_desc"
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_categories, order)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== Coin Data Tools ====================
class CoinGeckoCoinsListTool(BaseTool):
"""
Get all supported coins with IDs, names, and symbols.
"""
@property
def name(self) -> str:
return "cg_coins_list"
@property
def description(self) -> str:
return """Get all supported coins with id, symbol, and name.
Useful for coin discovery and ID lookup.
Examples:
- Get all coins: cg_coins_list()
- Get coins with platform addresses: cg_coins_list(include_platform=True)"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"include_platform": {
"type": "boolean",
"description": "Include platform contract addresses",
"default": False
}
}
}
async def execute(
self,
ctx: ToolContext,
include_platform: bool = False
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_coins_list, include_platform)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoCoinsMarketsTool(BaseTool):
"""
Get bulk market data for coins with sorting and filtering.
"""
@property
def name(self) -> str:
return "cg_coins_markets"
@property
def description(self) -> str:
return """Get market data for coins with sorting, filtering, and pagination.
Screen coins by market cap, volume, price change, or category.
Examples:
- Get top 100 by market cap: cg_coins_markets()
- Get top by volume: cg_coins_markets(order="volume_desc")
- Get DeFi coins: cg_coins_markets(category="decentralized-finance-defi")
- Get specific coins: cg_coins_markets(ids="bitcoin,ethereum,solana")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"vs_currency": {
"type": "string",
"description": "Target currency (usd, eur, btc)",
"default": "usd"
},
"order": {
"type": "string",
"description": "Sort order: market_cap_desc, volume_desc, price_change_24h_desc",
"default": "market_cap_desc"
},
"per_page": {
"type": "integer",
"description": "Results per page (max 250)",
"default": 100
},
"page": {
"type": "integer",
"description": "Page number",
"default": 1
},
"sparkline": {
"type": "boolean",
"description": "Include 7-day sparkline data",
"default": False
},
"price_change_percentage": {
"type": "string",
"description": "Price change periods (comma-separated): 1h, 24h, 7d, 14d, 30d, 200d, 1y",
"default": "24h"
},
"category": {
"type": "string",
"description": "Filter by category id"
},
"ids": {
"type": "string",
"description": "Comma-separated coin ids to filter"
}
}
}
async def execute(
self,
ctx: ToolContext,
vs_currency: str = "usd",
order: str = "market_cap_desc",
per_page: int = 100,
page: int = 1,
sparkline: bool = False,
price_change_percentage: str = "24h",
category: Optional[str] = None,
ids: Optional[str] = None
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(
get_coins_markets,
vs_currency=vs_currency,
order=order,
per_page=per_page,
page=page,
sparkline=sparkline,
price_change_percentage=price_change_percentage,
category=category,
ids=ids
)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoCoinDataTool(BaseTool):
"""
Get full coin metadata including description, links, ATH, ATL.
"""
@property
def name(self) -> str:
return "cg_coin_data"
@property
def description(self) -> str:
return """Get comprehensive coin data including description, links, ATH, ATL, market data.
Deep research on specific coin.
Examples:
- Get Bitcoin data: cg_coin_data(coin_id="bitcoin")
- Include tickers: cg_coin_data(coin_id="ethereum", tickers=True)
- Full data: cg_coin_data(coin_id="solana", community_data=True, developer_data=True)"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"coin_id": {
"type": "string",
"description": "CoinGecko coin ID (bitcoin, ethereum, solana)"
},
"localization": {
"type": "boolean",
"description": "Include localized languages",
"default": False
},
"tickers": {
"type": "boolean",
"description": "Include tickers data",
"default": False
},
"market_data": {
"type": "boolean",
"description": "Include market data",
"default": True
},
"community_data": {
"type": "boolean",
"description": "Include community data",
"default": False
},
"developer_data": {
"type": "boolean",
"description": "Include developer data",
"default": False
},
"sparkline": {
"type": "boolean",
"description": "Include sparkline 7 days data",
"default": False
}
},
"required": ["coin_id"]
}
async def execute(
self,
ctx: ToolContext,
coin_id: str,
localization: bool = False,
tickers: bool = False,
market_data: bool = True,
community_data: bool = False,
developer_data: bool = False,
sparkline: bool = False
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(
get_coin_data,
coin_id=coin_id,
localization=localization,
tickers=tickers,
market_data=market_data,
community_data=community_data,
developer_data=developer_data,
sparkline=sparkline
)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoCoinTickersTool(BaseTool):
"""
Get all trading pairs/tickers for a coin across exchanges.
"""
@property
def name(self) -> str:
return "cg_coin_tickers"
@property
def description(self) -> str:
return """Get all trading pairs/tickers for a coin across exchanges.
Find liquidity and arbitrage opportunities.
Examples:
- Get BTC tickers: cg_coin_tickers(coin_id="bitcoin")
- Filter by exchange: cg_coin_tickers(coin_id="ethereum", exchange_ids="binance")
- With depth: cg_coin_tickers(coin_id="solana", depth=True)"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"coin_id": {
"type": "string",
"description": "CoinGecko coin ID"
},
"exchange_ids": {
"type": "string",
"description": "Comma-separated exchange ids to filter"
},
"include_exchange_logo": {
"type": "boolean",
"description": "Include exchange logo",
"default": False
},
"page": {
"type": "integer",
"description": "Page number",
"default": 1
},
"order": {
"type": "string",
"description": "Sort order: trust_score_desc, volume_desc",
"default": "volume_desc"
},
"depth": {
"type": "boolean",
"description": "Include order book depth",
"default": False
}
},
"required": ["coin_id"]
}
async def execute(
self,
ctx: ToolContext,
coin_id: str,
exchange_ids: Optional[str] = None,
include_exchange_logo: bool = False,
page: int = 1,
order: str = "volume_desc",
depth: bool = False
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(
get_coin_tickers,
coin_id=coin_id,
exchange_ids=exchange_ids,
include_exchange_logo=include_exchange_logo,
page=page,
order=order,
depth=depth
)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== Exchange Tools ====================
class CoinGeckoExchangesTool(BaseTool):
"""
Get all spot exchanges with volumes and trust scores.
"""
@property
def name(self) -> str:
return "cg_exchanges"
@property
def description(self) -> str:
return """Get all spot exchanges with volumes and trust scores.
Compare exchanges by volume and trust.
Examples:
- Get top 100 exchanges: cg_exchanges()
- Paginate: cg_exchanges(per_page=50, page=2)"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"per_page": {
"type": "integer",
"description": "Results per page (max 250)",
"default": 100
},
"page": {
"type": "integer",
"description": "Page number",
"default": 1
}
}
}
async def execute(
self,
ctx: ToolContext,
per_page: int = 100,
page: int = 1
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_exchanges, per_page, page)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoExchangeTool(BaseTool):
"""
Get detailed exchange data.
"""
@property
def name(self) -> str:
return "cg_exchange"
@property
def description(self) -> str:
return """Get detailed exchange data including tickers and BTC volume.
Research specific exchange.
Examples:
- Get Binance data: cg_exchange(exchange_id="binance")
- Get Coinbase data: cg_exchange(exchange_id="coinbase-exchange")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"exchange_id": {
"type": "string",
"description": "CoinGecko exchange ID (binance, coinbase-exchange)"
}
},
"required": ["exchange_id"]
}
async def execute(
self,
ctx: ToolContext,
exchange_id: str
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_exchange, exchange_id)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoExchangeTickersTool(BaseTool):
"""
Get all trading pairs on an exchange.
"""
@property
def name(self) -> str:
return "cg_exchange_tickers"
@property
def description(self) -> str:
return """Get all trading pairs on an exchange.
Find trading opportunities on specific exchange.
Examples:
- Get Binance pairs: cg_exchange_tickers(exchange_id="binance")
- Filter by coin: cg_exchange_tickers(exchange_id="coinbase-exchange", coin_ids="bitcoin")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"exchange_id": {
"type": "string",
"description": "CoinGecko exchange ID"
},
"coin_ids": {
"type": "string",
"description": "Comma-separated coin ids to filter"
},
"include_exchange_logo": {
"type": "boolean",
"description": "Include exchange logo",
"default": False
},
"page": {
"type": "integer",
"description": "Page number",
"default": 1
},
"order": {
"type": "string",
"description": "Sort order: trust_score_desc, volume_desc",
"default": "volume_desc"
},
"depth": {
"type": "boolean",
"description": "Include order book depth",
"default": False
}
},
"required": ["exchange_id"]
}
async def execute(
self,
ctx: ToolContext,
exchange_id: str,
coin_ids: Optional[str] = None,
include_exchange_logo: bool = False,
page: int = 1,
order: str = "volume_desc",
depth: bool = False
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(
get_exchange_tickers,
exchange_id=exchange_id,
coin_ids=coin_ids,
include_exchange_logo=include_exchange_logo,
page=page,
order=order,
depth=depth
)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoExchangeVolumeChartTool(BaseTool):
"""
Get historical volume chart for an exchange.
"""
@property
def name(self) -> str:
return "cg_exchange_volume_chart"
@property
def description(self) -> str:
return """Get historical volume chart for an exchange.
Track exchange growth over time.
Examples:
- Get Binance 30-day volume: cg_exchange_volume_chart(exchange_id="binance")
- Get 90-day history: cg_exchange_volume_chart(exchange_id="coinbase-exchange", days=90)"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"exchange_id": {
"type": "string",
"description": "CoinGecko exchange ID"
},
"days": {
"type": "integer",
"description": "Number of days (1, 7, 14, 30, 90, 180, 365)",
"default": 30
}
},
"required": ["exchange_id"]
}
async def execute(
self,
ctx: ToolContext,
exchange_id: str,
days: int = 30
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_exchange_volume_chart, exchange_id, days)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== NFT Tools ====================
class CoinGeckoNFTsListTool(BaseTool):
"""
Get all NFT collections.
"""
@property
def name(self) -> str:
return "cg_nfts_list"
@property
def description(self) -> str:
return """Get all NFT collections with IDs and contract addresses.
NFT discovery.
Examples:
- Get top NFTs by market cap: cg_nfts_list()
- Sort by volume: cg_nfts_list(order="h24_volume_usd_desc")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"order": {
"type": "string",
"description": "Sort order: market_cap_usd_desc, h24_volume_usd_desc",
"default": "market_cap_usd_desc"
},
"per_page": {
"type": "integer",
"description": "Results per page (max 250)",
"default": 100
},
"page": {
"type": "integer",
"description": "Page number",
"default": 1
}
}
}
async def execute(
self,
ctx: ToolContext,
order: str = "market_cap_usd_desc",
per_page: int = 100,
page: int = 1
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_nfts_list, order, per_page, page)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoNFTTool(BaseTool):
"""
Get NFT collection data.
"""
@property
def name(self) -> str:
return "cg_nft"
@property
def description(self) -> str:
return """Get NFT collection data including floor price, volume, market cap.
NFT research.
Examples:
- Get Bored Apes: cg_nft(nft_id="bored-ape-yacht-club")
- Get CryptoPunks: cg_nft(nft_id="cryptopunks")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"nft_id": {
"type": "string",
"description": "CoinGecko NFT collection ID"
}
},
"required": ["nft_id"]
}
async def execute(
self,
ctx: ToolContext,
nft_id: str
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_nft, nft_id)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoNFTByContractTool(BaseTool):
"""
Get NFT collection by contract address.
"""
@property
def name(self) -> str:
return "cg_nft_by_contract"
@property
def description(self) -> str:
return """Get NFT collection by contract address.
On-chain NFT lookup.
Examples:
- Get BAYC by contract: cg_nft_by_contract(asset_platform="ethereum", contract_address="0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"asset_platform": {
"type": "string",
"description": "Asset platform id (ethereum, solana)"
},
"contract_address": {
"type": "string",
"description": "NFT contract address"
}
},
"required": ["asset_platform", "contract_address"]
}
async def execute(
self,
ctx: ToolContext,
asset_platform: str,
contract_address: str
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_nft_by_contract, asset_platform, contract_address)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== Infrastructure Tools ====================
class CoinGeckoAssetPlatformsTool(BaseTool):
"""
Get all blockchain networks/asset platforms.
"""
@property
def name(self) -> str:
return "cg_asset_platforms"
@property
def description(self) -> str:
return """Get all blockchain networks (Ethereum, Solana, etc.).
Filter by chain.
Examples:
- Get all platforms: cg_asset_platforms()
- Filter NFT platforms: cg_asset_platforms(filter="nft")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"filter": {
"type": "string",
"description": "Filter platforms (e.g., nft)"
}
}
}
async def execute(
self,
ctx: ToolContext,
filter: Optional[str] = None
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_asset_platforms, filter)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoExchangeRatesTool(BaseTool):
"""
Get BTC exchange rates to all fiat currencies.
"""
@property
def name(self) -> str:
return "cg_exchange_rates"
@property
def description(self) -> str:
return """Get BTC exchange rates to all fiat currencies.
Currency conversion.
Examples:
- Get exchange rates: cg_exchange_rates()"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {}
}
async def execute(self, ctx: ToolContext) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_exchange_rates)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoVsCurrenciesTool(BaseTool):
"""
Get list of supported quote currencies.
"""
@property
def name(self) -> str:
return "cg_vs_currencies"
@property
def description(self) -> str:
return """Get list of supported quote currencies (vs_currencies).
Reference data.
Examples:
- Get supported currencies: cg_vs_currencies()"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {}
}
async def execute(self, ctx: ToolContext) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_vs_currencies)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoCategoriesListTool(BaseTool):
"""
Get lightweight list of category names and IDs.
"""
@property
def name(self) -> str:
return "cg_categories_list"
@property
def description(self) -> str:
return """Get lightweight list of category names and IDs (no market data).
Quick lookup.
Examples:
- Get categories list: cg_categories_list()"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {}
}
async def execute(self, ctx: ToolContext) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_categories_list)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== Search Tool ====================
class CoinGeckoSearchTool(BaseTool):
"""
Search for coins, exchanges, categories, and NFTs.
"""
@property
def name(self) -> str:
return "cg_search"
@property
def description(self) -> str:
return """Search for coins, exchanges, categories, and NFTs.
Discovery across all CoinGecko data.
Examples:
- Search for Solana: cg_search(query="solana")
- Search for DeFi: cg_search(query="defi")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query"
}
},
"required": ["query"]
}
async def execute(
self,
ctx: ToolContext,
query: str
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(search, query)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
# ==================== Contract Tools ====================
class CoinGeckoTokenPriceTool(BaseTool):
"""
Get token prices by contract address.
"""
@property
def name(self) -> str:
return "cg_token_price"
@property
def description(self) -> str:
return """Get token prices by contract address.
On-chain pricing.
Examples:
- Get USDC price on Ethereum: cg_token_price(platform="ethereum", contract_addresses="0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")
- Multiple tokens: cg_token_price(platform="ethereum", contract_addresses="0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48,0xdac17f958d2ee523a2206206994597c13d831ec7")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"platform": {
"type": "string",
"description": "Asset platform id (ethereum, solana, polygon-pos)"
},
"contract_addresses": {
"type": "string",
"description": "Comma-separated contract addresses"
},
"vs_currencies": {
"type": "string",
"description": "Comma-separated target currencies (usd, eur, btc)",
"default": "usd"
},
"include_market_cap": {
"type": "boolean",
"description": "Include market cap",
"default": False
},
"include_24hr_vol": {
"type": "boolean",
"description": "Include 24h volume",
"default": False
},
"include_24hr_change": {
"type": "boolean",
"description": "Include 24h price change",
"default": False
},
"include_last_updated_at": {
"type": "boolean",
"description": "Include last updated timestamp",
"default": False
}
},
"required": ["platform", "contract_addresses"]
}
async def execute(
self,
ctx: ToolContext,
platform: str,
contract_addresses: str,
vs_currencies: str = "usd",
include_market_cap: bool = False,
include_24hr_vol: bool = False,
include_24hr_change: bool = False,
include_last_updated_at: bool = False
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(
get_token_price,
platform=platform,
contract_addresses=contract_addresses,
vs_currencies=vs_currencies,
include_market_cap=include_market_cap,
include_24hr_vol=include_24hr_vol,
include_24hr_change=include_24hr_change,
include_last_updated_at=include_last_updated_at
)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
class CoinGeckoCoinByContractTool(BaseTool):
"""
Get coin data by contract address.
"""
@property
def name(self) -> str:
return "cg_coin_by_contract"
@property
def description(self) -> str:
return """Get coin data by contract address.
On-chain lookup.
Examples:
- Get USDC on Ethereum: cg_coin_by_contract(platform="ethereum", contract_address="0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"platform": {
"type": "string",
"description": "Asset platform id (ethereum, solana, polygon-pos)"
},
"contract_address": {
"type": "string",
"description": "Token contract address"
}
},
"required": ["platform", "contract_address"]
}
async def execute(
self,
ctx: ToolContext,
platform: str,
contract_address: str
) -> ToolResult:
if not COINGECKO_AVAILABLE:
return ToolResult(
success=False,
output=None,
error="CoinGecko tools not available."
)
try:
result = await asyncio.to_thread(get_coin_by_contract, platform, contract_address)
return ToolResult(success=True, output=result)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
"""
CoinGecko skill exports — script-mode skill.
Usage from a bash block:
python3 - <<'EOF'
import sys
sys.path.insert(0, "/data/workspace/skills/coingecko")
from exports import coin_price, cg_trending
print(coin_price(coin_ids="bitcoin,ethereum"))
EOF
"""
import os, sys
# tools/ contains all sub-modules; make them importable regardless of cwd.
_TOOLS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tools")
if _TOOLS_DIR not in sys.path:
sys.path.insert(0, _TOOLS_DIR)
from coin_prices import get_coin_prices_at_timestamps
from coin_ohlc_range_by_id import get_coin_ohlc_range_by_id
from coin_historical_chart_range_by_id import get_coin_historical_chart_range_by_id
from coins import (get_coins_list, get_coins_markets, get_coin_data, get_coin_tickers)
from market_discovery import get_trending, get_top_gainers_losers, get_new_coins
from global_data import get_global, get_global_defi
from search import search as _search
from derivatives import get_derivatives, get_derivatives_exchanges, get_categories
from exchanges import (get_exchanges, get_exchange, get_exchange_tickers,
get_exchange_volume_chart)
from infrastructure import (get_asset_platforms, get_exchange_rates,
get_vs_currencies, get_categories_list)
from nfts import get_nfts_list, get_nft, get_nft_by_contract
from contracts import get_token_price, get_coin_by_contract
# ── Price tools ──
def coin_price(coin_ids, timestamps=None, vs_currency="usd"):
"""Get coin prices. coin_ids: comma-separated IDs or symbols (bitcoin,BTC,ETH)."""
return get_coin_prices_at_timestamps(
coin_ids=coin_ids,
timestamps=timestamps or ["now"],
vs_currency=vs_currency
)
def coin_ohlc(coin_id, days=30, vs_currency="usd"):
"""Get OHLC candlestick data for the last N days.
Wraps get_coin_ohlc_range_by_id which expects unix timestamps.
"""
import time as _time
to_ts = int(_time.time())
from_ts = to_ts - int(days) * 86400
return get_coin_ohlc_range_by_id(
coin_id, from_timestamp=from_ts, to_timestamp=to_ts
)
def coin_chart(coin_id, days=30, vs_currency="usd"):
"""Get historical price chart for the last N days (timestamp + price points).
Wraps get_coin_historical_chart_range_by_id which expects unix timestamps.
"""
import time as _time
to_ts = int(_time.time())
from_ts = to_ts - int(days) * 86400
return get_coin_historical_chart_range_by_id(
coin_id,
vs_currency=vs_currency,
from_timestamp=from_ts,
to_timestamp=to_ts,
)
# ── Discovery tools ──
def cg_trending():
"""Get trending coins, NFTs, categories."""
return get_trending()
def cg_top_gainers_losers(vs_currency="usd", duration="24h"):
"""Get top gainers and losers."""
return get_top_gainers_losers(vs_currency, duration)
def cg_new_coins():
"""Get recently added coins."""
return get_new_coins()
def cg_search(query):
"""Search for coins, exchanges, categories by name."""
return _search(query)
# ── Global data ──
def cg_global():
"""Get global crypto market stats."""
return get_global()
def cg_global_defi():
"""Get global DeFi market stats."""
return get_global_defi()
# ── Coins ──
def cg_coins_list(include_platform=False):
"""Get list of all coins (id, symbol, name)."""
return get_coins_list(include_platform)
def cg_coins_markets(vs_currency="usd", order="market_cap_desc", per_page=100,
page=1, sparkline=False, price_change_percentage="24h",
category=None, ids=None):
"""Get coin market data (price, mcap, volume, change%)."""
return get_coins_markets(vs_currency, order, per_page, page, sparkline,
price_change_percentage, category, ids)
def cg_coin_data(coin_id, localization=False, tickers=False, market_data=True,
community_data=False, developer_data=False, sparkline=False):
"""Get detailed data for a specific coin."""
return get_coin_data(coin_id, localization, tickers, market_data,
community_data, developer_data, sparkline)
def cg_coin_tickers(coin_id, exchange_ids=None, include_exchange_logo=False,
page=1, order="volume_desc", depth=False):
"""Get coin trading tickers across exchanges."""
return get_coin_tickers(coin_id, exchange_ids, include_exchange_logo,
page, order, depth)
# ── Categories ──
def cg_categories(order="market_cap_desc"):
"""Get coin categories with market data."""
return get_categories(order)
def cg_categories_list():
"""Get list of all categories (id + name only)."""
return get_categories_list()
# ── Derivatives ──
def cg_derivatives(include_tickers="unexpired"):
"""Get derivatives tickers (futures/perpetuals)."""
return get_derivatives(include_tickers)
def cg_derivatives_exchanges(order="open_interest_btc_desc", per_page=50):
"""Get derivatives exchanges ranked by open interest."""
return get_derivatives_exchanges(order, per_page)
# ── Exchanges ──
def cg_exchanges(per_page=100, page=1):
"""Get list of exchanges with volume data."""
return get_exchanges(per_page, page)
def cg_exchange(exchange_id):
"""Get specific exchange data."""
return get_exchange(exchange_id)
def cg_exchange_tickers(exchange_id, coin_ids=None, include_exchange_logo=False,
page=1, order="volume_desc", depth=False):
"""Get tickers for a specific exchange."""
return get_exchange_tickers(exchange_id, coin_ids, include_exchange_logo,
page, order, depth)
def cg_exchange_volume_chart(exchange_id, days=30):
"""Get exchange volume chart data."""
return get_exchange_volume_chart(exchange_id, days)
# ── NFTs ──
def cg_nfts_list(order="market_cap_usd_desc", per_page=100, page=1):
"""Get NFT collections list."""
return get_nfts_list(order, per_page, page)
def cg_nft(nft_id):
"""Get specific NFT collection data."""
return get_nft(nft_id)
def cg_nft_by_contract(asset_platform, contract_address):
"""Get NFT data by contract address."""
return get_nft_by_contract(asset_platform, contract_address)
# ── Infrastructure ──
def cg_asset_platforms(filter=None):
"""Get list of asset platforms (blockchains)."""
return get_asset_platforms(filter)
def cg_exchange_rates():
"""Get BTC exchange rates to other currencies."""
return get_exchange_rates()
def cg_vs_currencies():
"""Get list of supported vs currencies."""
return get_vs_currencies()
# ── Contract/Token tools ──
def cg_token_price(platform, contract_addresses, vs_currencies="usd",
include_market_cap=False, include_24hr_vol=False,
include_24hr_change=False, include_last_updated_at=False):
"""Get token price by contract address."""
return get_token_price(platform, contract_addresses, vs_currencies,
include_market_cap, include_24hr_vol,
include_24hr_change, include_last_updated_at)
def cg_coin_by_contract(platform, contract_address):
"""Get coin data by contract address."""
return get_coin_by_contract(platform, contract_address)
# coingecko module
#!/usr/bin/env python3
"""
CoinGecko Coin Historical Chart Data within Time Range Tool
This tool provides access to the CoinGecko Pro API /coins/{id}/market-chart/range endpoint,
which returns historical chart data for a specific coin by its id or symbol within a time range.
API Reference: https://docs.coingecko.com/reference/coins-id-market-chart-range
Usage Example:
from tools.coin_historical_chart_range_by_id import get_coin_historical_chart_range
# Using symbol
data = get_coin_historical_chart_range('BTC', vs_currency='usd', from_timestamp=1672531200, to_timestamp=1672617600)
# Using ID
data = get_coin_historical_chart_range('bitcoin', vs_currency='usd', from_timestamp=1672531200, to_timestamp=1672617600)
print(data)
Returns:
dict with keys: 'prices', 'market_caps', 'total_volumes'
"""
import os
from dotenv import load_dotenv
import time
import argparse
import json
from core.http_client import proxied_get
try:
from .utils import parse_flexible_time, split_time_range, merge_market_chart_data, get_days_difference, search_coin_by_name
except ImportError:
from utils import parse_flexible_time, split_time_range, merge_market_chart_data, get_days_difference, search_coin_by_name
# MCP Tool Schema
MCP_TOOL_SCHEMA = {
"name": "get_coin_historical_chart_range_by_id",
"title": "CoinGecko Historical Chart Range",
"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.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"coin_id": {
"type": "string",
"minLength": 1,
"description": "The coin id (e.g., 'bitcoin') or symbol (e.g., 'BTC')"
},
"vs_currency": {
"type": "string",
"default": "usd",
"description": "The target currency (e.g., 'usd')"
},
"from_timestamp": {
"type": ["string", "integer", "number"],
"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')"
},
"to_timestamp": {
"type": ["string", "integer", "number"],
"description": "End time - same formats as from_timestamp"
}
},
"required": ["coin_id", "from_timestamp", "to_timestamp"],
"additionalProperties": False
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"prices": {
"type": "array",
"items": {
"type": "array",
"items": [
{"type": "number", "description": "Unix timestamp in milliseconds"},
{"type": "number", "description": "Price in the specified vs_currency"}
],
"minItems": 2,
"maxItems": 2
},
"description": "Array of [timestamp_ms, price] pairs showing coin price at each time point"
},
"market_caps": {
"type": "array",
"items": {
"type": "array",
"items": [
{"type": "number", "description": "Unix timestamp in milliseconds"},
{"type": "number", "description": "Market capitalization at this timestamp"}
],
"minItems": 2,
"maxItems": 2
},
"description": "Array of [timestamp_ms, market_cap] pairs showing market capitalization"
},
"total_volumes": {
"type": "array",
"items": {
"type": "array",
"items": [
{"type": "number", "description": "Unix timestamp in milliseconds"},
{"type": "number", "description": "Total trading volume"}
],
"minItems": 2,
"maxItems": 2
},
"description": "Array of [timestamp_ms, volume] pairs showing trading volume"
}
},
"required": ["prices", "market_caps", "total_volumes"],
"additionalProperties": False
},
"annotations": {
"path": "tools/coingecko/coin_historical_chart_range_by_id.py",
"function": "get_coin_historical_chart_range_by_id",
"examples": [
{
"name": "basic_auto_interval",
"arguments": {
"coin_id": "BTC",
"from_timestamp": "30 days ago",
"to_timestamp": "today"
}
},
{
"name": "large_range_splitting",
"arguments": {
"coin_id": "BTC",
"from_timestamp": "2023-01-01",
"to_timestamp": "2023-12-31"
}
}
]
}
}
# Load environment variables from project root directory
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../..'))
load_dotenv(os.path.join(project_root, '.env'))
def get_coin_historical_chart_range_by_id(coin_id, vs_currency='usd', from_timestamp=None, to_timestamp=None):
"""
Fetch historical chart data for a specific coin by its id or symbol within a time range from CoinGecko.
Automatically handles data splitting for large time ranges based on interval limits and flexible time input parsing.
Args:
coin_id (str): The coin id (e.g., 'bitcoin') or symbol (e.g., 'BTC')
vs_currency (str): The target currency (e.g., 'usd')
from_timestamp (Union[str, int, float]): Start time - supports:
- Unix timestamp (1640995200)
- ISO date ('2023-01-01' or '2023-01-01 10:30:00')
- Natural language ('2 weeks ago', 'last month', 'yesterday')
to_timestamp (Union[str, int, float]): End time - same formats as from_timestamp
Returns:
dict: Historical chart data with keys: 'prices', 'market_caps', 'total_volumes'
Automatically merges data from multiple API calls if needed for large ranges
Raises:
ConnectionError: If API request fails after retries
ValueError: If parameters are invalid or time range exceeds interval limits
Data Limitations (based on official CoinGecko API):
- Auto granularity: 1 day = 5-min, 1-90 days = hourly, >90 days = daily
- Cache frequency: 1 day = 30s, 2-90 days = 30min, >90 days = 12h
Examples:
>>> # Get last 30 days of data
>>> data = get_coin_historical_chart_range_by_id('BTC', 'usd', '30 days ago', 'today')
>>> # Get data for specific date range
>>> data = get_coin_historical_chart_range_by_id('ETH', 'usd', '2023-01-01', '2023-03-31')
>>> # Large range with automatic splitting
>>> data = get_coin_historical_chart_range_by_id('BTC', 'usd', '2023-01-01', '2023-12-31')
"""
if not coin_id:
raise ValueError("coin_id parameter is required")
if not from_timestamp or not to_timestamp:
raise ValueError("Both from_timestamp and to_timestamp are required")
# Convert symbol to ID if needed
coin_result = search_coin_by_name(coin_id)
if not coin_result:
raise ValueError(f"Could not find coin with symbol or name: {coin_id}")
actual_coin_id = coin_result['id']
# Parse flexible time inputs
from_ts = parse_flexible_time(from_timestamp)
to_ts = parse_flexible_time(to_timestamp)
if from_ts >= to_ts:
raise ValueError("from_timestamp must be earlier than to_timestamp")
# Determine splitting strategy based on time range
days_diff = get_days_difference(from_ts, to_ts)
# For better granularity, split at 90 days to maintain hourly data when possible
if days_diff <= 90:
return _fetch_single_range(actual_coin_id, vs_currency, from_ts, to_ts)
else:
return _fetch_with_splitting(actual_coin_id, vs_currency, from_ts, to_ts, max_days=90)
def _fetch_single_range(coin_id, vs_currency, from_timestamp, to_timestamp):
"""Fetch historical chart data for a single time range."""
url = f"https://pro-api.coingecko.com/api/v3/coins/{coin_id}/market_chart/range"
params = {
'vs_currency': vs_currency,
'from': from_timestamp,
'to': to_timestamp
}
headers = {"x-cg-pro-api-key": os.getenv("COINGECKO_API_KEY")}
if not headers["x-cg-pro-api-key"]:
raise ValueError("COINGECKO_API_KEY environment variable is required")
for attempt in range(3):
try:
resp = proxied_get(url, params=params, headers=headers, timeout=15)
resp.raise_for_status()
return resp.json()
except Exception as e:
if attempt == 2: # Last attempt
raise ConnectionError(f"API request failed after retries: {e}")
time.sleep(1)
def _fetch_with_splitting(coin_id, vs_currency, from_ts, to_ts, max_days):
"""Fetch historical chart data with automatic splitting for large ranges."""
time_chunks = split_time_range(from_ts, to_ts, max_days=max_days)
data_chunks = []
for chunk_start, chunk_end in time_chunks:
chunk_data = _fetch_single_range(coin_id, vs_currency, chunk_start, chunk_end)
data_chunks.append(chunk_data)
# Small delay between requests to be respectful to the API
time.sleep(0.5)
# Merge all chunks
return merge_market_chart_data(data_chunks)
def main():
"""Main CLI function."""
parser = argparse.ArgumentParser(
description="Fetch historical chart data within a time range for a specific coin from CoinGecko API.",
epilog="""INPUT:
--coin_id: Coin ID/symbol (bitcoin, BTC, ethereum, ETH)
--from_timestamp: Start time ("30 days ago", "2023-01-01", timestamp)
--to_timestamp: End time ("today", "2023-12-31", timestamp)
--vs_currency: Target currency (default: usd)
OUTPUT:
JSON array of price and volume data:
[{"timestamp": 1640995200, "price": 46300.45, "market_cap": 874500000000,
"total_volume": 34500000000}]
EXAMPLE:
python coin_historical_chart_range_by_id.py --coin_id BTC --from_timestamp "30 days ago" --to_timestamp "today"
python coin_historical_chart_range_by_id.py --coin_id ethereum --from_timestamp "2023-01-01" --to_timestamp "2023-06-30"
""",
formatter_class=argparse.RawDescriptionHelpFormatter
)
# MCP Schema query options
parser.add_argument('--schema', action='store_true',
help='Output complete MCP tool schema (JSON)')
parser.add_argument('--name', action='store_true',
help='Output tool name from schema')
parser.add_argument('--title', action='store_true',
help='Output tool title from schema')
parser.add_argument('--description', action='store_true',
help='Output tool description from schema')
parser.add_argument('--inputSchema', action='store_true',
help='Output input schema')
parser.add_argument('--outputSchema', action='store_true',
help='Output output schema')
parser.add_argument('--annotations', action='store_true',
help='Output annotations from schema')
# Tool functionality options
parser.add_argument('--coin_id', type=str, help='Coin id (e.g., bitcoin) or symbol (e.g., BTC)')
parser.add_argument('--vs_currency', type=str, default='usd', help='Target currency (default: usd)')
parser.add_argument('--from_timestamp', type=str,
help='Start time - supports: Unix timestamp, ISO date (2023-01-01), natural language ("2 weeks ago", "last month")')
parser.add_argument('--to_timestamp', type=str,
help='End time - same formats as from_timestamp')
args = parser.parse_args()
# Handle MCP schema queries first
if args.schema:
print(json.dumps(MCP_TOOL_SCHEMA, indent=2, sort_keys=True))
return
elif args.name:
print(MCP_TOOL_SCHEMA["name"])
return
elif args.title:
print(MCP_TOOL_SCHEMA["title"])
return
elif args.description:
print(MCP_TOOL_SCHEMA["description"])
return
elif args.inputSchema:
print(json.dumps(MCP_TOOL_SCHEMA["inputSchema"], indent=2, sort_keys=True))
return
elif args.outputSchema:
print(json.dumps(MCP_TOOL_SCHEMA["outputSchema"], indent=2, sort_keys=True))
return
elif args.annotations:
print(json.dumps(MCP_TOOL_SCHEMA["annotations"], indent=2, sort_keys=True))
return
# Check required arguments only if not showing example
if not args.coin_id:
parser.error("--coin_id is required")
if not args.from_timestamp:
parser.error("--from_timestamp is required")
if not args.to_timestamp:
parser.error("--to_timestamp is required")
try:
# Call the main function to fetch historical chart data using the provided arguments
data = get_coin_historical_chart_range_by_id(
coin_id=args.coin_id,
vs_currency=args.vs_currency,
from_timestamp=args.from_timestamp,
to_timestamp=args.to_timestamp
)
# Print the result as pretty-formatted JSON
print(json.dumps(data, ensure_ascii=False, indent=2))
except Exception as e:
# Print error message if the API call fails
print(f"Failed to fetch historical chart data: {e}")
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
CoinGecko Coin OHLC Chart within Time Range Tool - MCP Compliant
API Reference: https://docs.coingecko.com/reference/coins-id-ohlc-range
Returns: Array of [timestamp_ms, open, high, low, close] in USD
"""
import os
from dotenv import load_dotenv
import time
import argparse
import json
import sys
try:
from .utils import parse_flexible_time, split_time_range, merge_ohlc_data, get_days_difference, search_coin_by_name
except ImportError:
from utils import parse_flexible_time, split_time_range, merge_ohlc_data, get_days_difference, search_coin_by_name
from core.http_client import proxied_get
# Load environment variables from project root directory
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..'))
load_dotenv(os.path.join(project_root, '.env'))
# MCP Tool Schema
MCP_TOOL_SCHEMA = {
"name": "get_coin_ohlc_range_by_id",
"title": "CoinGecko OHLC Range",
"description": "Retrieve OHLC candlestick data within a custom time range for technical analysis. Supports unlimited time ranges (365+ days) with automatic data splitting for large ranges. Will return a lot of data, use with caution.",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"coin_id": {
"type": "string",
"minLength": 1,
"description": "The coin ID (e.g., 'bitcoin', 'ethereum') or symbol (e.g., 'BTC', 'ETH')"
},
"from_timestamp": {
"type": ["string", "integer", "number"],
"description": "Start time - supports Unix timestamp, ISO date ('2023-01-01'), or natural language ('2 weeks ago', 'last month')"
},
"to_timestamp": {
"type": ["string", "integer", "number"],
"description": "End time - same formats as from_timestamp"
},
"interval": {
"type": ["string", "null"],
"enum": ["daily", "hourly", None],
"description": "Data interval - 'daily' (max 180 days per request), 'hourly' (max 31 days per request), or null for auto-selection based on time range"
}
},
"required": ["coin_id", "from_timestamp", "to_timestamp"],
"additionalProperties": False
},
"outputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "array",
"items": {
"type": "array",
"items": [
{"type": "number", "description": "Unix timestamp in milliseconds"},
{"type": "number", "description": "Opening price in USD"},
{"type": "number", "description": "Highest price in USD"},
{"type": "number", "description": "Lowest price in USD"},
{"type": "number", "description": "Closing price in USD"}
],
"minItems": 5,
"maxItems": 5
},
"description": "Array of OHLC candlestick data where each item is [timestamp_ms, open, high, low, close] in USD"
},
"annotations": {
"path": "tools/coingecko/coin_ohlc_range_by_id.py",
"function": "get_coin_ohlc_range_by_id",
"examples": [
{
"name": "basic_daily",
"arguments": {
"coin_id": "bitcoin",
"from_timestamp": "2024-01-01",
"to_timestamp": "2024-01-07",
"interval": "daily"
}
},
{
"name": "natural_language",
"arguments": {
"coin_id": "ETH",
"from_timestamp": "30 days ago",
"to_timestamp": "today",
"interval": "hourly"
}
}
]
}
}
def get_coin_ohlc_range_by_id(coin_id, from_timestamp=None, to_timestamp=None, interval=None):
"""
Fetch OHLC chart data for a specific coin within a time range from CoinGecko Pro API.
Handles automatic data splitting for large time ranges. Currency fixed to USD.
"""
if not coin_id:
raise ValueError("coin_id parameter is required")
if not from_timestamp or not to_timestamp:
raise ValueError("Both from_timestamp and to_timestamp are required")
# Convert symbol to ID if needed
coin_result = search_coin_by_name(coin_id)
if not coin_result:
raise ValueError(f"Could not find coin with symbol or name: {coin_id}")
actual_coin_id = coin_result['id']
# Currency is fixed to USD
vs_currency = 'usd'
# Parse flexible time inputs
from_ts = parse_flexible_time(from_timestamp)
to_ts = parse_flexible_time(to_timestamp)
if from_ts >= to_ts:
raise ValueError("from_timestamp must be earlier than to_timestamp")
# Validate interval parameter
if interval is not None:
valid_intervals = ['daily', 'hourly']
if interval not in valid_intervals:
raise ValueError(f"interval must be one of {valid_intervals} or None, got: {interval}")
# Determine optimal interval and splitting strategy
days_diff = get_days_difference(from_ts, to_ts)
# Auto-select interval if not specified
if interval is None:
if days_diff <= 31:
interval = 'hourly'
else:
interval = 'daily'
# Validate time range against interval limits
if interval == 'hourly' and days_diff > 31:
if days_diff <= 180:
# Switch to daily for better compatibility
interval = 'daily'
else:
# Split into hourly chunks (31 days each) then merge
return _fetch_ohlc_with_splitting(actual_coin_id, vs_currency, from_ts, to_ts, 'hourly', 31)
elif interval == 'daily' and days_diff > 180:
# Split into daily chunks (180 days each) then merge
return _fetch_ohlc_with_splitting(actual_coin_id, vs_currency, from_ts, to_ts, 'daily', 180)
# Single request
return _fetch_single_ohlc_range(actual_coin_id, vs_currency, from_ts, to_ts, interval)
def _fetch_ohlc_with_splitting(coin_id, vs_currency, from_ts, to_ts, interval, max_days):
"""Fetch OHLC data with automatic splitting for large ranges."""
time_chunks = split_time_range(from_ts, to_ts, max_days=max_days)
data_chunks = []
for chunk_start, chunk_end in time_chunks:
chunk_data = _fetch_single_ohlc_range(coin_id, vs_currency, chunk_start, chunk_end, interval)
data_chunks.append(chunk_data)
# Small delay between requests to be respectful to the API
time.sleep(0.5)
# Merge all chunks
return merge_ohlc_data(data_chunks)
def _fetch_single_ohlc_range(coin_id, vs_currency, from_timestamp, to_timestamp, interval):
"""Fetch OHLC data for a single time range."""
url = f"https://pro-api.coingecko.com/api/v3/coins/{coin_id}/ohlc/range"
params = {
'vs_currency': vs_currency,
'from': from_timestamp,
'to': to_timestamp
}
if interval:
params['interval'] = interval
headers = {"x-cg-pro-api-key": os.getenv("COINGECKO_API_KEY")}
if not headers["x-cg-pro-api-key"]:
raise ValueError("COINGECKO_API_KEY environment variable is required")
# Retry logic
for attempt in range(3):
try:
resp = proxied_get(url, params=params, headers=headers, timeout=15)
resp.raise_for_status()
return resp.json()
except Exception as e:
if attempt == 2: # Last attempt
raise ConnectionError(f"API request failed after retries: {e}")
time.sleep(1)
# Backward compatibility
def get_coin_ohlc_range(coin_id, vs_currency='usd', from_timestamp=None, to_timestamp=None, interval=None):
"""Backward compatibility wrapper for get_coin_ohlc_range_by_id. vs_currency is ignored (always USD)."""
return get_coin_ohlc_range_by_id(coin_id, from_timestamp, to_timestamp, interval)
def main():
"""Command-line interface for the coin OHLC range tool."""
# Handle MCP schema queries first (single argument only)
if len(sys.argv) == 2:
arg = sys.argv[1]
if arg == "--schema":
print(json.dumps(MCP_TOOL_SCHEMA, indent=2, sort_keys=True, ensure_ascii=False))
return 0
elif arg.startswith("--") and len(arg) > 2:
field_name = arg[2:] # Remove "--" prefix
if field_name in MCP_TOOL_SCHEMA:
field_value = MCP_TOOL_SCHEMA[field_name]
print(json.dumps(field_value, indent=2, sort_keys=True, ensure_ascii=False))
return 0
parser = argparse.ArgumentParser(
description="Fetch OHLC chart data within a time range for a specific coin from CoinGecko API.",
epilog="""INPUT:
--coin_id: Coin ID/symbol (bitcoin, BTC, ethereum, ETH)
--from_timestamp: Start time ("30 days ago", "2023-01-01", timestamp)
--to_timestamp: End time ("today", "2023-12-31", timestamp)
--interval: Data interval (daily, hourly, or auto-select)
OUTPUT:
JSON array of OHLC data points:
[{"timestamp": 1640995200, "open": 46300.45, "high": 47100.23,
"low": 45800.12, "close": 46950.78}]
EXAMPLE:
python coin_ohlc_range_by_id.py --coin_id BTC --from_timestamp "30 days ago" --to_timestamp "today"
python coin_ohlc_range_by_id.py --coin_id ethereum --from_timestamp "2023-01-01" --to_timestamp "2023-12-31" --interval daily
""",
formatter_class=argparse.RawDescriptionHelpFormatter
)
# MCP schema arguments
parser.add_argument('--schema', action='store_true', help='Output complete MCP Tool Schema (JSON)')
parser.add_argument('--name', action='store_true', help='Output tool name')
parser.add_argument('--title', action='store_true', help='Output tool title')
parser.add_argument('--description', action='store_true', help='Output tool description')
parser.add_argument('--inputSchema', action='store_true', help='Output input schema')
parser.add_argument('--outputSchema', action='store_true', help='Output output schema')
parser.add_argument('--annotations', action='store_true', help='Output annotations')
# Original functionality arguments
parser.add_argument('--coin_id', help='Coin id (e.g., bitcoin) or symbol (e.g., BTC)')
parser.add_argument('--from_timestamp', type=str,
help='Start time - supports: Unix timestamp, ISO date (2023-01-01), natural language ("2 weeks ago", "last month")')
parser.add_argument('--to_timestamp', type=str,
help='End time - same formats as from_timestamp')
parser.add_argument('--interval', type=str, choices=['daily', 'hourly'],
help='Data interval - "daily" (max 180 days) or "hourly" (max 31 days). Auto-selected if not specified')
args = parser.parse_args()
# Handle MCP schema queries
if args.schema:
print(json.dumps(MCP_TOOL_SCHEMA, indent=2, sort_keys=True, ensure_ascii=False))
return 0
elif args.name:
print(json.dumps(MCP_TOOL_SCHEMA["name"], ensure_ascii=False))
return 0
elif args.title:
print(json.dumps(MCP_TOOL_SCHEMA["title"], ensure_ascii=False))
return 0
elif args.description:
print(json.dumps(MCP_TOOL_SCHEMA["description"], ensure_ascii=False))
return 0
elif args.inputSchema:
print(json.dumps(MCP_TOOL_SCHEMA["inputSchema"], indent=2, sort_keys=True, ensure_ascii=False))
return 0
elif args.outputSchema:
print(json.dumps(MCP_TOOL_SCHEMA["outputSchema"], indent=2, sort_keys=True, ensure_ascii=False))
return 0
elif args.annotations:
print(json.dumps(MCP_TOOL_SCHEMA["annotations"], indent=2, sort_keys=True, ensure_ascii=False))
return 0
# Validate required arguments for normal operation
if not args.coin_id:
parser.error("--coin_id is required")
if not args.from_timestamp:
parser.error("--from_timestamp is required")
if not args.to_timestamp:
parser.error("--to_timestamp is required")
try:
data = get_coin_ohlc_range_by_id(
coin_id=args.coin_id,
from_timestamp=args.from_timestamp,
to_timestamp=args.to_timestamp,
interval=args.interval
)
print(json.dumps(data, ensure_ascii=False, indent=2))
except Exception as e:
print(f"Failed to fetch OHLC range data: {e}")
return 1
return 0
if __name__ == "__main__":
exit(main()) #!/usr/bin/env python3
"""
CoinGecko Coin Prices at Multiple Timestamps Tool
This tool provides functionality to fetch coin prices at multiple specific timestamps
using the CoinGecko Pro API. It supports flexible time input formats including "now"
for current prices and various date formats for historical prices.
MCP Tool Schema compliant with CLI interface supporting:
- --help: Output complete Schema (JSON, pretty-printed)
- --<field>: Output specific Schema field
Dependencies:
- requests: For HTTP API calls
- python-dotenv: For environment variable management
Environment Variables Required:
- COINGECKO_API_KEY: Your CoinGecko Pro API key (required for API access)
API Limitations:
- Rate limits apply based on your CoinGecko Pro subscription
- Historical data available from February 9, 2018 onwards
- Current price endpoint updates every 20 seconds for Pro API tiers
"""
import os
from dotenv import load_dotenv
import time
import argparse
import json
from typing import List, Dict, Any, Union
from datetime import datetime
try:
from .utils import parse_flexible_time, format_dd_mm_yyyy_date, search_coin_by_name
except ImportError:
from utils import parse_flexible_time, format_dd_mm_yyyy_date, search_coin_by_name
from core.http_client import proxied_get
# Load environment variables from agent_framework root directory
# Path: extensions/trading/tools/coingecko/ -> go up 4 levels to agent_framework/
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..'))
load_dotenv(os.path.join(project_root, '.env'))
# MCP Tool Schema
MCP_TOOL_SCHEMA = {
"name": "get_coin_prices_at_timestamps",
"title": "CoinGecko Coin Prices at Multiple Timestamps",
"description": "Fetch cryptocurrency prices at multiple specific timestamps using CoinGecko Pro API. Supports flexible time input formats including 'now' for current prices and various date formats for historical prices.",
"inputSchema": {
"type": "object",
"properties": {
"coin_ids": {
"type": ["string", "array"],
"items": {
"type": "string"
},
"description": "Single coin ID/symbol or list of coin IDs/symbols. Supports comma-separated strings, individual strings, or arrays. Accepts both full names ('bitcoin') and symbols ('BTC'). Case-insensitive.",
"examples": ["bitcoin", "BTC", "BTC,ETH,SOL", ["bitcoin", "ethereum", "solana"]]
},
"timestamps": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of timestamp strings in various formats. Supports 'now' for current price, Unix timestamps, ISO dates, and natural language expressions.",
"default": ["now"],
"examples": [["now"], ["now", "2023-01-01", "yesterday"], ["now", "1640995200", "last month"]]
},
"vs_currency": {
"type": "string",
"description": "The target currency for price quotes",
"default": "usd",
"examples": ["usd", "eur", "btc"]
},
"rate_limit_delay": {
"type": "number",
"description": "Delay between API calls in seconds to respect rate limits",
"default": 1.0,
"minimum": 0.1,
"maximum": 10.0
}
},
"required": ["coin_ids"],
"additionalProperties": False
},
"outputSchema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"timestamp": {
"type": "string",
"description": "Original timestamp input"
},
"parsed_timestamp": {
"type": ["integer", "null"],
"description": "Unix timestamp (for historical data) or null for errors"
},
"date": {
"type": "string",
"description": "Human readable date"
},
"price": {
"type": ["number", "null"],
"description": "Price in specified currency or null for errors"
},
"coin_id": {
"type": "string",
"description": "CoinGecko coin ID used for API call"
},
"coin_symbol": {
"type": "string",
"description": "Coin symbol (e.g., 'BTC')"
},
"coin_name": {
"type": "string",
"description": "Coin name (e.g., 'Bitcoin')"
},
"status": {
"type": "string",
"enum": ["success", "error"],
"description": "Status of the price fetch operation"
},
"error": {
"type": ["string", "null"],
"description": "Error message if status is 'error', otherwise null"
}
},
"required": ["timestamp", "parsed_timestamp", "date", "price", "coin_id", "coin_symbol", "coin_name", "status", "error"]
}
},
"annotations": {
"path": "tools/coingecko/coin_prices.py",
"function": "get_coin_prices_at_timestamps",
"examples": [
{
"name": "Single coin current price",
"input": {
"coin_ids": "bitcoin"
},
"output": [
{
"timestamp": "now",
"parsed_timestamp": 1672531200,
"date": "2023-01-01 00:00:00 UTC",
"price": 16547.32,
"coin_id": "bitcoin",
"coin_symbol": "BTC",
"coin_name": "Bitcoin",
"status": "success",
"error": None
}
]
},
{
"name": "Multiple coins with timestamps",
"input": {
"coin_ids": "BTC,ETH,SOL",
"timestamps": ["now", "yesterday"]
},
"output": [
{
"timestamp": "now",
"parsed_timestamp": 1672531200,
"date": "2023-01-01 00:00:00 UTC",
"price": 16547.32,
"coin_id": "bitcoin",
"coin_symbol": "BTC",
"coin_name": "Bitcoin",
"status": "success",
"error": None
},
{
"timestamp": "yesterday",
"parsed_timestamp": 1672444800,
"date": "2022-12-31 00:00:00 UTC",
"price": 16625.11,
"coin_id": "bitcoin",
"coin_symbol": "BTC",
"coin_name": "Bitcoin",
"status": "success",
"error": None
}
]
}
],
"env_vars": {
"COINGECKO_API_KEY": {
"description": "CoinGecko Pro API key for authentication",
"required": True,
"url": "https://coingecko.com/en/api"
}
},
"data_availability": {
"current": "Real-time updates every 20 seconds",
"historical": "Available from February 9, 2018 onwards"
}
}
}
def get_coin_prices_at_timestamps(coin_ids: Union[str, List[str]],
timestamps: List[str] = None,
vs_currency: str = 'usd',
rate_limit_delay: float = 1.0) -> List[Dict[str, Any]]:
"""
Get multiple coin prices at multiple specific timestamps.
This function fetches prices for one or more coins at multiple timestamps using CoinGecko API.
It automatically handles different time input formats and uses appropriate
API endpoints for current vs historical prices with rate limiting protection.
Args:
coin_ids (Union[str, List[str]]): Single coin ID/symbol or list of coin IDs/symbols
- String: "bitcoin" or "BTC" for single coin
- String with comma-separation: "BTC,ETH,SOL" for multiple coins
- List: ["bitcoin", "ethereum", "solana"] for multiple coins
timestamps (List[str], optional): List of timestamp strings in various formats (default: ["now"]):
- "now": Current price
- Unix timestamp (1640995200)
- ISO date ('2023-01-01' or '2023-01-01 10:30:00')
- Natural language ('2 weeks ago', 'last month', 'yesterday')
vs_currency (str): The target currency (default: 'usd')
rate_limit_delay (float): Delay between API calls in seconds (default: 1.0)
Returns:
List[Dict[str, Any]]: List of price data dictionaries with:
- timestamp: Original timestamp input
- parsed_timestamp: Unix timestamp (for historical data)
- date: Human readable date
- price: Price in specified currency
- coin_id: CoinGecko coin ID used for API call
- coin_symbol: Coin symbol (e.g., 'BTC')
- coin_name: Coin name (e.g., 'Bitcoin')
- status: 'success' or 'error'
- error: Error message (if status is 'error')
Raises:
ValueError: If coin_ids is invalid
ConnectionError: If API requests fail after retries
Example Usage:
# Single coin with multiple timestamps
timestamps = ["now", "2023-01-01", "30 days ago"]
prices = get_coin_prices_at_timestamps("BTC", timestamps)
# Multiple coins with single timestamp
prices = get_coin_prices_at_timestamps(["BTC", "ETH", "SOL"], ["now"])
# Multiple coins with multiple timestamps (comma-separated string)
prices = get_coin_prices_at_timestamps("BTC,ETH,SOL", ["now", "yesterday"])
for price_data in prices:
print(f"{price_data['coin_symbol']} on {price_data['date']}: ${price_data['price']}")
"""
if not coin_ids:
raise ValueError("coin_ids parameter is required")
# Default to current price if no timestamps provided
if timestamps is None:
timestamps = ["now"]
elif not isinstance(timestamps, list):
raise ValueError("timestamps must be a list")
# Parse coin_ids input - handle string, comma-separated string, or list
if isinstance(coin_ids, str):
# Check if it's comma-separated
if ',' in coin_ids:
coin_list = [coin.strip() for coin in coin_ids.split(',') if coin.strip()]
else:
coin_list = [coin_ids.strip()]
elif isinstance(coin_ids, list):
coin_list = [str(coin).strip() for coin in coin_ids if str(coin).strip()]
else:
raise ValueError("coin_ids must be a string or list of strings")
if not coin_list:
raise ValueError("No valid coin IDs provided")
# Resolve all coin IDs
resolved_coins = []
for coin_input in coin_list:
coin_result = search_coin_by_name(coin_input)
if not coin_result:
raise ValueError(f"Could not find coin with symbol or name: {coin_input}")
resolved_coins.append(coin_result)
results = []
total_api_calls = len(resolved_coins) * len(timestamps)
call_count = 0
# Get prices for each coin at each timestamp
for coin_data in resolved_coins:
actual_coin_id = coin_data['id']
coin_symbol = coin_data['symbol']
coin_name = coin_data['name']
for timestamp in timestamps:
try:
result = _get_single_price(actual_coin_id, timestamp, vs_currency)
result['coin_id'] = actual_coin_id
result['coin_symbol'] = coin_symbol
result['coin_name'] = coin_name
results.append(result)
call_count += 1
# Add rate limiting delay between API calls (except after the last call)
if call_count < total_api_calls:
time.sleep(rate_limit_delay)
except Exception as e:
error_result = {
'timestamp': timestamp,
'parsed_timestamp': None,
'date': str(timestamp),
'price': None,
'coin_id': actual_coin_id,
'coin_symbol': coin_symbol,
'coin_name': coin_name,
'status': 'error',
'error': str(e)
}
results.append(error_result)
continue
return results
def _get_single_price(coin_id: str, timestamp: str, vs_currency: str) -> Dict[str, Any]:
"""Get price for a single timestamp."""
timestamp_str = str(timestamp).strip().lower()
# Handle "now" case - get current price
if timestamp_str == "now":
return _get_current_price(coin_id, vs_currency, timestamp)
# Parse timestamp and get historical price
try:
parsed_ts = parse_flexible_time(timestamp)
return _get_historical_price(coin_id, parsed_ts, vs_currency, timestamp)
except Exception as e:
raise ValueError(f"Invalid timestamp format '{timestamp}': {e}")
def _get_current_price(coin_id: str, vs_currency: str, original_timestamp: str) -> Dict[str, Any]:
"""Get current price using simple/price endpoint."""
url = "https://pro-api.coingecko.com/api/v3/simple/price"
params = {
'ids': coin_id,
'vs_currencies': vs_currency,
'include_last_updated_at': 'true'
}
headers = {"x-cg-pro-api-key": os.getenv("COINGECKO_API_KEY")}
if not headers["x-cg-pro-api-key"]:
raise ValueError("COINGECKO_API_KEY environment variable is required")
# Retry logic
for attempt in range(3):
try:
resp = proxied_get(url, params=params, headers=headers, timeout=15)
resp.raise_for_status()
data = resp.json()
if coin_id not in data:
raise ValueError(f"Coin '{coin_id}' not found")
coin_data = data[coin_id]
price = coin_data.get(vs_currency)
last_updated = coin_data.get('last_updated_at')
if price is None:
raise ValueError(f"Price not available for currency '{vs_currency}'")
return {
'timestamp': original_timestamp,
'parsed_timestamp': last_updated,
'date': datetime.utcfromtimestamp(last_updated).strftime('%Y-%m-%d %H:%M:%S UTC') if last_updated else 'now',
'price': price,
'status': 'success',
'error': None
}
except Exception as e:
if attempt == 2: # Last attempt
raise ConnectionError(f"Failed to fetch current price: {e}")
time.sleep(1)
def _get_historical_price(coin_id: str, timestamp: int, vs_currency: str, original_timestamp: str) -> Dict[str, Any]:
"""Get historical price using history endpoint."""
# Format date for CoinGecko API (dd-mm-yyyy)
date_str = format_dd_mm_yyyy_date(timestamp)
url = f"https://pro-api.coingecko.com/api/v3/coins/{coin_id}/history"
params = {
'date': date_str,
'localization': 'false'
}
headers = {"x-cg-pro-api-key": os.getenv("COINGECKO_API_KEY")}
if not headers["x-cg-pro-api-key"]:
raise ValueError("COINGECKO_API_KEY environment variable is required")
# Retry logic
for attempt in range(3):
try:
resp = proxied_get(url, params=params, headers=headers, timeout=15)
resp.raise_for_status()
data = resp.json()
# Extract price from market_data
if 'market_data' not in data or 'current_price' not in data['market_data']:
raise ValueError(f"Price data not available for date {date_str}")
price_data = data['market_data']['current_price']
price = price_data.get(vs_currency)
if price is None:
raise ValueError(f"Price not available for currency '{vs_currency}' on date {date_str}")
return {
'timestamp': original_timestamp,
'parsed_timestamp': timestamp,
'date': datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S UTC'),
'price': price,
'status': 'success',
'error': None
}
except Exception as e:
if attempt == 2: # Last attempt
raise ConnectionError(f"Failed to fetch historical price for {date_str}: {e}")
time.sleep(1)
def main():
"""Command-line interface for the coin prices at timestamps tool with MCP Schema support."""
import sys
# Handle MCP Schema CLI arguments (only if they don't contain coin_ids or timestamps)
if len(sys.argv) > 1 and not any("coin_ids" in arg or "timestamps" in arg for arg in sys.argv[1:]):
arg = sys.argv[1]
# Handle --help (complete schema) - only if no other arguments
if arg == "--schema" and len(sys.argv) == 2:
print(json.dumps(MCP_TOOL_SCHEMA, indent=2, sort_keys=True, ensure_ascii=False))
return 0
# Handle specific field requests (e.g., --name, --description, --inputSchema)
if arg.startswith("--") and len(arg) > 2 and len(sys.argv) == 2:
field_name = arg[2:] # Remove "--" prefix
if field_name in MCP_TOOL_SCHEMA:
field_value = MCP_TOOL_SCHEMA[field_name]
print(json.dumps(field_value, indent=2, sort_keys=True, ensure_ascii=False))
return 0
# Original CLI functionality
parser = argparse.ArgumentParser(
description="Get coin prices at multiple specific timestamps from CoinGecko API.",
epilog="""INPUT:
--coin_ids: Coin symbols/names (BTC, bitcoin, "BTC,ETH,SOL")
--timestamps: Time points ("now,yesterday,2023-01-01,last month")
OUTPUT:
JSON array with price data for each coin-timestamp combination:
[{"timestamp": "now", "price": 16547.32, "coin_symbol": "BTC",
"coin_name": "Bitcoin", "date": "2023-01-01 00:00:00 UTC", "status": "success"}]
EXAMPLE:
python coin_prices.py --coin_ids BTC --timestamps "now,yesterday"
python coin_prices.py --coin_ids "BTC,ETH" --timestamps "now"
""",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument('--coin_ids', required=True,
help='Coin id(s), symbol(s), or comma-separated list (e.g., "bitcoin", "BTC", "BTC,ETH,SOL")')
parser.add_argument('--timestamps',
help='Comma-separated list of timestamps (e.g., "now,2023-01-01,yesterday"). Default: "now"')
args = parser.parse_args()
try:
# Parse comma-separated timestamps or use default
if args.timestamps:
timestamps = [ts.strip() for ts in args.timestamps.split(',') if ts.strip()]
if not timestamps:
raise ValueError("No valid timestamps provided")
else:
timestamps = None # Will default to ["now"] in function
# Call main function with fixed parameters
results = get_coin_prices_at_timestamps(
coin_ids=args.coin_ids,
timestamps=timestamps,
vs_currency='usd',
rate_limit_delay=1.0
)
# Output in JSON format only
print(json.dumps(results, ensure_ascii=False, indent=2))
except Exception as e:
error_result = {
"error": str(e),
"timestamp": datetime.now().isoformat(),
"status": "failed"
}
print(json.dumps(error_result, indent=2, ensure_ascii=False))
return 1
return 0
if __name__ == "__main__":
exit(main())#!/usr/bin/env python3
"""
CoinGecko Global Data Tools
Tools for fetching global crypto market statistics and DeFi data.
"""
import os
from dotenv import load_dotenv
import json
import argparse
from typing import Dict, Any
from core.http_client import proxied_get
# Load environment variables
load_dotenv()
# MCP Tool Schemas
MCP_GLOBAL_SCHEMA = {
"name": "cg_global",
"title": "CoinGecko Global Market Stats",
"description": "Get global cryptocurrency market statistics including total market cap, volume, BTC dominance.",
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": False
}
}
MCP_GLOBAL_DEFI_SCHEMA = {
"name": "cg_global_defi",
"title": "CoinGecko Global DeFi Stats",
"description": "Get global DeFi market statistics including TVL and DeFi dominance.",
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": False
}
}
def get_api_key() -> str:
"""Get CoinGecko API key from environment."""
api_key = os.getenv("COINGECKO_API_KEY")
if not api_key:
raise ValueError("COINGECKO_API_KEY environment variable is required")
return api_key
def get_global() -> Dict[str, Any]:
"""
Get global cryptocurrency market statistics.
Returns:
Dictionary with market cap, volume, BTC dominance, etc.
"""
api_key = get_api_key()
url = "https://pro-api.coingecko.com/api/v3/global"
headers = {"x-cg-pro-api-key": api_key}
response = proxied_get(url, headers=headers, timeout=15)
response.raise_for_status()
data = response.json().get("data", {})
return {
"active_cryptocurrencies": data.get("active_cryptocurrencies"),
"upcoming_icos": data.get("upcoming_icos"),
"ongoing_icos": data.get("ongoing_icos"),
"ended_icos": data.get("ended_icos"),
"markets": data.get("markets"),
"total_market_cap": data.get("total_market_cap", {}),
"total_volume": data.get("total_volume", {}),
"market_cap_percentage": data.get("market_cap_percentage", {}),
"market_cap_change_percentage_24h_usd": data.get("market_cap_change_percentage_24h_usd"),
"updated_at": data.get("updated_at")
}
def get_global_defi() -> Dict[str, Any]:
"""
Get global DeFi market statistics.
Returns:
Dictionary with DeFi market cap, TVL, dominance
"""
api_key = get_api_key()
url = "https://pro-api.coingecko.com/api/v3/global/decentralized_finance_defi"
headers = {"x-cg-pro-api-key": api_key}
response = proxied_get(url, headers=headers, timeout=15)
response.raise_for_status()
data = response.json().get("data", {})
return {
"defi_market_cap": data.get("defi_market_cap"),
"eth_market_cap": data.get("eth_market_cap"),
"defi_to_eth_ratio": data.get("defi_to_eth_ratio"),
"trading_volume_24h": data.get("trading_volume_24h"),
"defi_dominance": data.get("defi_dominance"),
"top_coin_name": data.get("top_coin_name"),
"top_coin_defi_dominance": data.get("top_coin_defi_dominance")
}
def main():
"""CLI interface for global data tools."""
parser = argparse.ArgumentParser(
description="CoinGecko Global Data Tools",
formatter_class=argparse.RawDescriptionHelpFormatter
)
subparsers = parser.add_subparsers(dest="command")
# Global command
subparsers.add_parser("global", help="Get global market stats")
# DeFi command
subparsers.add_parser("defi", help="Get DeFi market stats")
parser.add_argument("--schema", action="store_true", help="Output MCP schema")
args = parser.parse_args()
if args.schema:
schemas = {
"global": MCP_GLOBAL_SCHEMA,
"global_defi": MCP_GLOBAL_DEFI_SCHEMA
}
print(json.dumps(schemas, indent=2))
return 0
try:
if args.command == "global":
result = get_global()
elif args.command == "defi":
result = get_global_defi()
else:
parser.print_help()
return 0
print(json.dumps(result, indent=2, ensure_ascii=False))
return 0
except Exception as e:
print(json.dumps({"error": str(e)}, indent=2))
return 1
if __name__ == "__main__":
exit(main())
Related skills
How it compares
Use coingecko when agent workflows need broad market discovery and pricing feeds; prefer on-chain signal skills for wallet-level smart-money activity.
FAQ
What does coingecko do?
|
When should I use coingecko?
|
Is coingecko safe to install?
Review the Security Audits panel on this page before installing in production.