{"record":{"id":"255c2faae3518dea","repo":"nautechsystems/nautilus_trader","slug":"historical-binancebar-requests-require-time-aggreg","errorCode":null,"errorMessage":"historical BinanceBar requests require time aggregation","messagePattern":"historical BinanceBar requests require time aggregation","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/data.rs","lineNumber":2640,"sourceCode":"    /// Requests Binance futures custom data.\n    ///\n    /// Spawned fetch failures are logged and no response is emitted, matching\n    /// the existing request-path behavior for other Binance adapter requests.\n    fn request_data(&self, request: RequestCustomData) -> anyhow::Result<()> {\n        let data_type = request.data_type.clone();\n        let data_type_name = data_type.type_name().to_string();\n\n        if data_type_name == \"BinanceBar\" {\n            let bar_type = parse_binance_bar_type(&data_type)?;\n            anyhow::ensure!(\n                bar_type.aggregation_source() == AggregationSource::External,\n                \"historical BinanceBar requests require EXTERNAL aggregation\"\n            );\n            anyhow::ensure!(\n                bar_type.spec().price_type == PriceType::Last,\n                \"historical BinanceBar requests require LAST price type\"\n            );\n            anyhow::ensure!(\n                bar_type.spec().is_time_aggregated(),\n                \"historical BinanceBar requests require time aggregation\"\n            );\n            let http = self.http_client.clone();\n            let sender = self.data_sender.clone();\n            let request_id = request.request_id;\n            let client_id = request.client_id;\n            let start = request.start;\n            let end = request.end;\n            let limit = request.limit.map(|value| value.get() as u32);\n            let params = request.params;\n            let clock = self.clock;\n            let venue = self.venue();\n            let start_nanos = datetime_to_unix_nanos(start);\n            let end_nanos = datetime_to_unix_nanos(end);\n            get_runtime().spawn(async move {\n                match http.request_binance_bars(bar_type, start, end, limit).await {\n                    Ok(bars) => {","sourceCodeStart":2622,"sourceCodeEnd":2658,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/futures/data.rs#L2622-L2658","documentation":"Historical `BinanceBar` requests require a time-aggregated BarSpecification — a SECOND/MINUTE/HOUR/DAY step. Tick- or volume-aggregated specs (e.g. a 100-VOLUME bar) are rejected because Binance kline endpoints only bucket data by time.","triggerScenarios":"`request_data` with data type name `BinanceBar` and a bar type whose aggregation is not time-based, e.g. `BTCUSDT-PERP.BINANCE-100-VOLUME-LAST-EXTERNAL` or `-1-TICK-LAST-EXTERNAL`.","commonSituations":"Volume-bar or tick-bar strategies trying to backfill history; generic bar request code forwarding whatever bar type the strategy registered; porting from venues that serve tick/volume candles.","solutions":["Request a time-aggregated bar type, e.g. `BTCUSDT-PERP.BINANCE-1-MINUTE-LAST-EXTERNAL`","For volume/tick bars, backfill trades and aggregate locally — Binance cannot serve them as history"],"exampleFix":"# before\nbar_type = BarType.from_str('BTCUSDT-PERP.BINANCE-100-VOLUME-LAST-EXTERNAL')\n\n# after\nbar_type = BarType.from_str('BTCUSDT-PERP.BINANCE-1-MINUTE-LAST-EXTERNAL')","handlingStrategy":"validation","validationCode":"from nautilus_trader.model.data import BarAggregation\n\ndef is_time_aggregated(bar_spec) -> bool:\n    return bar_spec.aggregation in (BarAggregation.SECOND, BarAggregation.MINUTE, BarAggregation.HOUR, BarAggregation.DAY)\n\nif not is_time_aggregated(bar_type.spec):\n    raise ValueError(f'{bar_type} is not time-aggregated; Binance kline history is time-bucketed only')","typeGuard":"def is_time_aggregated_bar(bar_type) -> bool:\n    return bar_type.spec.aggregation in (BarAggregation.SECOND, BarAggregation.MINUTE, BarAggregation.HOUR, BarAggregation.DAY)","tryCatchPattern":"try:\n    actor.request_custom_data(data_type, ...)\nexcept Exception as e:\n    if 'require time aggregation' in str(e):\n        raise ValueError('Volume/tick bar history is not served by Binance; backfill trades and aggregate locally') from e\n    raise","preventionTips":["Treat tick/volume bars as client-side constructs: backfill trades, never request their history from the exchange","Guard shared backfill code with a time-aggregation check on the bar specification"],"tags":["binance","futures","bars","aggregation","volume-bars","request-validation"],"backgroundTag":"non-time-aggregated-bar","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}