nautechsystems/nautilus_trader · error · anyhow::Error

historical BinanceBar requests require time aggregation

Error message

historical BinanceBar requests require time aggregation

What it means

The Binance Spot data client only serves historical bars that Binance actually provides: exchange-native klines, which exist solely for time-based intervals. Before dispatching a BinanceBar custom-data request it parses the bar_type from the DataType metadata and calls BarSpecification::is_time_aggregated(), rejecting threshold-driven aggregations (TICK, VOLUME, VALUE and their imbalance variants) because no Binance endpoint can return such history.

Source

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

    fn request_data(&self, request: RequestCustomData) -> anyhow::Result<()> {
        if request.data_type.type_name() != "BinanceBar" {
            log::warn!(
                "Unsupported custom data request: {}",
                request.data_type.type_name()
            );
            return Ok(());
        }
        let bar_type = parse_binance_bar_type(&request.data_type)?;
        anyhow::ensure!(
            bar_type.aggregation_source() == AggregationSource::External,
            "historical BinanceBar requests require EXTERNAL aggregation"
        );
        anyhow::ensure!(
            bar_type.spec().price_type == PriceType::Last,
            "historical BinanceBar requests require LAST price type"
        );
        anyhow::ensure!(
            bar_type.spec().is_time_aggregated(),
            "historical BinanceBar requests require time aggregation"
        );
        let http = self.http_client.clone();
        let sender = self.data_sender.clone();
        let request_id = request.request_id;
        let client_id = request.client_id;
        let data_type = request.data_type;
        let start = request.start;
        let end = request.end;
        let limit = request.limit.map(|value| value.get() as u32);
        let params = request.params;
        let clock = self.clock;
        let venue = self.venue();
        let start_nanos = datetime_to_unix_nanos(start);
        let end_nanos = datetime_to_unix_nanos(end);

        get_runtime().spawn(async move {

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Use a time-based aggregation that maps to a Binance kline interval (SECOND/MINUTE/HOUR/DAY), e.g. 'BTCUSDT_BINANCE-1-MINUTE-LAST-EXTERNAL'
  2. If you need tick/volume/value bars, subscribe to TradeTicks or QuoteTicks and aggregate locally with an INTERNAL bar type
  3. Pre-validate bar_type.spec().is_time_aggregated() in your own code before issuing the request

Example fix

// before
let bar_type = BarType::from_str("BTCUSDT_BINANCE-10000-TICK-LAST-EXTERNAL")?;
client.request_bars(...)?; // -> requires time aggregation

// after: kline interval Binance actually serves
let bar_type = BarType::from_str("BTCUSDT_BINANCE-1-MINUTE-LAST-EXTERNAL")?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_binance_requestable(bar_type: &BarType) -> anyhow::Result<()> {
    anyhow::ensure!(
        bar_type.spec().is_time_aggregated(),
        "bar type {bar_type} is not time-aggregated; Binance only serves klines"
    );
    Ok(())
}
// call before request_bars / BinanceBar custom data requests

Type guard

fn is_time_aggregated_bar(bar_type: &BarType) -> bool {
    bar_type.spec().is_time_aggregated()
}

Prevention

When it happens

Trigger: Issuing a BinanceBar custom-data / request_bars call whose bar_type metadata is a non-time spec, e.g. 'BTCUSDT_BINANCE-10000-TICK-LAST-EXTERNAL' or 'ETHUSDT_BINANCE-500-VOLUME-LAST-EXTERNAL'. The ensure! at spot/data.rs:2250 fires synchronously, before any HTTP request is spawned.

Common situations: Porting a strategy from a venue that serves tick-bar or volume-bar history; reusing a BarType string that was built for Nautilus's internal aggregator; generating bar specs programmatically without filtering BarAggregation variants.

Related errors


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