BG Lab: On-Chain Trading Rules, Tested Honestly
Every on-chain chart invites the same question: if I had followed this, would it have worked? “Buy when MVRV is low”, “get out when holders are euphoric”, “follow the exchange outflows”. The charts make it look obvious in hindsight. The honest answer requires a backtest, and an honest backtest is harder than it looks, because the easiest person to fool is the one who builds it.
BG Lab, now live at bgeometrics.com/lab and in the API, is our attempt to answer that question properly. It searches thousands of simple rules built on BGeometrics metrics, keeps only the ones that survive a set of deliberately hard filters, tests them on years of data they were never allowed to see, and then tracks them live with their thresholds frozen. The idea of a rule-search lab isn’t new (Glassnode previewed one this year); the engine, the metrics and the filters behind ours are our own.
What a rule is
A rule is one or two conditions on a metric, written as a sentence you can check yourself:
MVRV Percentile(365) > 46.6 → Long
Sortino Ratio 364d RSI(14) > 57.6 AND Net Unrealized Loss Z-Score(90) < −0.331 → Long
Every day, at the close, the rule is either in (hold BTC) or out (hold cash). The position is taken the next day, so the backtest never uses a number that wasn’t published yet. Every change of position pays a 0.1% fee. And every result is shown next to the only benchmark that matters for most people: buy & hold.
No leverage, no shorting, no position sizing. Long or flat. If a rule can’t add value in that format, more complexity won’t rescue it.
How rules are found
The engine starts from about 40 BGeometrics metrics: valuation (MVRV, NUPL, Mayer Multiple, Thermocap), holder behaviour (LTH/STH NUPL, SOPR, Reserve Risk, dormancy), mining (Puell Multiple, hashrate), exchange flows and reserves, capital flows and derivatives. Each one is used in seven simple forms:
| Transform | Meaning |
|---|---|
| Raw | The value as published by the API |
| Z-Score(90), Z-Score(365) | Distance from its own recent mean, in standard deviations |
| Percentile(365) | Where today’s value ranks within the last year (0-100) |
| RSI(14), RSI(30) | Momentum of the metric itself |
| / MA(30), / MA(90) | The metric relative to its own moving average |
That gives about 290 features. For each one the engine tests nine thresholds in both directions, then combines the best single conditions into pairs. A typical daily run evaluates about 6,800 rules.
The problem with testing 6,800 rules
Test enough rules and some will look brilliant by pure chance. That isn’t a risk; it’s a certainty. Most published backtests don’t fail because the maths is wrong; they fail because the best of thousands of attempts is presented as if it were the only one.
So every rule has to pass six filters before it can be published:
- Unseen data. Rules are selected using only the oldest 80% of history (2014 to March 2024). The most recent 20%, from March 2024 to today, is held out and never used to pick anything. It’s the closest thing to a real test the past can offer.
- Walk-forward. The selection period is split into four sub-periods, and the rule has to beat buy & hold in at least three of them. A rule that made all its money in 2017 doesn’t qualify.
- Threshold stability. If a rule works at 1.71 but fails at 1.65 and 1.80, it’s a tuned number, not a signal. Neighbouring thresholds must work too.
- Activity. At least 12 entries in the selection period, between 15% and 90% of the time in the market, and at least one entry in the last year. A rule that hasn’t fired since 2022 has nothing to say about today.
- Beat momentum. This one turned out to matter most (more below). A rule must beat a plain “BTC price above its 50-day average” rule over the same period, not just buy & hold.
- Deflated Sharpe. The Deflated Sharpe Ratio (Bailey & López de Prado) estimates the probability that a Sharpe ratio reflects real skill rather than the luck of the draw, given how many rules were tried. We show it on every rule as “Not luck”. The usual bar is 95%.
What it found
Here is the honest summary of the first runs.
Most on-chain rules are price momentum in disguise. An RSI(14) above 50 on MVRV or NUPL looks like an on-chain signal, but MVRV and NUPL move with price, so the rule is largely “price went up recently”. That’s why filter 5 exists: before it, the catalogue was full of rules that a 50-day moving average does just as well, with no on-chain data at all.
The best rule in training failed on unseen data. The highest-scoring rule of the first run, Thermocap Multiple RSI(30) > 52.4 AND Exchange Reserve RSI(30) < 65.3, had a training Sharpe of 2.07 and the highest “Not luck” score of the whole run, 44%. On the held-out period it went nowhere: ×0.99 while buy & hold made ×1.20. That’s exactly what the held-out period is for, and exactly why it’s never used for selection.
Roughly half of the rules that pass every filter still fail on unseen data. Passing the filters is necessary, not sufficient.
The engine found a data problem. Before searching, the engine checks whether any metric is more correlated with the next day’s price move than with the same day’s, which is the fingerprint of a timestamp shifted forward. The Puell Multiple tripped it: its history before 2025 was stamped one day early, which made it look predictive in a backtest. We fixed the historical series in the API, and the check now comes back clean every day.
The first published rules
Five rules are published today. Numbers below are for the unseen period (2024-03-30 to 2026-10-21), next to the two benchmarks over the same days:
| Rule | Growth | Sharpe | Max drawdown | Time in market | Not luck |
|---|---|---|---|---|---|
| Sortino Ratio 364d RSI(14) > 57.6 AND Net Unrealized Loss Z(90) < −0.331 | ×1.52 | 0.98 | −14% | 18% | 3% |
| Thermocap Multiple RSI(30) > 52.4 AND Net Unrealized Loss Z(90) < −0.331 | ×1.45 | 0.72 | −22% | 35% | 17% |
| Net Capital Flow 30d % Percentile(365) > 60.8 | ×1.43 | 0.71 | −22% | 31% | 4% |
| MVRV Z-Score RSI(14) > 50.2 AND Reserve Risk Percentile(365) > 18.3 | ×1.37 | 0.61 | −27% | 36% | 20% |
| MVRV Percentile(365) > 46.6 | ×1.32 | 0.52 | −29% | 48% | 6% |
| Buy & hold BTC | ×1.20 | 0.38 | −53% | 100% | |
| BTC price > MA(50) | ×1.43 | 0.62 | −26% | 55% |
All five beat buy & hold on unseen data, with roughly half the drawdown or less. But read the last row carefully: a plain 50-day moving average did about as well as the middle of the table. Three of the five rules beat it on a risk-adjusted basis; two don’t. And none of them comes close to the 95% “Not luck” bar. We could have hidden that column. We’d rather you see it.
What these rules do have in common is that they spend most of their time out of the market and avoid the deepest drawdowns. Whether that is skill or a feature of the last two and a half years is precisely what live tracking will tell.
Live tracking: the test that can’t be overfitted
The held-out period is honest, but it’s still the past, and we chose which rules to publish after seeing it. The only test that can’t be gamed is the future.
So the day a rule enters the catalogue, its thresholds are frozen. From then on the Lab shows its real performance against buy & hold since that date, with no re-tuning. If a rule stops passing the filters, it leaves the catalogue, but its history isn’t deleted. Today that live record is only days old; over the coming months it becomes the most important number on the page.
What you see on the page
At bgeometrics.com/lab, logged-in users get:
- Today’s pulse: how many published rules are long BTC at the latest close, next to buy & hold and the momentum benchmark over the unseen period.
- A card per rule: its conditions, whether it is long or in cash today, growth and Sharpe against buy & hold, max drawdown, time in market, “Not luck” and live performance.
- The equity curve of each rule against buy & hold, on a log scale, for the unseen period or the full history since 2014, with the signal for every day.
The engine runs every day after the metrics update, so the state and the curves are always current.
In the API
Everything on the page is also available in the BGeometrics API, for users with an active token:
| Endpoint | Returns |
|---|---|
/v1/lab/rules | The published rules, with all their statistics |
/v1/lab/rules/{ruleKey} | One rule plus its daily signal and equity vs. buy & hold (startday, endday optional) |
/v1/lab/pulse | Which published rules are long BTC today |
/v1/lab/run/last | The latest engine run: windows, number of rules tested, benchmarks |
curl "https://api.bitcoin-data.com/v1/lab/pulse?token=YOUR_TOKEN"
Every field is documented in the API reference, under BG Lab.
Limitations
- Backtests flatter. Some on-chain metrics are revised as more data arrives, so the value a rule “saw” in the past may differ slightly from what was published at the time. That tends to make backtests look better than reality.
- One asset, one regime. All the unseen data comes from a single market phase, 2024 to 2026. Rules that sit out of the market look good in some regimes and lag badly in others.
- Selection bias doesn’t disappear. Holding out data reduces it; it doesn’t remove it. That’s why “Not luck” is on every card and why live tracking matters more than any backtest.
BG Lab is an analysis tool, not investment advice.
What’s next
- Alerts when a published rule changes state, through Signals and Telegram.
- Lab tools in the BGeometrics MCP server, so you can ask Claude which rules are active and why.
- A rule builder: pick a metric, a transform and a threshold, and see its backtest, with the same filters, instantly.
If a rule ever clears the 95% bar and keeps working live, you’ll read about it here first. If none does, that’s worth knowing too.
See the metrics in this article live
Free interactive charts, or full historical access with a paid plan.