Complete rewrite — replaces the ML-based signal optimizer with a transparent on-chain metric monitoring dashboard. Scrapes 10 metrics from LookIntoBitcoin (Playwright) and free APIs, scores each 0-10, composite 0-100. Metrics: Fear & Greed, Puell Multiple, MVRV Z-Score, Drawdown from ATH, Price vs 200W SMA, Reserve Risk, RHODL Ratio, NUPL, LTH Realized Price, Hash Ribbons. Auto-refreshes every 15 minutes. Settings page preserved. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
81 lines
2.6 KiB
Python
81 lines
2.6 KiB
Python
"""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
|