{"record":{"id":"5e00c6bf2f379e41","repo":"nautechsystems/nautilus_trader","slug":"historical-binancebar-requests-require-external-ag","errorCode":null,"errorMessage":"historical BinanceBar requests require EXTERNAL aggregation","messagePattern":"historical BinanceBar requests require EXTERNAL aggregation","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/data.rs","lineNumber":2632,"sourceCode":"                }\n                Err(e) => log::error!(\"Instrument request failed: {e:?}\"),\n            }\n        });\n\n        Ok(())\n    }\n\n    /// 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);","sourceCodeStart":2614,"sourceCodeEnd":2650,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/futures/data.rs#L2614-L2650","documentation":"The custom `BinanceBar` historical request path only fetches exchange-native klines. After parsing the bar type from the data type metadata, it requires `AggregationSource::External`; INTERNAL (client-aggregated) bar types are rejected because no Binance endpoint can serve bars the client itself aggregates.","triggerScenarios":"`request_data`/`RequestCustomData` with data type name `BinanceBar` whose parsed BarType ends in `-INTERNAL`, e.g. `BTCUSDT-PERP.BINANCE-1-MINUTE-LAST-INTERNAL`.","commonSituations":"Requesting history for a bar type the strategy also uses for internal tick aggregation; config templates defaulting to INTERNAL aggregation; assuming request_bars fills any registered bar type.","solutions":["Request with an EXTERNAL bar type, e.g. `BTCUSDT-PERP.BINANCE-1-MINUTE-LAST-EXTERNAL`","If you need INTERNAL bars, subscribe to the EXTERNAL bars or trades and aggregate locally instead of requesting history for the INTERNAL type"],"exampleFix":"# before\nbar_type = BarType.from_str('BTCUSDT-PERP.BINANCE-1-MINUTE-LAST-INTERNAL')\nactor.request_custom_data(DataType(BinanceBar, {'bar_type': str(bar_type)}), ...)\n\n# after\nbar_type = BarType.from_str('BTCUSDT-PERP.BINANCE-1-MINUTE-LAST-EXTERNAL')\nactor.request_custom_data(DataType(BinanceBar, {'bar_type': str(bar_type)}), ...)","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(bar_type):\n    raise ValueError(f'{bar_type} is INTERNAL; Binance serves EXTERNAL bars only — request the matching -EXTERNAL type')","typeGuard":"def is_requestable_binance_bar(bar_type) -> bool:\n    return (\n        bar_type.aggregation_source == AggregationSource.EXTERNAL\n        and bar_type.spec.price_type == PriceType.LAST\n        and bar_type.spec.aggregation in (BarAggregation.SECOND, BarAggregation.MINUTE, BarAggregation.HOUR, BarAggregation.DAY)\n    )","tryCatchPattern":"try:\n    actor.request_custom_data(data_type, ...)\nexcept Exception as e:\n    if 'require EXTERNAL aggregation' in str(e):\n        raise ValueError('Swap the bar type to its -EXTERNAL form before requesting BinanceBar history') from e\n    raise","preventionTips":["Keep two distinct bar types per strategy: the EXTERNAL type for backfill, the INTERNAL one for live aggregation","Validate bar type strings end in -LAST-EXTERNAL-<time step> before any Binance history request"],"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"}