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

  1. Set the venue book_type to L1_MBP in the SimulatedVenueConfig when using quotes/trades/bars
  2. Add order book data (OrderBookDelta/Depth) for every instrument with data on that venue
  3. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/3f88e4aa66c2373a. Report an issue: GitHub.