nautechsystems/nautilus_trader · error · anyhow::Error
Binance historical bars require EXTERNAL aggregation
Error message
Binance historical bars require EXTERNAL aggregation
What it means
Historical Binance bars come only from Binance klines, which are built by the exchange itself. Nautilus distinguishes EXTERNAL aggregation (venue-built bars) from INTERNAL (locally aggregated); the adapter rejects BarsRequest bar types whose aggregation source is INTERNAL because the venue cannot serve history for a bar spec it never produced.
Source
Thrown at crates/adapters/binance/src/spot/data.rs:2356
});
Ok(())
}
fn request_bars(&self, request: RequestBars) -> anyhow::Result<()> {
let http = self.http_client.clone();
let sender = self.data_sender.clone();
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(View on GitHub (pinned to a4b06ed870)
Solutions
- Request the exchange-native bar type: suffix -EXTERNAL (AggregationSource::External), e.g. 'ETHUSDT_BINANCE-5-MINUTE-LAST-EXTERNAL'
- For INTERNAL bars, subscribe to trades/quotes and let the local aggregator build them instead of requesting history
- Check bar_type.aggregation_source() == AggregationSource::External before calling request_bars
Example fix
// before
let bar_type = BarType::from_str("ETHUSDT_BINANCE-5-MINUTE-LAST-INTERNAL")?;
// after: exchange-native klines
let bar_type = BarType::from_str("ETHUSDT_BINANCE-5-MINUTE-LAST-EXTERNAL")?; Defensive patterns
Strategy: validation
Validate before calling
fn ensure_external(bar_type: &BarType) -> anyhow::Result<()> {
anyhow::ensure!(
bar_type.aggregation_source() == AggregationSource::External,
"historical Binance bars need aggregation source EXTERNAL, got {bar_type}"
);
Ok(())
} Type guard
fn is_external_bar(bar_type: &BarType) -> bool {
bar_type.aggregation_source() == AggregationSource::External
} Prevention
- When constructing BarType for venue history, always pass AggregationSource::External explicitly
- Reserve -INTERNAL bar types for locally aggregated subscriptions
- Log the bar type string before requesting history; the suffix is the first thing to check
When it happens
Trigger: Calling request_bars with a bar type string ending in -INTERNAL, e.g. 'ETHUSDT_BINANCE-5-MINUTE-LAST-INTERNAL'. The ensure! at spot/data.rs:2356 fails before the request task is spawned.
Common situations: Defaulting to AggregationSource::Internal when constructing BarType programmatically; requesting history for a bar type the strategy built for local aggregation; porting configs between adapters without checking the source suffix.
Related errors
- historical BinanceBar requests require EXTERNAL aggregation
- historical BinanceBar requests require LAST price type
- historical BinanceBar requests require time aggregation
- Binance historical bars require LAST price type
- Binance historical bars require time aggregation
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/eb6a148ebb473ded.
Report an issue: GitHub.