{"record":{"id":"90f26a953c0220aa","repo":"nautechsystems/nautilus_trader","slug":"historical-binancebar-requests-require-time-aggreg-90f26a","errorCode":null,"errorMessage":"historical BinanceBar requests require time aggregation","messagePattern":"historical BinanceBar requests require time aggregation","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/spot/data.rs","lineNumber":2250,"sourceCode":"\n    fn request_data(&self, request: RequestCustomData) -> anyhow::Result<()> {\n        if request.data_type.type_name() != \"BinanceBar\" {\n            log::warn!(\n                \"Unsupported custom data request: {}\",\n                request.data_type.type_name()\n            );\n            return Ok(());\n        }\n        let bar_type = parse_binance_bar_type(&request.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 data_type = request.data_type;\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\n        get_runtime().spawn(async move {","sourceCodeStart":2232,"sourceCodeEnd":2268,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/spot/data.rs#L2232-L2268","documentation":"The Binance Spot data client only serves historical bars that Binance actually provides: exchange-native klines, which exist solely for time-based intervals. Before dispatching a BinanceBar custom-data request it parses the bar_type from the DataType metadata and calls BarSpecification::is_time_aggregated(), rejecting threshold-driven aggregations (TICK, VOLUME, VALUE and their imbalance variants) because no Binance endpoint can return such history.","triggerScenarios":"Issuing a BinanceBar custom-data / request_bars call whose bar_type metadata is a non-time spec, e.g. 'BTCUSDT_BINANCE-10000-TICK-LAST-EXTERNAL' or 'ETHUSDT_BINANCE-500-VOLUME-LAST-EXTERNAL'. The ensure! at spot/data.rs:2250 fires synchronously, before any HTTP request is spawned.","commonSituations":"Porting a strategy from a venue that serves tick-bar or volume-bar history; reusing a BarType string that was built for Nautilus's internal aggregator; generating bar specs programmatically without filtering BarAggregation variants.","solutions":["Use a time-based aggregation that maps to a Binance kline interval (SECOND/MINUTE/HOUR/DAY), e.g. 'BTCUSDT_BINANCE-1-MINUTE-LAST-EXTERNAL'","If you need tick/volume/value bars, subscribe to TradeTicks or QuoteTicks and aggregate locally with an INTERNAL bar type","Pre-validate bar_type.spec().is_time_aggregated() in your own code before issuing the request"],"exampleFix":"// before\nlet bar_type = BarType::from_str(\"BTCUSDT_BINANCE-10000-TICK-LAST-EXTERNAL\")?;\nclient.request_bars(...)?; // -> requires time aggregation\n\n// after: kline interval Binance actually serves\nlet bar_type = BarType::from_str(\"BTCUSDT_BINANCE-1-MINUTE-LAST-EXTERNAL\")?;","handlingStrategy":"validation","validationCode":"fn ensure_binance_requestable(bar_type: &BarType) -> anyhow::Result<()> {\n    anyhow::ensure!(\n        bar_type.spec().is_time_aggregated(),\n        \"bar type {bar_type} is not time-aggregated; Binance only serves klines\"\n    );\n    Ok(())\n}\n// call before request_bars / BinanceBar custom data requests","typeGuard":"fn is_time_aggregated_bar(bar_type: &BarType) -> bool {\n    bar_type.spec().is_time_aggregated()\n}","tryCatchPattern":null,"preventionTips":["Define bar type strings once as consts and lint them against the venue's kline intervals","Treat TICK/VOLUME/VALUE aggregations as locally-computed only; never request their history from Binance","Validate the full triple (time-aggregated, LAST, EXTERNAL) in one helper at strategy start"],"tags":["binance","spot","bars","bar-type","validation","nautilustrader"],"backgroundTag":"invalid-bar-specification","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}