Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

trade-classification-bars

Lee-Ready tick-rule trade classification, validated against exchange ground truth, plus alternative bar sampling (time, tick, volume, dollar) on real Binance BTCUSDT data.

The idea in plain words

Every trade has two sides: someone buys, someone sells. But only one side is in a hurry, the one that crosses the spread to get the trade done right now. That side is the aggressor, and it is the side that actually moves the price.

Exchanges usually do not tell you who the aggressor was. The trick: if the price ticked up, the buyer was probably in a hurry (they bought at whatever price was offered). If it ticked down, the seller was. That is the whole rule, and it gets it right 97.6% of the time. We know because Binance secretly stamps the answer on every single trade, so we can check.

Second idea: how do you chop one day of trades into chunks (bars)? Like slicing a pizza: same pizza, different cuts. Cut by the clock: every minute gets a slice, even the quiet ones. Cut by money: every slice is the same dollar amount, so busy hours get more slices. The cut changes what the data looks like. Clock-cut returns look like a spiky hedgehog (kurtosis 8.37). Money-cut returns look almost like a bell curve. Models trained on one cut behave differently on the other, so choosing the cut is a modeling decision you make before any model exists.

Why

Market microstructure (Jansen, Machine Learning for Trading, ch03) says price data is not a neutral series: every trade is an economic event with an aggressor. Two skills matter before any ML on market data:

  1. Trade classification: knowing whether a trade was buyer- or seller-initiated, which you usually have to infer because venues rarely stamp the side.
  2. Sampling design: the bar type you choose changes the statistical properties of your training data (and therefore your features and labels).

Binance does stamp the aggressor side (is_buyer_maker), so this repo lets you implement the inference and check it against the truth.

What it does

  1. Downloads one day of BTCUSDT aggTrades from data.binance.vision (free, no API key).
  2. Classifies every trade with the tick rule: price up -> buy, price down -> sell, flat -> carry previous.
  3. Validates against Binance's own flag and prints accuracy + confusion matrix.
  4. Builds time, tick, volume and dollar bars, then compares return distributions (kurtosis, autocorrelation, skew).

How to run

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

# 1. fetch one day of data (~60-120 MB)
.venv/bin/python fetch_data.py --date 2026-08-10

# 2. classify + validate + compare bar types
.venv/bin/python analyze.py

# 3. regenerate the storytelling charts (charts/*.png, Plotly dark theme;
#    interactive charts/*.html are also written locally but not committed)
.venv/bin/python plots.py

Tunable: --tick-size, --volume-size (BTC), --dollar-size (USD), --time-size.

Results (2026-08-10, BTCUSDT)

530,873 aggTrades, full UTC day (00:00:00.012 -> 23:59:59.715).

Trade classification

Metric Value
Tick-rule accuracy vs exchange ground truth 97.62%
True sells classified correctly 235,560 / 239,798
True buys classified correctly 282,694 / 291,074

Errors concentrate at flat (zero-tick) prints and at large prints that cross several price levels; the tick rule can only see the last tick, not the quote book.

Bar return statistics (normal distribution -> kurtosis 0, autocorr 0)

Bar type Bars Std ret (bps) Skew Kurtosis Autocorr(1)
time (1 min) 1,440 3.49 -0.107 8.37 0.035
tick (1,000 trades) 531 5.81 0.042 -0.41 0.119
volume (100 BTC) 137 12.66 0.055 0.06 -0.223
dollar ($5M) 177 10.65 0.624 1.45 -0.123

Time bars have fat tails (kurtosis 8.4x normal). Sampling on activity (volume/dollar bars) flattens the distribution toward i.i.d. normal, which is why model features built on time bars behave differently from features built on dollar bars.

Reproduce: python fetch_data.py --date 2026-08-10 && python analyze.py

The story

1. A day in the life of BTCUSDT

Intraday traded volume by hour

530,873 prints in 24 hours. Volume is not uniform: it concentrates in the US/Europe overlap (13-17 UTC peak) and thins out in the late evening (21-22 UTC trough). A "minute" at 14:00 UTC and a "minute" at 22:00 UTC are different things.

2. The tick rule is nearly perfect, and its errors are informative

Tick-rule error rate by price change

97.62% overall accuracy. The error rate by price move size is U-shaped: 0.11% for exactly 1-tick moves (direction is obvious), rising to 5.69% at flat prints (the rule must guess by carry-forward) and 7.11% for prints >100 ticks (big sweeps where one aggregate can bundle opposite-side fills).

3. Sampling changes the distribution of your data

Return distributions by bar type

Kurtosis and autocorrelation by bar type

Time bars have fat tails (excess kurtosis 8.37, about 8x a normal distribution). Activity-based bars approach normal: volume 0.06, dollar 1.45. Models that assume i.i.d. samples see very different data depending on the bar type you hand them.

4. Sampling is a design choice, visible in real time

Bars completed per hour

Time bars mint exactly 60/hour, always. Dollar bars mint when money moves: bursts during active hours, almost nothing in dead ones. Same day, two datasets with different information content per row.

Key findings

  • The tick rule recovers the aggressor side at 97.62% against the exchange's own flag; errors concentrate at flat prints and >100-tick sweeps (story 2).
  • Bar type is a modeling decision, not bookkeeping: kurtosis drops from 8.37 (time) to 0.06 (volume) and 1.45 (dollar) (story 3).
  • Dollar bars concentrate information in active hours, so each row carries a more comparable amount of information (story 4). Features and labels inherit whatever the sampling scheme produces.

License

MIT

About

Lee-Ready tick-rule trade classification validated against Binance ground truth + time/tick/volume/dollar bar sampling

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages