{"record":{"id":"5106dec233e9957d","repo":"nautechsystems/nautilus_trader","slug":"binance-historical-bars-require-time-aggregation-5106de","errorCode":null,"errorMessage":"Binance historical bars require time aggregation","messagePattern":"Binance historical bars require time aggregation","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/spot/data.rs","lineNumber":2364,"sourceCode":"        let bar_type = request.bar_type;\n        let start = request.start;\n        let end = request.end;\n        let limit = request.limit.map(|n| n.get() as u32);\n        let request_id = request.request_id;\n        let client_id = request.client_id.unwrap_or(self.client_id);\n        let params = request.params;\n        let clock = self.clock;\n        let start_nanos = datetime_to_unix_nanos(start);\n        let end_nanos = datetime_to_unix_nanos(end);\n        anyhow::ensure!(\n            bar_type.aggregation_source() == AggregationSource::External,\n            \"Binance historical bars require EXTERNAL aggregation\"\n        );\n        anyhow::ensure!(\n            bar_type.spec().price_type == PriceType::Last,\n            \"Binance historical bars require LAST price type\"\n        );\n        anyhow::ensure!(\n            bar_type.spec().is_time_aggregated(),\n            \"Binance historical bars require time aggregation\"\n        );\n\n        get_runtime().spawn(async move {\n            let result = http.request_bars(bar_type, start, end, limit).await;\n\n            match result.context(\"failed to request bars from Binance\") {\n                Ok(bars) => {\n                    let response = DataResponse::Bars(BarsResponse::new(\n                        request_id,\n                        client_id,\n                        bar_type,\n                        bars,\n                        start_nanos,\n                        end_nanos,\n                        clock.get_time_ns(),\n                        params,","sourceCodeStart":2346,"sourceCodeEnd":2382,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/spot/data.rs#L2346-L2382","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before (Python strategy)\nbar_type = BarType.from_str(\"BTCUSDT_BINANCE-1000-VOLUME-LAST-EXTERNAL\")\nself.request_bars(BarHistoryData(bar_type))\n\n# after\nbar_type = BarType.from_str(\"BTCUSDT_BINANCE-1-MINUTE-LAST-EXTERNAL\")\nself.request_bars(BarHistoryData(bar_type))","handlingStrategy":"validation","validationCode":"fn validate_binance_bar_request(bar_type: &BarType) -> anyhow::Result<()> {\n    anyhow::ensure!(bar_type.aggregation_source() == AggregationSource::External);\n    anyhow::ensure!(bar_type.spec().price_type == PriceType::Last);\n    anyhow::ensure!(bar_type.spec().is_time_aggregated());\n    Ok(())\n}","typeGuard":"fn is_requestable_binance_bar(bar_type: &BarType) -> bool {\n    bar_type.aggregation_source() == AggregationSource::External\n        && bar_type.spec().price_type == PriceType::Last\n        && bar_type.spec().is_time_aggregated()\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["binance","spot","bars","bar-type","validation"],"backgroundTag":"invalid-bar-specification","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}