{"record":{"id":"4940c0445bd11794","repo":"nautechsystems/nautilus_trader","slug":"model-name-requires-an-option-instrument","errorCode":null,"errorMessage":"{model_name} requires an option instrument","messagePattern":"(.+?) requires an option instrument","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/execution/src/models/fee.rs","lineNumber":658,"sourceCode":"        Some(LiquiditySide::NoLiquiditySide) | None => anyhow::bail!(\"Liquidity side not set\"),\n    };\n    check_fee_rate(Some(rate), \"fee_rate\")?;\n    Ok(rate)\n}\n\nfn check_fee_rate(rate: Option<Decimal>, name: &str) -> anyhow::Result<()> {\n    if rate.is_some_and(|rate| rate < Decimal::ZERO) {\n        anyhow::bail!(\"`{name}` must be greater than or equal to zero\");\n    }\n    Ok(())\n}\n\nfn check_option_instrument(instrument: &InstrumentAny, model_name: &str) -> anyhow::Result<()> {\n    if !matches!(\n        instrument,\n        InstrumentAny::CryptoOption(_) | InstrumentAny::OptionContract(_)\n    ) {\n        anyhow::bail!(\"{model_name} requires an option instrument\");\n    }\n    Ok(())\n}\n\nfn commission_currency(instrument: &InstrumentAny) -> Currency {\n    if instrument.is_inverse() {\n        instrument.settlement_currency()\n    } else {\n        instrument.quote_currency()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::{cell::Cell, rc::Rc};\n\n    use nautilus_model::{\n        enums::{LiquiditySide, OrderSide, OrderType},","sourceCodeStart":640,"sourceCodeEnd":676,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/execution/src/models/fee.rs#L640-L676","documentation":"`check_option_instrument` guards option fee models by verifying the instrument is a CryptoOption or OptionContract. Any other instrument type (spot, futures, binary option, etc.) bails with '{model_name} requires an option instrument', since the model's fee math assumes option contracts.","triggerScenarios":"Calling get_commission/get_commission_with_context on an option fee model with an InstrumentAny that is not CryptoOption or OptionContract — e.g. CurrencyPair, CryptoPerpetual, FuturesContract, or BinaryOption.","commonSituations":"Assigning one fee model to a multi-instrument portfolio; misconfigured backtest where the instrument cache returns the wrong instrument; copy-pasted setup reused across markets.","solutions":["Wire the option fee model only to CryptoOption/OptionContract instruments","Dispatch fee models per instrument type when building the backtest/live config","Add a startup validation pass that checks each fee model against its instruments"],"exampleFix":"// before\nlet fee = option_fee_model.get_commission(&order, qty, px, &fx_pair_instrument)?;\n// after\nif matches!(instrument, InstrumentAny::CryptoOption(_) | InstrumentAny::OptionContract(_)) {\n    let fee = option_fee_model.get_commission(&order, qty, px, &instrument)?;\n} else {\n    let fee = maker_taker_model.get_commission(&order, qty, px, &instrument)?;\n}","handlingStrategy":"validation","validationCode":"if !matches!(instrument, InstrumentAny::CryptoOption(_) | InstrumentAny::OptionContract(_)) {\n    // route to a non-option fee model\n}","typeGuard":"fn is_option_instrument(i: &InstrumentAny) -> bool {\n    matches!(i, InstrumentAny::CryptoOption(_) | InstrumentAny::OptionContract(_))\n}","tryCatchPattern":"match option_model.get_commission(&order, qty, px, &instrument) {\n    Ok(fee) => fee,\n    Err(e) if e.to_string().contains(\"option instrument\") => generic_model_fee(),\n    Err(e) => return Err(e),\n}","preventionTips":["Select fee models per instrument type when configuring strategies","Validate model-instrument pairing at strategy startup","Keep per-market fee model registries instead of one global model"],"tags":["rust","fee-model","instrument-type","options"],"backgroundTag":"invalid-argument-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"}