nautechsystems/nautilus_trader · error · anyhow::Error

Binance Spot supports L1_MBP and L2_MBP order book subscript

Error message

Binance Spot supports L1_MBP and L2_MBP order book subscriptions

What it means

Binance Spot order book subscriptions accept only L1_MBP (top of book) and L2_MBP (aggregated depth); the venue exposes no L3/order-by-order data on these streams, so any other BookType (typically L3_MBP) is rejected immediately.

Source

Thrown at crates/adapters/binance/src/spot/data.rs:1832

    fn subscribe_book_deltas(&mut self, cmd: SubscribeBookDeltas) -> anyhow::Result<()> {
        if cmd.book_type == BookType::L1_MBP {
            anyhow::ensure!(
                cmd.depth.is_none_or(|depth| depth.get() == 1),
                "Binance Spot L1_MBP supports depth 1 only"
            );
            anyhow::ensure!(
                !self.book_subscriptions.contains_key(&cmd.instrument_id),
                "cannot subscribe L1_MBP and L2_MBP for the same Binance Spot instrument"
            );
            self.l1_book_subscriptions.rcu(|subscriptions| {
                *subscriptions.entry(cmd.instrument_id).or_insert(0) += 1;
            });
            self.subscribe_top_of_book(cmd.instrument_id);
            return Ok(());
        }

        if cmd.book_type != BookType::L2_MBP {
            anyhow::bail!("Binance Spot supports L1_MBP and L2_MBP order book subscriptions");
        }
        anyhow::ensure!(
            !self.l1_book_subscriptions.contains_key(&cmd.instrument_id),
            "cannot subscribe L1_MBP and L2_MBP for the same Binance Spot instrument"
        );

        let instrument_id = cmd.instrument_id;
        let ws = self.ws_client.clone();
        let symbol_lower = instrument_id.symbol.as_str().to_lowercase();

        if self.spot_market_data_mode == BinanceSpotMarketDataMode::Json && cmd.depth.is_some() {
            // Explicit depth requests use partial-book streams. Full-depth JSON
            // subscriptions fall through to the REST snapshot + @depth diff path.
            let depth_level = match cmd.depth.map(|d| d.get()) {
                Some(1..=5) => 5,
                Some(6..=10) => 10,
                _ => 20,
            };

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Request L2_MBP for aggregated depth or L1_MBP for top of book on Binance Spot
  2. If order-by-order data is a hard requirement, use a venue/adapter that provides L3 data

Example fix

# before
client.subscribe_book_deltas(
    instrument_id,
    BookType.L3_MBP,  # errors: not offered on Binance Spot
    depth=None,
)

# after
client.subscribe_book_deltas(
    instrument_id,
    BookType.L2_MBP,
    depth=None,
)
Defensive patterns

Strategy: type-guard

Type guard

from nautilus_trader.model.data import BookType

def is_supported_binance_spot_book_type(book_type) -> bool:
    return book_type in (BookType.L1_MBP, BookType.L2_MBP)

Prevention

When it happens

Trigger: subscribe_book_deltas with book_type set to L3_MBP (or any type other than L1_MBP/L2_MBP) on a Binance Spot instrument.

Common situations: Porting a strategy from a venue that provides L3 (e.g. some crypto exchanges or FX feeds) without adjusting the book type; generic book-subscription presets that default to L3.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/f98c5b6cb57bc4e1. Report an issue: GitHub.