nautechsystems/nautilus_trader · warning · anyhow::Error

Symbol '{}' is not trading (status: {:?})

Error message

Symbol '{}' is not trading (status: {:?})

What it means

parse_usdm_instrument_with_fees refuses to build an instrument for any USD-M symbol whose status is not BinanceTradingStatus::Trading, reporting the symbol and its current status. Non-trading states cover the listing/delisting lifecycle: pending-trading, settling, pre-settle, delivering, delivered.

Source

Thrown at crates/adapters/binance/src/common/parse.rs:296

        Delivery,
    }

    let contract_kind = match symbol.contract_type.as_str() {
        CONTRACT_TYPE_PERPETUAL => ContractKind::CryptoPerpetual,
        CONTRACT_TYPE_TRADIFI_PERPETUAL => ContractKind::TradFi(parse_tradifi_asset_class(symbol)?),
        CONTRACT_TYPE_CURRENT_MONTH
        | CONTRACT_TYPE_NEXT_MONTH
        | CONTRACT_TYPE_CURRENT_QUARTER
        | CONTRACT_TYPE_NEXT_QUARTER => ContractKind::Delivery,
        _ => anyhow::bail!(
            "Unsupported USD-M contract type '{}' for symbol '{}'",
            symbol.contract_type,
            symbol.symbol,
        ),
    };

    if symbol.status != BinanceTradingStatus::Trading {
        anyhow::bail!(
            "Symbol '{}' is not trading (status: {:?})",
            symbol.symbol,
            symbol.status
        );
    }

    let quote_currency = get_currency(symbol.quote_asset.as_str());
    let settlement_currency = get_currency(symbol.margin_asset.as_str());

    let instrument_id = format_instrument_id(&symbol.symbol, BinanceProductType::UsdM);
    let raw_symbol = Symbol::new(symbol.symbol.as_str());

    let price_filter = get_filter(&symbol.filters, "PRICE_FILTER")
        .context("Missing PRICE_FILTER in symbol filters")?;

    let tick_size = parse_filter_price(price_filter, "tickSize")?;
    if tick_size.is_zero() {
        anyhow::bail!(

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Confirm the symbol's live status via the Binance USD-M exchangeInfo endpoint.
  2. Load instruments only for an explicit allowlist of symbols you trade, all in TRADING status.
  3. Treat this error as a skip condition during bulk loads rather than a fatal failure.
  4. For expired contracts you only need historical data from, request historical bars directly instead of loading a live instrument.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-filter USD-M symbols to those actively trading
let tradable: Vec<_> = exchange_info
    .symbols
    .into_iter()
    .filter(|s| s.status == BinanceTradingStatus::Trading)
    .collect();

Type guard

fn is_trading_usdm(status: BinanceTradingStatus) -> bool {
    status == BinanceTradingStatus::Trading
}

Try / catch

match parse_usdm_instrument(&symbol, ts_event, ts_init) {
    Ok(inst) => instruments.push(inst),
    Err(e) if e.to_string().contains("is not trading") => {
        tracing::debug!(symbol = %symbol.symbol, "skipping non-trading symbol")
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Loading USD-M instruments while one or more exchangeInfo symbols are in a non-TRADING lifecycle state — symbols pending listing, quarterly contracts in settlement/delivery, or already-delivered expired contracts.

Common situations: Startup coincides with a quarterly contract rotation; a bulk 'load all instruments' call during a delisting wave; replaying a recorded exchangeInfo snapshot that still contains expired contracts; explicitly requesting a specific expired symbol.

Related errors


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