{"record":{"id":"ba6786af40d1aded","repo":"nautechsystems/nautilus_trader","slug":"binance-historical-bars-require-external-aggregati","errorCode":null,"errorMessage":"Binance historical bars require EXTERNAL aggregation","messagePattern":"Binance historical bars require EXTERNAL aggregation","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/data.rs","lineNumber":3002,"sourceCode":"        });\n\n        Ok(())\n    }\n\n    fn request_bars(&self, request: RequestBars) -> anyhow::Result<()> {\n        let http = self.http_client.clone();\n        let sender = self.data_sender.clone();\n        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 Futures\") {\n                Ok(bars) => {\n                    let response = DataResponse::Bars(BarsResponse::new(","sourceCodeStart":2984,"sourceCodeEnd":3020,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/futures/data.rs#L2984-L3020","documentation":"The standard historical-bars request path (`request_bars`) requires the requested BarType to use `AggregationSource::External`, i.e. exchange-native bars. INTERNAL (client-aggregated) bar types are rejected before the fetch is spawned, because Binance kline endpoints can only return bars the exchange itself computed.","triggerScenarios":"`request_bars` with a BarType ending in `-INTERNAL`, e.g. `BTCUSDT-PERP.BINANCE-5-MINUTE-LAST-INTERNAL` — typically a bar type registered for client-side aggregation from ticks that is then also used for a history backfill request.","commonSituations":"Strategy registers INTERNAL bars (e.g. aggregated from trades) and then attempts to backfill the same bar type before live data arrives; config defaults producing INTERNAL bar types; porting workflows from venues that serve arbitrary aggregations.","solutions":["Request the matching EXTERNAL bar type, e.g. `BTCUSDT-PERP.BINANCE-5-MINUTE-LAST-EXTERNAL`","Backfill INTERNAL bars by fetching trades/EXTERNAL bars and feeding them through the local aggregator instead of requesting history for the INTERNAL type"],"exampleFix":"# before\nbar_type = BarType.from_str('BTCUSDT-PERP.BINANCE-5-MINUTE-LAST-INTERNAL')\nactor.request_bars(bar_type, start=start_ts)\n\n# after\nbar_type = BarType.from_str('BTCUSDT-PERP.BINANCE-5-MINUTE-LAST-EXTERNAL')\nactor.request_bars(bar_type, start=start_ts)","handlingStrategy":"validation","validationCode":"from nautilus_trader.model.enums import AggregationSource\n\ndef is_requestable_binance_bar(bar_type) -> bool:\n    return bar_type.aggregation_source == AggregationSource.EXTERNAL\n\nif not is_requestable_binance_bar(request_bar_type):\n    raise ValueError(f'{request_bar_type} is INTERNAL; request the matching -EXTERNAL bar type for Binance history')","typeGuard":"def is_external_bar(bar_type) -> bool:\n    return bar_type.aggregation_source == AggregationSource.EXTERNAL","tryCatchPattern":"try:\n    actor.request_bars(bar_type, start=start_ts, end=end_ts)\nexcept Exception as e:\n    if 'require EXTERNAL aggregation' in str(e):\n        external = BarType.from_str(str(bar_type).rsplit('-', 1)[0] + '-EXTERNAL')\n        actor.request_bars(external, start=start_ts, end=end_ts)\n    else:\n        raise","preventionTips":["Backfill only EXTERNAL bar types; warm INTERNAL bars by replaying trades/EXTERNAL bars through the local aggregator","Add a startup assertion that every bar type used for requests ends in -EXTERNAL"],"tags":["binance","futures","bars","aggregation","request-validation"],"backgroundTag":"external-aggregation-required","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}