nautechsystems/nautilus_trader · error · anyhow::Error

invalid 'take_profit' price: {e}

Error message

invalid 'take_profit' price: {e}

What it means

parse_bybit_tp_sl_params extracts TP/SL-related parameters from an order's params map. When a 'take_profit' key is present, its string value must parse into a Price via Price::from_str; failure produces this error (a separate check rejects negative values). It indicates the take-profit value supplied by the strategy is not a parseable price string.

Source

Thrown at crates/adapters/bybit/src/common/parse.rs:1792

        "1" | "2" | "3" | "4" | "5" => Ok(s),
        _ => anyhow::bail!("invalid 'bbo_level': '{s}', expected 1, 2, 3, 4, or 5"),
    }
}

/// Parses Bybit TP/SL parameters from an optional params map.
pub fn parse_bybit_tp_sl_params(params: Option<&Params>) -> anyhow::Result<BybitTpSlParams> {
    let Some(params) = params else {
        return Ok(BybitTpSlParams::default());
    };

    let mut result = BybitTpSlParams {
        is_leverage: params.get_bool("is_leverage").unwrap_or(false),
        ..Default::default()
    };

    if let Some(s) = get_price_str(params, "take_profit") {
        let p =
            Price::from_str(&s).map_err(|e| anyhow::anyhow!("invalid 'take_profit' price: {e}"))?;

        if p.as_f64() < 0.0 {
            anyhow::bail!("invalid 'take_profit' price: '{s}', expected a non-negative value");
        }
        result.take_profit = Some(p);
    }

    if let Some(s) = get_price_str(params, "stop_loss") {
        let p =
            Price::from_str(&s).map_err(|e| anyhow::anyhow!("invalid 'stop_loss' price: {e}"))?;

        if p.as_f64() < 0.0 {
            anyhow::bail!("invalid 'stop_loss' price: '{s}', expected a non-negative value");
        }
        result.stop_loss = Some(p);
    }

    for (key, setter) in [

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the take_profit param is a valid decimal string (e.g. "65000.5"), not empty or descriptive text.
  2. Validate/round the price to the instrument's price precision before attaching it to the order.
  3. Only include the take_profit key when a real TP is intended (omit rather than pass empty string).
  4. Sanitize upstream floats (reject NaN/inf, format with fixed decimals) before building params.

Example fix

// before
params.insert("take_profit".into(), format!("{}", maybe_tp)); // maybe_tp: Option<f64>
// after
if let Some(tp) = maybe_tp.filter(|v| v.is_finite() && *v > 0.0) {
    params.insert("take_profit".into(), format!("{:.2}", tp));
}
Defensive patterns

Strategy: validation

Validate before calling

// Rust: validate take_profit param before building order
let tp = tp.filter(|v| v.is_finite() && *v > 0.0)
    .map(|v| format!("{v:.instrument_price_precision$}"));

Type guard

fn valid_tp_string(s: &str) -> bool {
    s.trim().parse::<f64>().map(|v| v.is_finite() && v > 0.0).unwrap_or(false)
}

Try / catch

match parse_bybit_tp_sl_params(&params) {
    Ok(p) => p,
    Err(e) => { log::error!("rejecting order, bad TP/SL params: {e:#}"); return Err(e); }
};

Prevention

When it happens

Trigger: Submitting/modifying an order with params['take_profit'] set to a value Price::from_str rejects — empty string, non-numeric text, or a number exceeding price precision limits.

Common situations: Strategies passing floats/doubles instead of strings with sufficient decimal places; config files with placeholder or empty take-profit values; prices with more decimals than the instrument's precision; mixing NaN/inf from upstream calculations.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/4d388bf71c11e2ec. Report an issue: GitHub.