nautechsystems/nautilus_trader · error · anyhow::Error
Binance historical bars require time aggregation
Error message
Binance historical bars require time aggregation
What it means
The standard historical-bars path (request_bars on the Spot data client) enforces the same constraint as the custom BinanceBar path: Binance klines exist only for time-based intervals, so BarSpecification::is_time_aggregated() must be true. Threshold aggregations (TICK, VOLUME, VALUE and imbalance variants) are rejected up front.
Source
Thrown at crates/adapters/binance/src/spot/data.rs:2364
let bar_type = request.bar_type;
let start = request.start;
let end = request.end;
let limit = request.limit.map(|n| n.get() as u32);
let request_id = request.request_id;
let client_id = request.client_id.unwrap_or(self.client_id);
let params = request.params;
let clock = self.clock;
let start_nanos = datetime_to_unix_nanos(start);
let end_nanos = datetime_to_unix_nanos(end);
anyhow::ensure!(
bar_type.aggregation_source() == AggregationSource::External,
"Binance historical bars require EXTERNAL aggregation"
);
anyhow::ensure!(
bar_type.spec().price_type == PriceType::Last,
"Binance historical bars require LAST price type"
);
anyhow::ensure!(
bar_type.spec().is_time_aggregated(),
"Binance historical bars require time aggregation"
);
get_runtime().spawn(async move {
let result = http.request_bars(bar_type, start, end, limit).await;
match result.context("failed to request bars from Binance") {
Ok(bars) => {
let response = DataResponse::Bars(BarsResponse::new(
request_id,
client_id,
bar_type,
bars,
start_nanos,
end_nanos,
clock.get_time_ns(),
params,View on GitHub (pinned to a4b06ed870)
Solutions
- Switch to a time aggregation (SECOND/MINUTE/HOUR/DAY/WEEK/MONTH), e.g. 'BTCUSDT_BINANCE-1-MINUTE-LAST-EXTERNAL'
- Aggregate threshold bars locally from TradeTicks/QuoteTicks with an INTERNAL bar type
- Validate bar_type.spec().is_time_aggregated() before the request
Example fix
# before (Python strategy)
bar_type = BarType.from_str("BTCUSDT_BINANCE-1000-VOLUME-LAST-EXTERNAL")
self.request_bars(BarHistoryData(bar_type))
# after
bar_type = BarType.from_str("BTCUSDT_BINANCE-1-MINUTE-LAST-EXTERNAL")
self.request_bars(BarHistoryData(bar_type)) Defensive patterns
Strategy: validation
Validate before calling
fn validate_binance_bar_request(bar_type: &BarType) -> anyhow::Result<()> {
anyhow::ensure!(bar_type.aggregation_source() == AggregationSource::External);
anyhow::ensure!(bar_type.spec().price_type == PriceType::Last);
anyhow::ensure!(bar_type.spec().is_time_aggregated());
Ok(())
} Type guard
fn is_requestable_binance_bar(bar_type: &BarType) -> bool {
bar_type.aggregation_source() == AggregationSource::External
&& bar_type.spec().price_type == PriceType::Last
&& bar_type.spec().is_time_aggregated()
} Prevention
- Run one shared validator for all three bar constraints so requests fail in your code, not the adapter
- Keep backtest and live bar specs in the same config so unsupported live specs surface immediately
- Use standard kline intervals (1s/1m/1h/1d) to guarantee a venue-side mapping exists
When it happens
Trigger: Calling request_bars with a non-time aggregation, e.g. 'BTCUSDT_BINANCE-1000-VOLUME-LAST-EXTERNAL' or 'BTCUSDT_BINANCE-50-TICK-LAST-EXTERNAL'. The ensure! at spot/data.rs:2364 fails before the request task spawns.
Common situations: Strategies requesting volume-bar or tick-bar history; bar specs shared between a backtest (which can aggregate anything) and live Binance execution; copy-pasted bar type strings from other adapters.
Related errors
- historical BinanceBar requests require time aggregation
- historical BinanceBar requests require EXTERNAL aggregation
- historical BinanceBar requests require LAST price type
- Binance historical bars require EXTERNAL aggregation
- Binance historical bars require LAST price type
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/5106dec233e9957d.
Report an issue: GitHub.