You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/common/tools/marketcap.py

88 lines
3.1 KiB

#!/usr/bin/env python3
"""Fetch market capitalization data."""
import json
import os
import time
import requests
COINMAKETCAP_CACHE = os.path.join(os.path.dirname(__file__), "coinmarketcap.json")
COINMARKETCAP_API_BASE = "https://pro-api.coinmarketcap.com/v1/"
COINS_SEARCHABLE = {}
def call(endpoint, api_key, params=None):
url = COINMARKETCAP_API_BASE + endpoint
r = requests.get(url, params=params, headers={"X-CMC_PRO_API_KEY": api_key})
r.raise_for_status()
return r.json()
def init(api_key, refresh=None):
global COINS_SEARCHABLE
force_refresh = refresh is True
disable_refresh = refresh is False
try:
try:
mtime = os.path.getmtime(COINMAKETCAP_CACHE)
except FileNotFoundError:
mtime = 0
cache_is_fresh = mtime > time.time() - 3600
if disable_refresh or (cache_is_fresh and not force_refresh):
print("Using cached market cap data")
with open(COINMAKETCAP_CACHE) as f:
coinmarketcap_data = json.load(f)
else:
print("Fetching market cap data")
coinmarketcap_data = call(
"cryptocurrency/listings/latest",
api_key,
params={"limit": 5000, "convert": "USD"},
)
by_id = {str(coin["id"]): coin for coin in coinmarketcap_data["data"]}
all_ids = list(by_id.keys())
while all_ids:
first_100 = all_ids[:100]
all_ids = all_ids[100:]
time.sleep(2.2)
print(f"Fetching metadata, {len(all_ids)} coins remaining...")
metadata = call(
"cryptocurrency/info", api_key, params={"id": ",".join(first_100)}
)
for coin_id, meta in metadata["data"].items():
by_id[coin_id]["meta"] = meta
with open(COINMAKETCAP_CACHE, "w") as f:
json.dump(coinmarketcap_data, f)
except Exception as e:
raise RuntimeError("market cap data unavailable") from e
data_searchable = {}
for coin in coinmarketcap_data["data"]:
slug = coin["slug"]
symbol = coin["symbol"]
platform = coin["meta"]["platform"]
data_searchable[slug] = data_searchable[symbol] = coin
if platform is not None and platform["name"] == "Ethereum":
address = platform["token_address"].lower()
data_searchable[address] = coin
for explorer in coin["meta"]["urls"]["explorer"]:
# some tokens exist in multiple places, such as BNB and ETH
# then the "platform" field might list the wrong thing
# to be sure, walk the list of explorers and look for etherscan.io
if explorer.startswith("https://etherscan.io/token/"):
address = explorer.rsplit("/", 1)[-1].lower()
data_searchable[address] = coin
COINS_SEARCHABLE = data_searchable
def fiat_price(coin_symbol):
data = COINS_SEARCHABLE.get(coin_symbol)
if data is None:
return None
return data["quote"]["USD"]["price"]