{"record":{"id":"28ea63e395dcca6a","repo":"nautechsystems/nautilus_trader","slug":"callbackrate-rate-out-of-binance-range-min-ra","errorCode":null,"errorMessage":"callbackRate {rate}% out of Binance range [{min_rate}, {max_rate}]","messagePattern":"callbackRate (.+?)% out of Binance range \\[(.+?), (.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/conversions.rs","lineNumber":102,"sourceCode":"        Some(true)\n    } else {\n        None\n    }\n}\n\n/// Converts a Nautilus trailing offset (percent) into a Binance `callbackRate` decimal.\n///\n/// # Errors\n///\n/// Returns an error if the computed rate is outside the Binance accepted range\n/// `[0.1%, 10.0%]`.\npub(crate) fn trailing_offset_to_callback_rate(offset: Decimal) -> anyhow::Result<Decimal> {\n    let rate = offset / rust_decimal::Decimal::ONE_HUNDRED;\n    let min_rate = rust_decimal::Decimal::new(1, 1);\n    let max_rate = rust_decimal::Decimal::new(100, 1);\n\n    if rate < min_rate || rate > max_rate {\n        anyhow::bail!(\"callbackRate {rate}% out of Binance range [{min_rate}, {max_rate}]\");\n    }\n\n    Ok(rate)\n}\n\n/// Converts a Nautilus trailing offset (percent) into a Binance `callbackRate` string.\n///\n/// # Errors\n///\n/// Returns an error if the computed rate is outside the Binance accepted range.\npub(crate) fn trailing_offset_to_callback_rate_string(offset: Decimal) -> anyhow::Result<String> {\n    let rate = trailing_offset_to_callback_rate(offset)?;\n    Ok(format_callback_rate(rate))\n}\n\n/// Formats a `callbackRate` decimal for Binance request params.\n///\n/// Whole percents are rendered with a trailing `.0` to match Binance examples.","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/futures/conversions.rs#L84-L120","documentation":"For Binance trailing-stop orders the Nautilus trailing offset (basis points) is converted to Binance's callbackRate percent, which the exchange limits to [0.1%, 10.0%]. trailing_offset_to_callback_rate divides the offset by 100 and rejects anything outside that band; submit_order validates it before the order is sent so the order is denied locally rather than rejected by the API.","triggerScenarios":"Submitting a TRAILING_STOP_MARKET order on a Binance futures client with trailing_offset outside 10..=1000 bps — e.g. trailing_offset=5 (0.05%, below minimum), or trailing_offset=5000 (50%, above maximum), with trailing_offset_type=BASIS_POINTS.","commonSituations":"Porting stop distances from price units or percent into bps incorrectly (e.g. intending 0.5% and writing 5 bps); very tight trailing stops copied from spot scalping configs; not realizing Binance caps the callback rate at 10%.","solutions":["Set trailing_offset between 10 and 1000 basis points (0.1% to 10%): e.g. 250 bps for a 2.5% callback.","Double-check the unit conversion: percent * 100 = bps; 0.5% is 50 bps, not 5.","Validate the offset before submission and clamp or reject in strategy code so the order never reaches the denial path."],"exampleFix":"# before\norder = OrderFactory.trailing_stop_market(\n    trailing_offset=5,      # intended 0.5% but is 0.05%\n    trailing_offset_type=TrailingOffsetType.BASIS_POINTS,\n)\n\n# after\norder = OrderFactory.trailing_stop_market(\n    trailing_offset=50,     # 0.5% = 50 bps (within 10..=1000)\n    trailing_offset_type=TrailingOffsetType.BASIS_POINTS,\n)","handlingStrategy":"try-catch","validationCode":"MIN_BPS, MAX_BPS = 10, 1000  # Binance callbackRate 0.1%..10.0%\n\ndef callback_rate_bps_ok(offset) -> bool:\n    return MIN_BPS <= offset <= MAX_BPS\n\nassert callback_rate_bps_ok(order.trailing_offset)","typeGuard":"def is_valid_binance_callback_bps(offset) -> bool:\n    return isinstance(offset, (int, float)) and 10 <= offset <= 1000","tryCatchPattern":"try:\n    client.submit_order(order)\nexcept Exception as e:\n    if 'callbackRate' in str(e) and 'out of Binance range' in str(e):\n        # clamp into [0.1%, 10.0%] or surface to risk checks; do NOT blind-retry\n        log.warning('trailing offset out of Binance callback range: %s', e)\n    else:\n        raise","preventionTips":["Convert percent to bps with percent * 100 before setting trailing_offset.","Enforce the 10..=1000 bps band in strategy risk checks before order creation.","Test trailing-stop submission against testnet once when changing offset units."],"tags":["binance","futures","trailing-stop","order-submission","callback-rate","validation"],"backgroundTag":"invalid-order-parameter","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}