nautechsystems/nautilus_trader · error

Binance Futures does not support second-level kline interval

Error message

Binance Futures does not support second-level kline intervals

What it means

Binance futures kline streams and endpoints have no 1-second interval (unlike Binance spot, which added one), so `subscribe_bars` maps the BarSpecification to a `BinanceKlineInterval` and then rejects `Second1`. The check runs before the `@kline_` stream name is formed, so no WebSocket subscription is attempted.

Source

Thrown at crates/adapters/binance/src/futures/data.rs:2028

        // Binance Futures uses aggTrade for aggregate trades
        let stream = format!("{}@aggTrade", format_binance_stream_symbol(&instrument_id));

        self.spawn_ws(
            async move {
                ws.subscribe(vec![stream])
                    .await
                    .context("trades subscription")
            },
            "trade subscription",
        );
        Ok(())
    }

    fn subscribe_bars(&mut self, cmd: SubscribeBars) -> anyhow::Result<()> {
        let bar_type = cmd.bar_type;
        let ws = self.ws_client.clone();
        let interval = bar_spec_to_binance_interval(bar_type.spec())?;
        anyhow::ensure!(
            interval != crate::common::enums::BinanceKlineInterval::Second1,
            "Binance Futures does not support second-level kline intervals"
        );

        let stream = format!(
            "{}@kline_{}",
            format_binance_stream_symbol(&bar_type.instrument_id()),
            interval.as_str()
        );

        self.spawn_ws(
            async move {
                ws.subscribe(vec![stream])
                    .await
                    .context("bars subscription")
            },
            "bar subscription",
        );

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Use a bar step of 1 minute or larger (1-MINUTE, 5-MINUTE, 1-HOUR, ...) for Binance Futures
  2. If 1-second bars are required, subscribe to the trade stream and aggregate 1s bars locally (INTERNAL aggregation from trades)

Example fix

# before
bar_type = BarType.from_str('BTCUSDT-PERP.BINANCE-1-SECOND-LAST-EXTERNAL')
actor.subscribe_bars(bar_type)

# after
bar_type = BarType.from_str('BTCUSDT-PERP.BINANCE-1-MINUTE-LAST-EXTERNAL')
actor.subscribe_bars(bar_type)
Defensive patterns

Strategy: validation

Validate before calling

from nautilus_trader.model.data import BarSpecification, BarAggregation

def is_second_aggregated(bar_spec) -> bool:
    return bar_spec.aggregation == BarAggregation.SECOND and bar_spec.step == 1

if is_second_aggregated(bar_type.spec):
    raise ValueError('Binance Futures has no 1-second klines; use >= 1-minute steps or aggregate trades locally')
actor.subscribe_bars(bar_type)

Type guard

def is_supported_futures_kline_step(bar_spec) -> bool:
    return not (bar_spec.aggregation == BarAggregation.SECOND and bar_spec.step == 1)

Try / catch

try:
    actor.subscribe_bars(bar_type)
except Exception as e:
    if 'second-level kline intervals' in str(e):
        raise ValueError('Binance Futures klines start at 1 minute; subscribe trades and aggregate 1s bars client-side') from e
    raise

Prevention

When it happens

Trigger: `subscribe_bars` with a bar type whose step is 1 SECOND, e.g. BarType string `BTCUSDT-PERP.BINANCE-1-SECOND-LAST-EXTERNAL` or INTERNAL — the interval mapping yields `BinanceKlineInterval::Second1` and the ensure fails.

Common situations: Porting a spot 1-second kline config to futures; low-latency strategies that used 1s bars on another venue; backfilling 1-second bars assuming the futures kline endpoint supports them.

Related errors


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