Order-book imbalance looks simple.
Count the bids.
Count the asks.
Compare them.
If bids are much larger than asks, the market looks bullish.
If asks are much larger than bids, the market looks bearish.
But building a Polymarket bot around that assumption can be a serious mistake.
A large imbalance does not automatically mean the price will move.
Orders can disappear.
New liquidity can arrive.
Trades can consume one side of the book.
The spread can change.
And the imbalance that looked strong 200 milliseconds ago may no longer exist.
The real question is:
How can a Polymarket bot determine whether order-book imbalance represents meaningful market pressure or temporary noise?
That is where the engineering becomes interesting.
What Is Order-Book Imbalance?
For a simple order book, define:
Bid Volume = total size on the bid side
Ask Volume = total size on the ask side
A basic imbalance formula is:
Imbalance =
(Bid Volume - Ask Volume)
/
(Bid Volume + Ask Volume)
The result is between:
-1 and +1
For example:
Bid Volume = 800
Ask Volume = 200
Then:
(800 - 200) / (800 + 200)
= 600 / 1000
= 0.60
The result is:
+0.60
That means the displayed bid-side liquidity is significantly larger than the ask-side liquidity.
But this is only a snapshot.
It is not a trading decision.
Why a Single Imbalance Snapshot Is Dangerous
Imagine your Polymarket bot sees:
Imbalance = +0.70
The bot buys immediately.
Then:
100 ms later → +0.35
200 ms later → +0.10
300 ms later → -0.05
The original imbalance disappeared.
What happened?
Possibilities include:
• Large bids were cancelled
• New asks appeared
• Trades consumed the bids
• Price moved
• Liquidity migrated to another level
The bot wasn't necessarily wrong about the data.
The problem was treating a temporary observation as a persistent signal.
Persistence Matters
This is one of the first improvements I would make to a Polymarket bot.
Instead of asking:
What is the current imbalance?
Ask:
How long has the imbalance remained meaningful?
For example:
t0 → +0.68
t1 → +0.71
t2 → +0.69
t3 → +0.73
t4 → +0.66
This is more interesting than:
t0 → +0.70
t1 → +0.12
t2 → -0.10
Both examples contain:
+0.70
But they describe very different market conditions.
A Better Imbalance Signal
Instead of:
IF imbalance > threshold
BUY
I prefer thinking in terms of:
Imbalance
+
Persistence
+
Price Movement
+
Trade Flow
+
Liquidity
+
Spread
Then the bot can decide whether the imbalance is strong enough to influence execution.
Which Levels Should You Measure?
Another important question is:
How much of the order book should be included?
Suppose the book is:
Bid
0.48 → 100
0.47 → 200
0.46 → 300
0.45 → 800
0.44 → 1500
and:
Ask
0.52 → 100
0.53 → 150
0.54 → 200
0.55 → 300
0.56 → 400
If you include every level, the distant 0.45 bid can dominate your calculation.
But that liquidity may have very little relevance to the immediate execution price.
So the bot needs to define an observation window.
For example:
Top 1 level
Top 3 levels
Top 5 levels
Price-distance window
Depth within X ticks
There isn't one universally correct choice.
It depends on the strategy and market.
Top-of-Book Imbalance
The simplest approach is to compare only the best bid and best ask sizes.
For example:
Best Bid Size = 500
Best Ask Size = 100
Then:
Imbalance = (500 - 100) / (500 + 100)
= 0.667
This is fast.
But it can also be fragile.
A single large order can make the imbalance look extreme.
If that order disappears, the signal disappears with it.
Multi-Level Imbalance
A more stable approach is to use several levels.
For example:
Bid:
0.50 → 200
0.49 → 150
0.48 → 100
Total = 450
and:
Ask:
0.51 → 100
0.52 → 100
0.53 → 100
Total = 300
Then:
Imbalance =
(450 - 300) / (450 + 300)
= 0.20
This gives a different picture from looking only at the best level.
The important engineering decision is to make the depth window configurable.
Weighting Distance From the Mid Price
Not all liquidity should necessarily have equal weight.
Liquidity close to the current market may matter more than liquidity far away.
So you can introduce weights.
Conceptually:
Weighted Imbalance =
Weighted Bid Depth
-
Weighted Ask Depth
where levels closer to the midpoint receive greater weight.
For example:
Level 1 → weight 1.00
Level 2 → weight 0.75
Level 3 → weight 0.50
Level 4 → weight 0.25
The exact weighting function is something I would test rather than hard-code permanently.
Imbalance vs Price Movement
This is where the signal becomes much more useful.
Suppose:
Imbalance = +0.65
but:
Price = unchanged
That is different from:
Imbalance = +0.65
Price = rising
And different again from:
Imbalance = +0.65
Price = falling
The same imbalance can have different meanings depending on what price is doing.
So a Polymarket bot should not necessarily interpret:
Imbalance = +0.65
in isolation.
Add Trade Flow
Displayed liquidity is not the same thing as executed liquidity.
This is an important distinction.
The order book tells you what traders are currently displaying.
Trades tell you what actually happened.
Imagine:
Bid imbalance = +0.60
but recent trades are repeatedly hitting the bids.
That could indicate that the displayed bid liquidity is being consumed.
Now consider:
Bid imbalance = +0.60
while aggressive buying is repeatedly lifting the asks.
That is a very different situation.
So I would track:
• Order-book imbalance
• Recent trade direction
• Trade volume
• Price movement
• Liquidity changes
Liquidity Appearance vs Liquidity Consumption
This distinction is extremely important.
Suppose a large bid appears:
BUY 1,000
The bot might interpret this as strong support.
But if the order disappears before any meaningful trading occurs, it may have provided little real support.
On the other hand:
BUY 1,000
appears and:
300 traded
400 traded
200 traded
Now the displayed liquidity has actually participated in execution.
This is why I would track both:
Displayed Liquidity
and:
Consumed Liquidity
The Imbalance Can Move Before Price
A useful feature for a Polymarket bot is to monitor the sequence of events.
For example:
1. Bid depth increases
2. Imbalance becomes positive
3. Ask depth decreases
4. Trades begin lifting the ask
5. Mid price moves
This sequence can be more informative than simply observing:
Imbalance = +0.70
The order of events matters.
That means the bot should store short-term market history rather than only the latest book snapshot.
Use a Rolling Window
For example, maintain:
last 100 ms
last 250 ms
last 500 ms
last 1 second
Then calculate:
Current Imbalance
Average Imbalance
Maximum Imbalance
Minimum Imbalance
Imbalance Duration
Imbalance Change
Now the strategy can distinguish:
Strong + persistent
from:
Strong + temporary
Imbalance Velocity
Another useful feature is how quickly imbalance changes.
For example:
t0 = 0.10
t1 = 0.30
t2 = 0.50
t3 = 0.70
The imbalance is increasing rapidly.
Compare that with:
t0 = 0.70
t1 = 0.69
t2 = 0.68
t3 = 0.67
The second case still has positive imbalance.
But the pressure is weakening.
So instead of only calculating:
imbalance
calculate:
imbalance_change
and potentially:
imbalance_velocity
Don't Let Imbalance Override the Strategy
This is one of the most important rules.
I would not build:
IF imbalance > 0.5
BUY
as the complete strategy.
Instead:
Strategy Signal
+
Order-Book Imbalance
+
Trade Flow
+
Price Movement
+
Liquidity
+
Risk
should influence the final decision.
Imbalance should often be a feature.
Not the entire strategy.
Example: Two Different Markets
Consider Market A:
Imbalance = +0.70
Persistence = 50 ms
Price = falling
Trade flow = selling
Spread = widening
That doesn't look like a strong long setup.
Now Market B:
Imbalance = +0.65
Persistence = 800 ms
Price = rising
Trade flow = buying
Spread = stable
Liquidity = increasing
That is a much more interesting condition.
The numerical imbalance is similar.
The market context is completely different.
Imbalance and Execution
This is where the feature becomes useful for a Polymarket bot.
Suppose the strategy already wants to buy.
The execution engine sees:
Strong positive imbalance
+
Positive trade flow
+
Stable spread
It may decide that waiting for a lower passive price has a higher opportunity cost.
The bot could therefore become more aggressive.
Now consider:
Weakening imbalance
+
Negative trade flow
+
Widening spread
The execution engine may reduce size or wait.
This creates a better relationship between:
Signal
and:
Execution Policy.
Imbalance Can Also Tell the Bot When Not to Trade
This is often overlooked.
A good trading feature doesn't only answer:
"BUY?"
It can also answer:
"WAIT."
For example:
Strategy = BUY
Imbalance = unstable
Spread = widening
Liquidity = falling
Trade flow = conflicting
The best decision may be:
WAIT
The bot doesn't need to trade every time the strategy detects a theoretical opportunity.
A Practical Imbalance Score
You could create a composite score such as:
Score =
w1 × Imbalance
+
w2 × Persistence
+
w3 × TradeFlow
+
w4 × PriceMomentum
+
w5 × LiquidityChange
-
w6 × Spread
The weights should be determined through testing.
The important part is that the model combines multiple pieces of market information.
Then:
Score > Entry Threshold
could permit execution.
While:
Score < Entry Threshold
could result in:
WAIT
Avoid Hard-Coded Thresholds
A common mistake is:
imbalance > 0.50
forever.
Different markets can behave differently.
Liquidity can vary.
Time-to-resolution can vary.
Spread can vary.
Market participants can vary.
So thresholds should ideally be configurable and tested against historical data.
For example:
imbalanceThreshold
minimumPersistence
maxSpread
minimumDepth
minimumTradeVolume
maxSignalAge
These should be strategy parameters, not hidden constants throughout the codebase.
Signal Freshness Matters
Even a strong imbalance can become stale.
A simplified execution flow is:
ORDER BOOK UPDATE
↓
FEATURE CALCULATION
↓
SIGNAL
↓
VALIDATION
↓
EXECUTION
If the bot waits too long between those stages, the market state may have changed.
So I would associate each signal with:
signalTimestamp
bookTimestamp
and calculate:
signalAge
If:
signalAge > maximumAllowedAge
the bot should invalidate the signal and recalculate.
A Better Architecture
For a production-style Polymarket bot, I would separate the components:
Market Data
↓
Order Book
↓
Feature Engine
↓
Imbalance Calculator
↓
Signal Engine
↓
Risk Engine
↓
Execution Engine
↓
Order Manager
↓
Position Manager
The imbalance calculator shouldn't place orders.
The strategy shouldn't directly manipulate balances.
The execution engine shouldn't decide the market direction.
Each component should have a clear responsibility.
What I Would Log
When the bot trades because of an imbalance-related signal, I want to know exactly why.
For example:
SIGNAL
imbalance = 0.64
imbalance_duration = 620ms
trade_flow = +0.72
price_change = +0.004
spread = 0.01
depth = 840
signal_age = 18ms
DECISION
signal = BUY
confidence = HIGH
order_size = 100
EXECUTION
order_type = LIMIT
price = 0.54
filled = 82
remaining = 18
This makes the strategy testable.
Without this information, you may only see:
BUY
SELL
P&L
and have no idea why the bot made its decisions.
Backtesting the Feature
Before trusting order-book imbalance with real capital, I would test:
• Different depth windows
• Different imbalance thresholds
• Different persistence requirements
• Different market conditions
• Different time-to-resolution ranges
• Different liquidity levels
• Different spreads
• Different execution delays
The important metric isn't simply:
"Did price go up after positive imbalance?"
You also need to ask:
"Could the bot actually execute the trade at the assumed price?"
The Difference Between Prediction and Execution
This is the key lesson.
Suppose positive imbalance predicts that price will move higher.
That doesn't automatically mean the bot can profit from it.
The bot still needs:
Prediction
+
Entry Price
+
Execution Probability
+
Slippage
+
Position Size
+
Exit
+
Risk
A feature can be statistically useful and still be economically useless after execution costs.
The Rule I Would Use
I wouldn't build a Polymarket bot around:
Imbalance → Buy
I would build:
Imbalance
+
Persistence
+
Trade Flow
+
Price
+
Liquidity
+
Spread
+
Strategy
+
Risk
↓
Execution Decision
That's a much more robust way to think about order-book imbalance.
Final Thoughts
Order-book imbalance is one of those features that looks extremely simple at first.
Calculate bid volume.
Calculate ask volume.
Compare them.
Done.
But real markets aren't static.
Liquidity changes.
Orders disappear.
Trades consume liquidity.
Prices move.
Spreads change.
Signals become stale.
That's why the useful question isn't:
"Is there an imbalance?"
The better question is:
"Is the imbalance persistent, meaningful, tradable, and consistent with the rest of the market state?"
That is the difference between adding an indicator to a bot and actually engineering an execution system.
What's Next?
I'm continuing this practical Polymarket bot engineering series.
The next problem I want to explore is:
Limit Orders vs Marketable Orders in a Polymarket Bot
When should the bot provide liquidity?
When should it take liquidity?
How much does execution probability matter?
And when is getting filled more important than getting the perfect price?
Source Code
I publish practical Polymarket bot development and experiments on GitHub.
My Polymarket TWAP trading bot:
https://github.com/ruudkoeyvoets/polymarket-trading-bot-twap
Follow the Development
I also share Polymarket bot development, execution experiments, and technical research on YouTube:
https://www.youtube.com/@std0d
This article is for educational and software-development purposes only and is not financial advice. Automated trading involves substantial risk. No strategy, bot, or execution technique guarantees profit.
Top comments (0)