BizzleBot 62e32fc655 feat: replace ML optimizer with on-chain accumulation zone monitor
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>
2026-03-20 22:31:29 +00:00

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