Skip to main content
Glama

funding-rates-mcp

cli.py6.08 kB
import os from typing import List, Optional, Dict from dataclasses import dataclass from mcp.server.fastmcp import FastMCP import ccxt import pandas as pd from cachetools import TTLCache from dotenv import load_dotenv # Load environment variables load_dotenv() # Configuration SUPPORTED_EXCHANGES = ["binance", "okx", "bybit", "bitget", "gate", "coinex"] CACHE_TTL = 300 # Cache current rates for 5 minutes cache = TTLCache(maxsize=100, ttl=CACHE_TTL) # Data structure for funding rate @dataclass class FundingRate: exchange: str symbol: str rate: float timestamp: int # Initialize exchange clients exchanges = { name: getattr(ccxt, name)({ 'enableRateLimit': True }) for name in SUPPORTED_EXCHANGES } # Lifespan management def app_lifespan(server: FastMCP): """Manage application lifecycle""" yield {} # Create MCP server mcp = FastMCP( name="Funding Rates MCP", dependencies=["ccxt", "cachetools", "python-dotenv", "pandas"], lifespan=app_lifespan ) # Fetch funding rates for multiple symbols def fetch_funding_rates(exchange_name: str, symbols: List[str], params: Dict = {}) -> List[FundingRate]: """Fetch current funding rates for multiple symbols from an exchange Parameters: exchange_name (str): Name of the exchange (e.g., "binance"). symbols (List[str]): List of trading pairs (e.g., ["BTC/USDT:USDT", "ETH/USDT:USDT"]). params (Dict, optional): Additional parameters for the API call (e.g., {"type": "swap"}). Defaults to {}. Returns: List[FundingRate]: List of funding rate objects for the requested symbols. """ # Create cache key including params to avoid mixing different API calls params_key = ":".join(f"{k}={v}" for k, v in sorted(params.items())) cache_key = f"{exchange_name}:funding_rates:{','.join(symbols)}:{params_key}" if cache_key in cache: # Filter cached rates for requested symbols cached_rates = cache[cache_key] return [rate for rate in cached_rates if rate.symbol in symbols] exchange = exchanges.get(exchange_name) if not exchange: raise ValueError(f"Unsupported exchange: {exchange_name}") # Fetch funding rates for specified symbols if exchange_name in ['okx', 'cryptocom']: funding_data = {} for symbol in symbols: funding_data[symbol] = exchange.fetch_funding_rate(symbol, params) else: funding_data = exchange.fetch_funding_rates(symbols, params) funding_rates = [] for symbol in symbols: funding_info = funding_data.get(symbol) if funding_info and "fundingRate" in funding_info and "timestamp" in funding_info: funding_rates.append(FundingRate( exchange=exchange_name, symbol=symbol, rate=float(funding_info["fundingRate"]), timestamp=int(funding_info["timestamp"] or funding_info["fundingTimestamp"]) )) cache[cache_key] = funding_rates return [rate for rate in funding_rates if rate.symbol in symbols] # Tools @mcp.tool() def compare_funding_rates( symbols: List[str], exchanges: List[str] = [], params: Dict = {} ) -> str: """ Compare current funding rates for multiple symbols across specified exchanges. Parameters: symbols (List[str]): List of trading pairs (e.g., ["BTC/USDT:USDT", "ETH/USDT:USDT"]). exchanges (List[str], optional): List of exchanges to compare (e.g., ["binance", "bybit"]). Defaults to all supported exchanges (binance, bybit, okx). params (Dict, optional): Additional parameters for the API call (e.g., {"type": "swap"}). Defaults to {}. Returns: str: Markdown table comparing funding rates across exchanges and symbols. """ if not symbols: raise ValueError("At least one symbol must be provided") if not exchanges: exchanges = SUPPORTED_EXCHANGES invalid_exchanges = [ex for ex in exchanges if ex not in SUPPORTED_EXCHANGES] if invalid_exchanges: raise ValueError(f"Unsupported exchanges: {invalid_exchanges}") results = [] for exchange in exchanges: funding_rates = fetch_funding_rates(exchange, symbols, params) for symbol in symbols: rate_info = next((r for r in funding_rates if r.symbol == symbol), None) results.append({ "Exchange": exchange, "Symbol": symbol, "Funding Rate": rate_info.rate if rate_info else None, "Formatted Rate": f"{rate_info.rate:.6%}" if rate_info else "Unavailable" }) # Create pivoted table df = pd.DataFrame(results) pivot_df = df.pivot_table( index="Symbol", columns="Exchange", values="Formatted Rate", aggfunc="first" ).fillna("Unavailable") # Calculate divergence (max - min funding rate) for each symbol numeric_df = df.pivot_table( index="Symbol", columns="Exchange", values="Funding Rate", aggfunc="first" ) divergence = numeric_df.apply( lambda row: f"{(row.max() - row.min()):.6%}" if row.notna().any() else "Unavailable", axis=1 ) # Add Divergence column pivot_df["Divergence"] = divergence # Rename index for header pivot_df.index.name = "Symbol\Exchange" return f"Current funding rates:\n\n{pivot_df.to_markdown()}" @mcp.prompt() def compare_funding_rates_prompt(symbols: List[str]) -> str: """ Compare current funding rates for multiple symbols across all exchanges. Args: symbols (List[str]): List of trading pairs (e.g., ["BTC/USDT:USDT", "ETH/USDT:USDT"]). Returns: str: Prompt for comparing funding rates. """ if not symbols: raise ValueError("At least one symbol must be provided") return f"Compare the funding rates for {', '.join(symbols)} across {', '.join(SUPPORTED_EXCHANGES)}." # Main execution def main() -> None: mcp.run()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kukapay/funding-rates-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server