nautechsystems/nautilus_trader · error · anyhow::Error

Spot ticker requires a BINANCE instrument

Error message

Spot ticker requires a BINANCE instrument

What it means

For a BinanceSpotTicker custom data subscription, the DataType metadata must include an instrument_id whose venue equals the data client's venue (BINANCE for Spot). Any other venue in the metadata (a typo, another exchange, or a synthetic venue) is rejected by this check.

Source

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

    fn is_disconnected(&self) -> bool {
        !self.is_connected()
    }

    fn subscribe(&mut self, cmd: SubscribeCustomData) -> anyhow::Result<()> {
        if cmd.data_type.type_name() != "BinanceSpotTicker" {
            log::warn!(
                "Unsupported custom data subscription: {}",
                cmd.data_type.type_name()
            );
            return Ok(());
        }
        anyhow::ensure!(
            self.spot_market_data_mode == BinanceSpotMarketDataMode::Json,
            "Binance Spot 24-hour ticker custom data requires JSON market-data mode"
        );
        let instrument_id = Self::required_instrument_id_metadata(&cmd.data_type)?;
        anyhow::ensure!(
            instrument_id.venue == self.venue(),
            "Spot ticker requires a BINANCE instrument"
        );
        let should_subscribe = {
            let previous = self
                .ticker_refs
                .load()
                .get(&instrument_id)
                .copied()
                .unwrap_or(0);
            self.ticker_refs
                .rcu(|refs| *refs.entry(instrument_id).or_insert(0) += 1);
            previous == 0
        };

        if should_subscribe {
            let ws = self.ws_client.clone();
            let stream = format!("{}@ticker", instrument_id.symbol.as_str().to_lowercase());

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Set the DataType metadata instrument_id to a BINANCE-venue instrument, e.g. 'BTCUSDT.BINANCE'
  2. If routing between venues, verify the venue suffix is derived from the target adapter before constructing the custom data type

Example fix

# before
data_type = DataType(
    name="BinanceSpotTicker",
    metadata={"instrument_id": "BTCUSDT.BYBIT"},  # wrong venue
)

# after
from nautilus_trader.model.identifiers import InstrumentId
data_type = DataType(
    name="BinanceSpotTicker",
    metadata={"instrument_id": str(InstrumentId.from_str("BTCUSDT.BINANCE"))},
)
Defensive patterns

Strategy: type-guard

Validate before calling

from nautilus_trader.model.identifiers import InstrumentId

def is_binance_instrument(instrument_id: str) -> bool:
    return InstrumentId.from_str(instrument_id).venue == "BINANCE"

Type guard

def is_binance_instrument(instrument_id: str) -> bool:
    from nautilus_trader.model.identifiers import InstrumentId
    try:
        return InstrumentId.from_str(instrument_id).venue == "BINANCE"
    except ValueError:
        return False

Prevention

When it happens

Trigger: Subscribing to BinanceSpotTicker custom data whose instrument_id metadata reads e.g. 'BTCUSDT.BYBIT' or 'BTCUSDT.BINANCE_SPOT' instead of a BINANCE-venue instrument ID.

Common situations: Copy-pasting subscription setup from another adapter; constructing the DataType metadata manually with a wrong venue string; multi-venue routing code applying the wrong venue suffix.

Related errors


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