MBO, MBP and BBO: order book data, level by level
Market data comes in levels, and every vendor names them differently: L1, L2 and L3, BBO, MBP and MBO, top of book, depth of market, market by order. The content behind the names is the same. This page says what each level holds, which kind of backtest needs which, and why only one of them tells you where an order stands in its queue.
The levels, side by side
| Level | Also called | What it holds | What a backtest gets | Manifold-BT |
|---|---|---|---|---|
| Trades | Tape, time and sales, tick by tick | Every print: price, size, time, and which side was the aggressor | Fills in the order prices printed; order flow | ingest_trades |
| L1 | BBO, top of book (NBBO when consolidated across US venues) | The best bid and the best ask, with their sizes | The spread a fill really paid | attach_quotes |
| L2 | MBP, market by price, depth of market (MBP-10: ten levels) | The total size resting at each price, a number of levels deep | Depth and imbalance signals; a queue estimated from the displayed size | ingest_book |
| L3 | MBO, market by order (Nasdaq TotalView-ITCH) | Every order: when it entered, each execution, cancellation and replacement | The exact place of an order in its queue | ingest_mbo |
The difference is easiest to see on one real instant. This is the BTCUSDT perpetual book on Bybit, rebuilt from the free archive, as an L1 feed sends it and as L2 shows it:
Two prices and two sizes. The spread is one tick, 0.1 USDT.
Which level does a backtest need?
It depends on what the strategy does with the market, not on how fast it trades. A strategy that reads closes and holds for hours needs bars, and nothing on this page. One that crosses the spread many times a day needs L1, because a backtest that fills at the close rather than at the bid or the ask hides the cost that decides whether it pays.
A strategy that reads the book, the size waiting on each side or how it leans over the top five levels, needs L2: in Manifold-BT that is bt.book.imbalance(5) or bt.book.bid_size(3) in the same expression language as any other signal.
A strategy that rests passive orders, a market maker or a limit entry, needs the queue. A resting order is filled because everything ahead of it at its price went first, not because the price touched it. L2 lets a backtest estimate that queue; L3 lets it read it.
Why L2 can only estimate a queue
A level-2 book shows each level's total size. When the size at your price drops from ten to eight, the book does not say whether the two left ahead of you, which moves you up, or behind you, which does not. So on L2 Manifold-BT places a new order behind the whole depth shown at its level when it is posted, lets prints at that price work through it, and takes a rate of cancellations ahead as a declared assumption. When the book shows nothing at that level, the queue is unknown: the run uses a declared fallback or refuses by name, and never reads it as empty, which would put the order at the front of a queue nobody saw.
risk_adverse, puts every unseen cancellation behind you, while power and log split it by a probability that depends on where you stand. On L3 the feed names the order.On L3 the guess goes away. Every order has an identifier, so an execution or a cancellation of an order ahead takes its size out of the volume ahead, and an execution of an order behind yours means the market went through your place and yours was filled.
A maker that reads its place in the queue
The strategy below joins the best bid and ask with a round lot each and stands aside on a side where more than 20,000 shares wait ahead of it. On a day stored order by order, queue_ahead is that size exactly. The full run, on the Nasdaq sample day of 9 December 2025, is example 32 in the repository.
import manifoldbt as bt
from manifoldbt import book
# A day of Nasdaq TotalView-ITCH 5.0, stored order by order (L3)
store = bt.ingest_mbo("S120925-v50.txt.gz", {"AAPL": 1}, "2025-12-09")
# Join the best bid and ask, but stand aside behind a crowded queue.
# On this market, queue_ahead is the size ahead of the quote exactly.
inventory = bt.position()
book_ok = (book.bid_levels() > 0) & (book.ask_levels() > 0)
crowded_bid = bt.queue_ahead("bid") > 20_000
crowded_ask = bt.queue_ahead("ask") > 20_000
strategy = (
bt.Strategy.create("queue_aware_maker")
.quote("buy", bt.when(book_ok, book.bid_price_at(1)), 100, tif="GTX",
enabled=(inventory < 500) & ~crowded_bid)
.quote("sell", bt.when(book_ok, book.ask_price_at(1)), 100, tif="GTX",
enabled=(inventory > -500) & ~crowded_ask)
)Reading the tape, the book and order-by-order days into the engine is part of the Researcher plan.
Where each level comes from
For crypto, trades and L2 are free: Bybit publishes its book by price level, up to 500 levels deep, and its trades, one file per day, and Binance publishes its spot trades. L1 can be read off that same book, so it costs nothing more. The archives, their sizes and how far back they go are listed in free crypto tick data.
The free crypto archives stop at L2: none of them is order by order. For L3, Nasdaq publishes TotalView-ITCH 5.0 sample days, a whole session of every order on its book, which is what the example above reads; Databento sells MBO and MBP-10 for CME futures and US equities.
Frequently asked questions
What is the difference between MBO and MBP data?
MBP, market by price, gives the total size resting at each price level. MBO, market by order, gives every order separately, with an identifier, so you can follow one order from the moment it enters the book to its execution or cancellation. MBP tells you how much is waiting at a price; MBO tells you who is waiting, and in what order.
Is L2 data enough to backtest a market maker?
It is enough to estimate the queue, not to read it. A level-2 book shows a level shrinking, never whose order left: when the size at your price drops, it may be a fill ahead of you or a cancellation behind you. A backtest on L2 has to assume how much of the queue cancels. On L3 data the place of each order is in the data.
Where can I get L3 order book data?
Nasdaq publishes TotalView-ITCH 5.0 sample days, a full day of every order on its book: the file Manifold-BT's order-by-order example runs on is 7.9 GB for one session. Databento sells MBO for CME and US equities. The free crypto archives are not order by order: Bybit publishes its book by price level, which is L2.
What is BBO data?
The best bid and offer: the highest price someone will buy at, the lowest price someone will sell at, and the size at each. It is level 1. In the US, the NBBO is the national best bid and offer consolidated across exchanges. For a backtest, the BBO is what tells you the spread a fill paid instead of assuming one.
Keep reading
- The Researcher plan: the tape, the book, the trade clock →
- Execution Realism →
- Market making strategy in Python →
- Manifold-BT vs hftbacktest →
- Read the documentation →
- Best Python backtesting libraries, compared →
- How to backtest a trading strategy →
- What is backtesting? →
- Algorithmic trading in Python →
- Walk-forward optimization in Python →
Run your first backtest
Install Manifold-BT and reproduce the backtest above in seconds. The Rust core runs years of bars sub-second so you can sweep parameters instead of waiting.