mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-04 21:48:17 +00:00
112 lines
3.7 KiB
Python
112 lines
3.7 KiB
Python
#!/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("Fetching metadata, {} coins remaining...".format(len(all_ids)))
|
|
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 get_coin(coin):
|
|
if coin["type"] == "erc20":
|
|
address = coin["address"].lower()
|
|
return COINS_SEARCHABLE.get(address)
|
|
|
|
data = None
|
|
if "coinmarketcap_alias" in coin:
|
|
data = COINS_SEARCHABLE.get(coin["coinmarketcap_alias"])
|
|
if data is None:
|
|
slug = coin["name"].replace(" ", "-").lower()
|
|
data = COINS_SEARCHABLE.get(slug)
|
|
if data is None:
|
|
data = COINS_SEARCHABLE.get(coin["shortcut"].lower())
|
|
return data
|
|
|
|
|
|
def marketcap(coin):
|
|
data = get_coin(coin)
|
|
if data is None:
|
|
return None
|
|
|
|
return int(data["quote"]["USD"]["market_cap"])
|
|
|
|
|
|
def fiat_price(coin_symbol):
|
|
data = COINS_SEARCHABLE.get(coin_symbol)
|
|
if data is None:
|
|
return None
|
|
|
|
return data["quote"]["USD"]["price"]
|