Forward Forecasting logo FORWARDFORECASTING

Field Notes · Blockchain Analytics

Do Whales Move Bitcoin? Building an Analytics Demo Honest Enough to Say "Not Sure Yet"

Real BTC price data, real on-chain fundamentals, and a full scan of real recent Bitcoin blocks for whale transactions, run through a statistical test old enough to have been named after a 1983 paper, and the most interesting result was the one the dashboard refused to fake.

Fernando Borbón Bitcoin on-chain background from a prior personal analysis project Live at forwardforecasting.eu/blockchain-analytics
Editorial illustration of a golden whale breaching through a glowing candlestick price chart on a deep navy background

During one of my analyses, I pulled on-chain insights from Bitcoin's BigQuery dataset, wrote an anomaly detector for time-series metrics, and poked around an Ethereum address. I never got to build on any of it afterward. This project revisits that same territory on my own terms, with the one big constraint changed: instead of a paid BigQuery dataset, everything here runs on free public APIs, and instead of a one-off exercise, it has to actually answer a real question. Does big-wallet ("whale") transaction activity actually move the Bitcoin price, or is that just a story crypto Twitter tells itself?

This is the write-up. The live demo is linked at the bottom, and the repository is public.

Three free APIs standing in for a BigQuery dataset

The original challenge pointed at Google's BigQuery Bitcoin dataset, which is genuinely excellent but needs a GCP account, billing set up, and a query-cost budget to manage. None of that is a good fit for a self-contained public demo, so this project swaps in three sources that need no account and no API key at all:

CoinGecko
BTC/USD price, market cap, volume, 1yr daily
blockchain.info Charts
Active addresses, tx count, hash rate, more
blockchain.info rawblock
Full block contents, walked back block by block
150 blocks
Every transaction fully scanned, none sampled

rawblock returns an entire block, every transaction with every output value, in one HTTP call. That makes it practical to check every single transaction in a real recent window rather than statistically sampling. It does not make it practical to do that for a full year: roughly 52,000 blocks, well over 300GB of JSON, is not a demo-project ask. So the whale dataset here is real and exhaustive, just deliberately bounded to the most recent window rather than dressed up as more history than it is.

flowchart TD
    A["CoinGecko\nmarket_chart API"] -->|"daily price, market cap, volume"| D["daily_metrics.csv"]
    B["blockchain.info Charts API"] -->|"active addresses, tx count, hash rate"| D
    C["blockchain.info rawblock API"] -->|"real recent block window"| E["whale_transactions.csv"]
    E --> F["whale_daily.csv\ntx count + BTC volume"]
    D --> G["ESD anomaly test\nprice, active addresses"]
    D --> H["lead-lag correlation\nwhale volume vs price returns"]
    F --> H
    G --> I["dashboard_data.json"]
    H --> I
    F --> I
    D --> I
    I --> J["static/index.html\nsynced to forwardforecasting-landing"]
      
Two free API classes and one full block scan, joined into one dashboard

Why a 1983 statistics paper instead of a model

The event-detection task in the original challenge asked for exactly this: flag anomalous points in a time series, ideally without hand-tuning a threshold per series. My answer then was a generalized ESD (Extreme Studentized Deviate) test, from Rosner's 1983 paper, run on the residuals of a series against its own moving average. It is old, it is auditable line by line, and it still works, so I reimplemented it here as a small functional module instead of the original stateful class, and applied it independently to the BTC price series and the active-addresses series.

The result I didn't fake

The interesting question this project set out to answer is whether whale activity leads price moves, lags them, or does neither. The pipeline computes exactly that: Pearson and Spearman correlation between daily whale BTC volume and price returns, at lags from -3 to +3 days. On the run currently live on the dashboard, the honest answer is that the test could not run at all.

"Not enough overlapping days between whale activity and price data to test correlation." That's the dashboard's own summary line, not a hedge I added afterward.

The reason is straightforward once you see it: the whale scan window is real chain activity, but it only spans about two days (150 blocks at roughly 10 minutes each), while the price and on-chain series are daily. Two data points is not a correlation, it's a coin flip. Rather than compute a Pearson r on two rows and print a number that looks precise but means nothing, the pipeline checks the overlap first and says plainly when there isn't enough of it. That is a duller sentence than "whales don't move the market" or "whales do move the market," and it's the honest one.

MetricValue
BTC/USD (latest)$77,127
30-day price change+22.4%
Whale transactions (≥50 BTC), 150 blocks scanned2,177
Total whale volume, ~2-day window696,791 BTC
ESD-flagged price anomalies2
ESD-flagged active-address anomalies1
Annualized volatility44.1%

The anomaly detector, which doesn't need the same daily overlap the correlation test does, worked exactly as intended: two price days and one active-address day got flagged by the ESD test on this run, each one an actual statistical outlier against its own trailing average, not a fixed percentage-move threshold picked by hand.

Why statistics, not machine learning

A tempting version of this project trains a classifier on whale features to predict next-day price direction. I didn't build that one, for reasons that matter more than "it would take longer":

Not enough dataA few hundred daily points and a two-day whale window is nowhere near enough to train something that generalizes; it would fit noise and hand back a confident-looking, meaningless score.
Interpretability over fitAn ESD test and a Pearson correlation table are checkable line by line. A model's internal "whale influence score" would not be, and auditability is the actual point of this project.

What actually broke

The most concrete bug worth admitting: the first deployed version of the dashboard shipped with its charts pinned to Chart.js 4.4.4 loaded from cdnjs. That version simply isn't published at that path, cdnjs returns a 404 for it, so the script tag silently failed to load and every chart canvas rendered as an empty black box, dark background, no data, no error visible to a casual look. The fix was pinning to 4.4.1, an actual published build, and it's exactly the kind of failure that only shows up when you check the live page rather than trusting that "the code ran" means "the page works."

The stack, briefly

pandasJoining daily price and on-chain series, computing returns and rolling averages.
scipyThe Student's t critical values behind the generalized ESD test.
requestsCoinGecko, blockchain.info Charts, and blockchain.info rawblock, all keyless.
Chart.jsThe three interactive charts on the live dashboard (now correctly pinned to a version that exists).
pytest + ruffFast unit tests on synthetic series, no network required, plus linting in CI.
GitHub ActionsCI on push, and a sync job that publishes the static demo straight to this domain.

What it costs to run

Nothing. Every data source is a free, keyless public API, there's no server and no database, and the deployed page is a static file synced onto infrastructure that already runs everything else on this domain. The only real cost anywhere in this write-up was the AWS Bedrock call that generated the cover image above.

What's next

The single highest-value addition is a proper address-label database: a small schema for address, label, source, and confidence, seeded from public sources like mining-pool lists, so whale transactions can be split into "exchange inflow/outflow" versus "unknown wallet" instead of one undifferentiated bucket. That, plus a longer whale backfill from a local Bitcoin Core node instead of one HTTP call per block, is what would turn the correlation test from "not enough overlap to check" into an actual answer.

Try it

The live demo at forwardforecasting.eu/blockchain-analytics has the real price and on-chain charts, the whale-activity breakdown, the anomaly markers, and the correlation panel exactly as described here, including the honest "not enough data" line when that's what's true. The code, whale-detection logic, ESD implementation, and the Chart.js version bug included, is public.

See it live

Real price and on-chain data, a real scan of real blocks, and an answer that stays honest when the data doesn't support a headline.

Open the demo → View on GitHub →

About the cover image: the golden whale gliding along its own candlestick trail is a literal read on the project's actual question, whether a whale's movement traces the price chart's path or just happens to share the same space. ImageModelstability.stable-image-core-v1:1 · AWS Bedrock (us-west-2)Prompt“Editorial illustration, a golden whale silhouette breaching through a glowing candlestick price chart made of light, deep navy background, minimalist flat vector illustration style, clean geometric linework, no text, no logos”