CryptoSentinel_AI / app /price_fetcher.py
mgbam's picture
Update app/price_fetcher.py
476cee0 verified
raw
history blame
2.26 kB
"""
Background price cache with multi-API fallback and rate-limit handling
"""
import httpx
import logging
# Primary and secondary APIs for crypto prices
COINGECKO_URL = (
"https://api.coingecko.com/api/v3/simple/price"
"?ids=bitcoin,ethereum,dogecoin&vs_currencies=usd"
)
COINCAP_URL = (
"https://api.coincap.io/v2/assets?ids=bitcoin,ethereum,dogecoin"
)
# Shared price cache
CURRENT_PRICES = {"bitcoin": "--", "ethereum": "--", "dogecoin": "--"}
# How often to retry each API before falling back (seconds)
RETRY_DELAY = 5
def fetch_prices() -> None:
"""
Try CoinGecko first; on 429 or error, fall back to CoinCap.
Updates CURRENT_PRICES in-place.
"""
global CURRENT_PRICES
apis = [
("CoinGecko", COINGECKO_URL),
("CoinCap", COINCAP_URL)
]
for name, url in apis:
try:
resp = httpx.get(url, timeout=10)
# Handle CoinCap JSON structure separately
if name == "CoinGecko":
resp.raise_for_status()
data = resp.json()
prices = {
"bitcoin": data["bitcoin"]["usd"],
"ethereum": data["ethereum"]["usd"],
"dogecoin": data["dogecoin"]["usd"]
}
else:
resp.raise_for_status()
data = resp.json().get("data", [])
prices = {item["id"]: float(item["priceUsd"]) for item in data}
CURRENT_PRICES.update(prices)
logging.info("✅ [%s] prices updated: %s", name, prices)
return
except httpx.HTTPStatusError as e:
status = e.response.status_code
if status == 429:
logging.warning("⚠️ [%s] rate limit (429). Retrying fallback.", name)
else:
logging.warning("⚠️ [%s] HTTP error %s: %s", name, status, e)
except Exception as e:
logging.warning("⚠️ [%s] fetch error: %s", name, e)
# If we reach here, wait a bit before trying next API
try:
import time; time.sleep(RETRY_DELAY)
except Exception:
pass
logging.error("❌ All price APIs failed. Keeping previous prices: %s", CURRENT_PRICES)