{"record":{"id":"662c1ae80e9d9a25","repo":"nautechsystems/nautilus_trader","slug":"invalid-ordertype-order-type-for-protection-pr","errorCode":null,"errorMessage":"Invalid `OrderType` {order_type} for protection price calculation","messagePattern":"Invalid `OrderType` (.+?) for protection price calculation","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/execution/src/protection.rs","lineNumber":43,"sourceCode":"/// Uses integer arithmetic on raw price values to avoid floating-point precision issues.\n///\n/// # Returns\n/// A calculated protection price.\n///\n/// # Errors\n/// Returns an error if:\n/// - the order type is invalid.\n/// - best bid/ask is not provided when required for the order side.\npub fn protection_price_calculate(\n    price_increment: Price,\n    order: &OrderAny,\n    protection_points: u32,\n    bid: Option<Price>,\n    ask: Option<Price>,\n) -> anyhow::Result<Price> {\n    let order_type = order.order_type();\n    if !matches!(order_type, OrderType::Market | OrderType::StopMarket) {\n        anyhow::bail!(\"Invalid `OrderType` {order_type} for protection price calculation\");\n    }\n\n    let offset_raw = PriceRaw::from(protection_points) * price_increment.raw;\n\n    let order_side = order.order_side();\n    let protection_raw = match order_side {\n        OrderSide::Buy => {\n            let opposite = ask.ok_or_else(|| anyhow::anyhow!(\"Ask required\"))?;\n            opposite.raw + offset_raw\n        }\n        OrderSide::Sell => {\n            let opposite = bid.ok_or_else(|| anyhow::anyhow!(\"Bid required\"))?;\n            opposite.raw - offset_raw\n        }\n    };\n\n    Ok(Price::from_raw(protection_raw, price_increment.precision))\n}","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/execution/src/protection.rs#L25-L61","documentation":"`protection_price_calculate` computes a protection (slippage-bounded) price for Market and StopMarket orders only. Any other OrderType (Limit, StopLimit, etc.) cannot have a protection price applied, so it bails with 'Invalid `OrderType` {order_type} for protection price calculation'.","triggerScenarios":"Calling `protection_price_calculate(order, protection_points, bid, ask)` with an order whose `order_type()` is Limit, StopLimit, or any non-market type; also reached by fill_market_order if the order mutated type mid-pipeline.","commonSituations":"Wiring protection-price logic into a generic fill handler that also receives Limit orders; venue emulation code applied to all order types instead of market-like ones; misconfigured strategy submitting StopLimit orders through a market-fill emulator.","solutions":["Only invoke protection price calculation for Market or StopMarket orders","Branch on order_type() before calling and skip/defer protection for other types","Fix the upstream submission so the intended order type matches the protection config"],"exampleFix":"// before\nlet protected_px = protection_price_calculate(&order, points, bid, ask)?; // Limit order\n// after\nif matches!(order.order_type(), OrderType::Market | OrderType::StopMarket) {\n    let protected_px = protection_price_calculate(&order, points, bid, ask)?;\n} else {\n    // use the order's explicit limit price instead\n}","handlingStrategy":"type-guard","validationCode":"if !matches!(order.order_type(), OrderType::Market | OrderType::StopMarket) {\n    // skip protection-price logic; use the order's own limit price\n}","typeGuard":"fn supports_protection(order: &OrderAny) -> bool {\n    matches!(order.order_type(), OrderType::Market | OrderType::StopMarket)\n}","tryCatchPattern":"match protection_price_calculate(&order, points, bid, ask) {\n    Ok(px) => px,\n    Err(e) if e.to_string().contains(\"Invalid `OrderType`\") => order.display_px().unwrap_or(last_px),\n    Err(e) => return Err(e),\n}","preventionTips":["Guard fill handlers by order type before applying protection logic","Keep market-like orders in separate pipelines from limit orders","Add tests covering each OrderType through the fill path"],"tags":["rust","order-type","protection-price","validation"],"backgroundTag":"invalid-enum-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}