Skip to content
Barry Zhang, home
All work
Personal project · 2026

Predicting six-hour Bitcoin moves: a negative result

The point of this project is the pipeline discipline (pinned data, purged time-ordered splits, a frozen threshold and honest uncertainty) rather than a profitable signal.

Role
Sole author
Context
Can a blending ensemble predict tradeable six-hour BTCUSDT moves?
Stack
Pythonscikit-learnpandasNumPypytestJupyter
balanced accuracy on the locked test; the bootstrap interval includes 0.5
0.514
strategy return after costs, against −28.1% for buy-and-hold
−36.7%
six-hour candles collected and cross-checked against 79 monthly archives
9,613
candidate features screened
159
Locked test
Balanced accuracy, model by model
L2 logistic regression0.510
Random forest0.510
Gaussian naive Bayes0.524
Simple average0.512
Blended ensemble0.514

January to July 2026, 846 six-hour bars. The vertical line is chance (0.50). The band is the 95% moving-block bootstrap interval for the blend, 0.483 to 0.543, and it includes chance.

01

The question

Can a blending ensemble of three base classifiers (L2 logistic regression, random forest and Gaussian naive Bayes, combined by a regularized logistic meta-learner) predict six-hour BTCUSDT moves large enough to clear a 0.1% one-way transaction cost?

02

The answer

No. On a locked January to July 2026 test of 846 bars, balanced accuracy was 0.514, ROC-AUC 0.519 and the Brier score 0.251. The moving-block bootstrap interval for balanced accuracy spans 0.5.

The blend did not beat its best base model out of sample: Gaussian naive Bayes alone scored 0.524 on the test window, which I read as model-selection noise rather than skill. A costed long/cash backtest returned −36.7% over the test window against −28.1% for buy-and-hold, across 289 position changes. The label is predictable slightly above chance in cross-validation, but not exploitable after costs in this window.

03

Why it is worth showing

The value is the discipline around the result.

  • I collected the data myself from the Binance.US API (1 January 2020 to 31 July 2026) and cross-checked it against 79 monthly archives with published checksums. 11 cells differed between the two sources; they are disclosed, not averaged away.
  • Every source file is hash-pinned. The notebook refuses to run if the data changes.
  • Splits are time-ordered and purged at the boundaries, and the decision threshold was frozen on validation data before the locked test.
  • A fixed seed makes the run deterministic, and the last cell re-asserts every headline number and fails if anything drifts.
  • A pytest suite covers the backtest, the models, the evaluation code and source-data integrity.