Information Bars, Part 3: When Smart Math Meets Real Markets
In Part 2, I walked through the mechanics of imbalance and run bars. Clean, elegant, self-tuning. And then I mentioned that when I ran them on real data, TIB produced 1.5 bars per day instead of 50.
This post is about figuring out why.
Step 1: Proving the Code Right
Before guessing at causes, I built 68 mathematical proof tests. Not unit tests in the usual sense. These work like formal proofs. Each one:
- Sets up a specific sequence of trades by hand
- Works out on paper exactly what should happen
- Verifies that Arcana’s code matches exactly
For example: “Feed 5 consecutive buy trades into a TIB builder with threshold=5. The running total goes +1, +2, +3, +4, +5. At trade 5, |5| >= 5, so a bar should emit containing exactly 5 trades.”
I tested everything:
- Does the EWMA formula compute correctly?
- Does the threshold update at the right moment?
- Does the tick rule classify buys and sells properly?
- Does VIB produce identical results to TIB when every trade is exactly 1 ETH? (It should.)
- Does metadata survive a program restart?
Result: the code is mathematically perfect. Every calculation matches Prado’s textbook formulas exactly. All 68 proofs pass.
So the code isn’t wrong. The problem is deeper.
Step 2: The Coin Flip Problem
I need to take a detour into probability here, because this is the critical insight that explains everything.
Imagine flipping a fair coin. Heads = +1, Tails = -1. You keep a running total. How many flips until your total reaches 10?
Your gut says about 10. Maybe 15 or 20 if you’re being conservative.
The real answer: roughly 100.
A fair coin keeps canceling itself out. The +1s and -1s fight each other, and progress toward 10 is a slow, drunken stumble. One step forward, one step back, one forward, two back, three forward…
The math: to reach a distance of h, a fair random walk takes roughly h-squared steps. Not h. h-squared. This is called the quadratic scaling of random walks, and it’s one of those results that doesn’t click until you’ve really sat with it.
Why This Kills Info Bars
Connect this back to the imbalance bars. The adaptive threshold is set based on how many trades recent bars have taken. In a balanced market, a vicious cycle forms:
- The system expects bars to take ~100 trades (E[T] = 100)
- The threshold is computed as E[T] times |E[b]|. In a balanced market, |E[b]| is around 0.1, so threshold is around 10
- In a balanced market (fair coin), reaching threshold 10 takes 10-squared = 100 trades
- The system sees “oh, the bar took 100 trades, that matches my expectation”
- Equilibrium. But it’s unstable.
The Spiral
Imagine a small random bump pushes E[T] to 101:
- Threshold becomes slightly higher (~10.1)
- Fair random walk to 10.1 takes 10.1-squared, roughly 102 trades
- The system updates: “bars are taking 102 trades now”
- E[T] drifts to 102, threshold goes up, the next bar takes even longer…
- Runaway explosion. E[T] grows without bound. Bars stop being produced.
Or imagine E[T] dips to 99:
- Threshold becomes slightly lower (~9.9)
- Fair random walk to 9.9 takes 9.9-squared, roughly 98 trades
- The system updates: “bars are taking fewer trades”
- E[T] drifts to 98, threshold drops, bars get even shorter…
- Collapse. E[T] crashes to 1. Every single trade becomes its own bar. Useless.
E[T] = 100 is like a ball balanced on top of a hill. Any nudge, and in a stochastic system nudges are constant, sends it rolling off one side or the other.
The Production Problem
Arcana’s auto-calibration seeded E[T] at approximately 9,240. Way above the equilibrium point. So it was on the “explosion” side from the start. The threshold kept growing, bars got rarer and rarer, and TIB ended up at 1.5 bars per day. VIB did slightly better at 6.8 because volume weighting partially breaks the symmetry, but the same dynamic was at play across all six types.
This isn’t a bug. It’s a property of the algorithm when applied to markets that are roughly balanced between buyers and sellers. For a liquid pair like ETH-USD on Coinbase, that’s most of the time.
The Good News
Understanding the problem is most of the work. Once you know why E[T] is unstable, the fix is almost obvious: don’t let it drift past guardrails.
That’s exactly what I did. And it’s exactly what the most popular open-source implementation of Prado’s work already does. They just don’t explain why.