import os import json import logging import requests from hyperliquid.info import Info from hyperliquid.utils import constants from logging_utils import setup_logging def update_coin_mapping(): """ Fetches all assets from Hyperliquid and all coins from CoinGecko, then creates and saves a mapping from the Hyperliquid symbol to the CoinGecko ID using a robust matching algorithm. """ setup_logging('normal', 'CoinMapUpdater') logging.info("Starting coin mapping update process...") # --- 1. Fetch all assets from Hyperliquid --- try: logging.info("Fetching assets from Hyperliquid...") info = Info(constants.MAINNET_API_URL, skip_ws=True) meta, asset_contexts = info.meta_and_asset_ctxs() hyperliquid_assets = meta['universe'] logging.info(f"Found {len(hyperliquid_assets)} assets on Hyperliquid.") except Exception as e: logging.error(f"Failed to fetch assets from Hyperliquid: {e}") return # --- 2. Fetch all coins from CoinGecko --- try: logging.info("Fetching coin list from CoinGecko...") response = requests.get("https://api.coingecko.com/api/v3/coins/list") response.raise_for_status() coingecko_coins = response.json() # Create more robust lookup tables cg_symbol_lookup = {coin['symbol'].upper(): coin['id'] for coin in coingecko_coins} cg_name_lookup = {coin['name'].upper(): coin['id'] for coin in coingecko_coins} logging.info(f"Found {len(coingecko_coins)} coins on CoinGecko.") except requests.exceptions.RequestException as e: logging.error(f"Failed to fetch coin list from CoinGecko: {e}") return # --- 3. Create the mapping --- final_mapping = {} # Use manual overrides for critical coins where symbols are ambiguous manual_overrides = { "BTC": "bitcoin", "ETH": "ethereum", "SOL": "solana", "BNB": "binancecoin", "HYPE": "hyperliquid", "PUMP": "pump-fun", "ASTER": "astar", "ZEC": "zcash", "SUI": "sui", "ACE": "endurance", # Add other important ones you watch here } logging.info("Generating symbol-to-id mapping...") for asset in hyperliquid_assets: asset_symbol = asset['name'].upper() asset_name = asset.get('name', '').upper() # Use full name if available # Priority 1: Manual Overrides if asset_symbol in manual_overrides: final_mapping[asset_symbol] = manual_overrides[asset_symbol] continue # Priority 2: Exact Name Match if asset_name in cg_name_lookup: final_mapping[asset_symbol] = cg_name_lookup[asset_name] continue # Priority 3: Symbol Match if asset_symbol in cg_symbol_lookup: final_mapping[asset_symbol] = cg_symbol_lookup[asset_symbol] else: logging.warning(f"No match found for '{asset_symbol}' on CoinGecko. It will be excluded.") # --- 4. Save the mapping to a file --- map_file_path = os.path.join("_data", "coin_id_map.json") try: with open(map_file_path, 'w', encoding='utf-8') as f: json.dump(final_mapping, f, indent=4, sort_keys=True) logging.info(f"Successfully saved new coin mapping with {len(final_mapping)} entries to '{map_file_path}'.") except IOError as e: logging.error(f"Failed to write coin mapping file: {e}") if __name__ == "__main__": update_coin_mapping()