nautechsystems/nautilus_trader · error
No order book data found for instrument '{instrument_id}' wh
Error message
No order book data found for instrument '{instrument_id}' when `book_type` is '{:?}'. Set the venue `book_type` to 'L1_MBP' (for top-of-book data like quotes, trades, and bars) or provide order book data for this instrument. What it means
Venues configured with an L2/L3 MBP book_type need actual order book data to process deltas; if an instrument has other data (quotes/trades/bars) but no book data, the engine bails at run start because the configured book type cannot be maintained.
Source
Thrown at crates/backtest/src/engine.rs:749
self.sorted,
"Data has been added but not sorted, call `engine.sort_data()` or use \
`engine.add_data(..., sort=true)` before running"
);
for exchange in self.venues.values() {
let exchange = exchange.borrow();
let book_type_has_depth = exchange.book_type() as u8 > BookType::L1_MBP as u8;
if !book_type_has_depth {
continue;
}
for instrument_id in exchange.instrument_ids() {
let has_data = self.has_data.contains(instrument_id);
let missing_book_data = !self.has_book_data.contains(instrument_id)
&& !self.has_book_processed.contains(instrument_id);
if has_data && missing_book_data {
anyhow::bail!(
"No order book data found for instrument '{instrument_id}' when `book_type` \
is '{:?}'. Set the venue `book_type` to 'L1_MBP' (for top-of-book data \
like quotes, trades, and bars) or provide order book data for this \
instrument.",
exchange.book_type()
);
}
}
}
// Determine time boundaries
let start_ns = start.unwrap_or_else(|| self.ts_first.unwrap_or_default());
let end_ns = end.unwrap_or_else(|| self.ts_last_data.unwrap_or(start_ns));
anyhow::ensure!(start_ns <= end_ns, "start was > end");
self.end_ns = end_ns;
self.last_ns = start_ns;
self.last_module_ns = None;
View on GitHub (pinned to 18893faf8b)
Solutions
- Set the venue book_type to L1_MBP in the SimulatedVenueConfig when using quotes/trades/bars
- Add order book data (OrderBookDelta/Depth) for every instrument with data on that venue
- Verify the book data's instrument_id matches the exchange instrument_ids
Example fix
// before config.book_type = BookType::L2_MBP; // after config.book_type = BookType::L1_MBP; // top-of-book from quotes/trades/bars
Defensive patterns
Strategy: validation
Validate before calling
for instrument_id in book_instrument_ids {
anyhow::ensure!(
has_book_data(&engine, instrument_id) || venue_config.book_type == BookType::L1_MBP,
"instrument {instrument_id} lacks book data for {:?}", venue_config.book_type
);
} Try / catch
match engine.run(...) {
Err(e) if e.to_string().contains("No order book data found") => {
eprintln!("switch venue book_type to L1_MBP or add book data: {e}");
}
other => other?,
} Prevention
- Match book_type to the data you actually have (L1 for quotes/trades/bars)
- Ensure every instrument added to an L2/L3 venue has order book data
- Verify instrument_id consistency between book data files and venue instruments
When it happens
Trigger: add_venue with book_type L2_MBP (or L3) while only quotes/trades/bars were added for that instrument; book data never added via add_data; book data added but not registered under the instrument id.
Common situations: Reusing a venue config written for order-book data with a quote/trade dataset; forgetting to add the L1/L2 data files; instrument id mismatch so book data isn't attributed.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- At least one run config is required
- Invalid starting balance: {e}
- Only one run config per BacktestNode is supported (kernel Me
- Duplicate run config ID '{}'
- Data config start_time ({start}) must be <= end_time ({end})
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3f88e4aa66c2373a.
Report an issue: GitHub.