Bitcoin Accumulation Zone Monitor
Bitcoin on-chain metrics dashboard with classic equal-weight scoring, ML-optimized scoring, historical backtesting, and click-to-select metric context for long-term BTC accumulation decisions.
What It Does
Monitors Bitcoin accumulation conditions using 16 scored market/on-chain indicators plus optional informational cycle metrics. Each scored metric receives a 0-10 score and rolls into a 0-100 accumulation score.
The dashboard now supports two scoring modes:
- Classic — transparent equal-weight scoring across every active metric.
- ML — feature-importance weights trained against historical 365-day forward returns, with displayed per-metric weights and point contributions.
Historical backtests show score-vs-price behavior, score bracket performance, major signal events, and current-score context. Metric cards are clickable: selecting a metric overlays its historical series on the score chart and shows comparable historical periods with forward returns.
Screenshots
Main Dashboard — ML mode + metric context
Live BTC price, Classic/ML scoring toggle, 16 active scored metrics, ML weights/contributions, metric sparklines, and click-to-select historical context.
Historical Backtest
Current signal percentile, comparable historical periods by cycle, score-vs-BTC chart, bracket performance, and major signal events.
Settings
LLM provider configuration for optional AI-powered signal commentary and local/cloud model selection.
Feature Highlights
- 16 scored metrics from market sentiment, miner stress, valuation, holder behavior, network activity, and velocity signals.
- Classic vs ML scoring toggle on the dashboard and backtest API.
- ML score explainability: metric cards show learned weight and contribution in points.
- Leakage-resistant ML validation: training uses purged time-series splits so 365-day forward-return labels do not overlap validation windows.
- Historical context panel: compares the current composite score against historical periods and forward returns.
- Clickable metric cards: select any metric to see percentile, similar historical levels, forward returns, example dates by market cycle, and highlighted chart periods.
- Score history chart with BTC price overlay, range controls, and selected-metric overlay.
- Backtest dashboard with current signal context, score bracket performance, and signal-crossing events.
- Quick vs full refresh: quick refresh updates BTC price and Fear & Greed; full refresh re-scrapes on-chain sources.
- LLM settings UI for Ollama, LM Studio, OpenAI, Anthropic, and OpenRouter.
Metrics
| # | Metric | Source | Accumulation Signal |
|---|---|---|---|
| 1 | Fear & Greed Index | alternative.me API | Extreme fear / capitulation sentiment |
| 2 | Puell Multiple | LookIntoBitcoin | Miner revenue stress |
| 3 | MVRV Z-Score | LookIntoBitcoin | Market near/below realized value |
| 4 | Drawdown from ATH | Calculated from BTC price | Deep correction from cycle high |
| 5 | Price vs 200W SMA | LookIntoBitcoin + BTC price | Price near/below long-term trend |
| 6 | Reserve Risk | LookIntoBitcoin | High holder confidence relative to price |
| 7 | RHODL Ratio | LookIntoBitcoin | Long-term holder dominance |
| 8 | Net Unrealized Profit/Loss (NUPL) | LookIntoBitcoin | Capitulation / early recovery zones |
| 9 | LTH Realized Price | LookIntoBitcoin | Price near long-term holder cost basis |
| 10 | Hash Ribbons | LookIntoBitcoin | Miner capitulation/recovery signal |
| 11 | SOPR | CheckOnChain | Spent outputs near loss / reset territory |
| 12 | Sell-side Risk Ratio | CheckOnChain | Low realized profit/loss pressure |
| 13 | Active Address Momentum | CheckOnChain | Network activity momentum extremes |
| 14 | Transaction Count Momentum | CheckOnChain | Transaction activity momentum extremes |
| 15 | NVT Price | CheckOnChain | Network-value valuation discount/premium |
| 16 | VDD Multiple | CheckOnChain | Coin-days/velocity reset conditions |
Informational cards may also appear when data is available, such as Long-Term Holder Supply and Pi Cycle Bottom. These are displayed for context and are not included in the composite score.
Score Interpretation
| Score | Assessment | Interpretation |
|---|---|---|
| 80-100 | 🟢 Extreme Accumulation Zone | Broad capitulation/value conditions across active metrics |
| 65-79 | 🟢 Strong Accumulation Zone | Historically attractive long-term entry territory |
| 50-64 | 🟡 Moderate Opportunity | DCA-friendly, but not maximum-signal conditions |
| 35-49 | 🟡 Neutral | Mixed signals; not compelling either direction |
| 20-34 | 🔴 Caution — Overheated | Market conditions becoming less favorable |
| 0-19 | 🔴 Extreme Caution | Historically poor accumulation setup |
Backtest tables provide actual historical forward-return statistics per score bracket, including 30d/90d/180d/1yr averages, win rate, max gain/loss, and average max drawdown.
ML-Optimized Scoring
The ML mode uses a GradientBoostingClassifier trained on historical feature rows to predict whether a day was a good long-term buy based on 365-day forward return. Training features include:
- Classic metric scores.
- Raw metric values.
- 30-day metric deltas.
- Interaction features such as MVRV × NUPL and Puell × Reserve Risk.
- Cycle-position context such as days since ATH.
The resulting feature importances are aggregated back into transparent metric weights stored in config/ml_weights.json. The UI displays normalized weight and contribution for each active metric.
Validation uses purged expanding time-series splits: because each label uses a 365-day forward-return window, training rows whose label windows overlap validation are removed before scoring validation folds.
Tech Stack
| Component | Technology |
|---|---|
| Backend | Python 3.13 + FastAPI |
| Frontend | Inline HTML/CSS/JS dark trading-terminal UI |
| Charts | Chart.js |
| Scraping | requests + Playwright-style browser scraping where needed |
| Data APIs | alternative.me, CoinGecko, LookIntoBitcoin, CheckOnChain |
| ML | NumPy + pandas + scikit-learn GradientBoostingClassifier |
| Process Manager | pm2 or uvicorn |
| Default Port | 3088 |
How Data Is Collected
Data is collected from free/public sources and cached locally under data/.
- Fast live refreshes update BTC price, ATH/drawdown, 200D SMA/Mayer where possible, and Fear & Greed.
- On-chain metrics are cached and reused because they update slowly.
- Full refresh re-scrapes on-chain metrics from LookIntoBitcoin/CheckOnChain.
- Historical backtest data lives in
data/history.jsonand supports charting, backtests, and metric-context lookups. - Score history appends to
data/score_history.jsonl.
Project Structure
├── dashboard/
│ └── server.py # FastAPI server + inline dashboard/backtest/settings UI
├── scrapers/
│ ├── lookintobitcoin.py # LookIntoBitcoin metric scraping
│ ├── checkonchain.py # CheckOnChain metric scraping
│ ├── history_collector.py # Full historical data collection
│ ├── history_updater.py # Incremental historical updates
│ ├── fear_greed.py # Fear & Greed Index API
│ └── price.py # BTC price, ATH, drawdown, SMA helpers
├── scoring/
│ └── engine.py # Classic + ML-weighted scoring logic
├── backtesting/
│ └── engine.py # Historical backtest engine
├── ml/
│ └── optimizer.py # ML training, purged CV, weight export
├── tests/
│ ├── test_ml_optimizer_validation.py
│ └── test_scoring_engine_ml.py
├── data/
│ ├── cache.json # Live metric cache
│ ├── history.json # Historical metric/time-series data
│ └── score_history.jsonl # Live score history
├── config/
│ ├── thresholds.json # Classic scoring thresholds
│ ├── ml_weights.json # Learned ML metric weights
│ └── llm_settings.json # Optional AI commentary provider config
├── screenshots/ # README screenshots
├── ARCHITECTURE.md
└── README.md
Running
Local / ad-hoc with uv
cd /opt/data/btc-accumulation-monitor
PYTHONPATH=. uv run \
--with fastapi \
--with uvicorn \
--with requests \
--with pandas \
--with numpy \
--with scikit-learn \
python -m uvicorn dashboard.server:app --host 0.0.0.0 --port 3088
VPS-style install
cd /opt/apps/btc-ml-optimizer
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements_vps.txt pandas numpy scikit-learn
python -m uvicorn dashboard.server:app --host 0.0.0.0 --port 3088
pm2
pm2 start "python3 -m uvicorn dashboard.server:app --host 0.0.0.0 --port 3088" --name btc-ml-optimizer
First Run
- Visit
http://localhost:3088for the live dashboard. - Use Quick Refresh for fast price/Fear & Greed updates.
- Use Full Refresh to re-scrape on-chain metrics.
- Visit
http://localhost:3088/backtestto view historical score performance. - If historical data is missing, use the backtest page's collection flow to populate
data/history.json.
Useful API Endpoints
| Endpoint | Description |
|---|---|
GET /api/data?mode=classic |
Current metrics using equal-weight scoring |
GET /api/data?mode=ml |
Current metrics using ML-optimized weights |
GET /api/history |
Recent live score history |
POST /api/refresh |
Quick refresh |
POST /api/refresh?full=true |
Full on-chain refresh |
GET /api/backtest?mode=classic |
Historical backtest with classic scoring |
GET /api/backtest?mode=ml |
Historical backtest with ML scoring |
GET /api/metric-context?metric=mvrv_zscore&mode=ml |
Similar historical levels and forward returns for one metric |
GET /api/settings |
Safe LLM settings payload |
Testing
Focused tests can be run with uv:
cd /opt/data/btc-accumulation-monitor
PYTHONPATH=. uv run --with pytest --with numpy --with scikit-learn --with pandas \
pytest -q tests/test_ml_optimizer_validation.py tests/test_scoring_engine_ml.py
Architecture
See ARCHITECTURE.md for deeper implementation details on scoring, data collection, and backtesting.
License
Private — not for public distribution.