"""BTC price data from CoinGecko API.""" import logging import requests log = logging.getLogger(__name__) PRICE_URL = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd&include_24hr_change=true" HISTORY_URL = "https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=365" ATH_URL = "https://api.coingecko.com/api/v3/coins/bitcoin?localization=false&tickers=false&market_data=true&community_data=false&developer_data=false" def fetch_current(): """Fetch current BTC price and 24h change.""" try: resp = requests.get(PRICE_URL, timeout=15) resp.raise_for_status() data = resp.json() btc = data.get("bitcoin", {}) return { "price": btc.get("usd"), "change_24h": btc.get("usd_24h_change"), } except Exception as e: log.error("Price fetch error: %s", e) return {"price": None, "error": str(e)} def fetch_historical(): """Fetch 365 days of BTC price history. Returns list of [timestamp, price].""" try: resp = requests.get(HISTORY_URL, timeout=30) resp.raise_for_status() data = resp.json() prices = data.get("prices", []) return prices except Exception as e: log.error("Historical price fetch error: %s", e) return [] def fetch_ath(): """Fetch BTC all-time high from CoinGecko.""" try: resp = requests.get(ATH_URL, timeout=15) resp.raise_for_status() data = resp.json() market = data.get("market_data", {}) ath = market.get("ath", {}).get("usd") ath_change = market.get("ath_change_percentage", {}).get("usd") return { "ath": ath, "ath_change_pct": ath_change, } except Exception as e: log.error("ATH fetch error: %s", e) return {"ath": None, "error": str(e)} def calculate_200d_sma(prices): """Calculate 200-day SMA from historical price data.""" if not prices or len(prices) < 200: return None # prices is [[timestamp, price], ...] recent_200 = [p[1] for p in prices[-200:]] return sum(recent_200) / len(recent_200) def calculate_mayer_multiple(current_price, sma_200d): """Mayer Multiple = current price / 200-day SMA.""" if not current_price or not sma_200d or sma_200d == 0: return None return current_price / sma_200d def calculate_drawdown(current_price, ath): """Drawdown from ATH as percentage.""" if not current_price or not ath or ath == 0: return None return (ath - current_price) / ath * 100