nautechsystems/nautilus_trader · error

Underlying price is required

Error message

Underlying price is required

What it means

The capped option fee model prices non-inverse option commissions relative to the underlying asset price. When `get_commission_with_context` is called without an underlying price in the context (and the instrument is not inverse), it cannot compute the rate fee and raises this error. Inverse instruments are exempt because their rate already embeds the price.

Source

Thrown at crates/execution/src/models/fee.rs:563

        self.get_commission_with_context(order, fill_quantity, fill_px, instrument, None)
    }

    fn get_commission_with_context(
        &self,
        order: &OrderAny,
        fill_quantity: Quantity,
        fill_px: Price,
        instrument: &InstrumentAny,
        underlying_px: Option<Price>,
    ) -> anyhow::Result<Money> {
        check_option_instrument(instrument, "CappedOptionFeeModel")?;
        let rate = option_fee_rate(order, instrument, self.maker_rate, self.taker_rate)?;
        let multiplier = instrument.multiplier().as_decimal();
        let rate_fee = if instrument.is_inverse() {
            rate
        } else {
            let underlying_px =
                underlying_px.ok_or_else(|| anyhow::anyhow!("Underlying price is required"))?;
            mul_checked(rate, underlying_px.as_decimal())?
        };
        let cap_fee = mul_checked(self.cap, fill_px.as_decimal())?;
        let fee_per_contract = mul_checked(rate_fee.min(cap_fee), multiplier)?;
        let total = mul_checked(fee_per_contract, fill_quantity.as_decimal())?;
        Money::from_decimal(total, commission_currency(instrument)).map_err(Into::into)
    }
}

#[derive(Debug, Clone)]
#[cfg_attr(
    feature = "python",
    pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.execution")
)]
#[cfg_attr(
    feature = "python",
    pyo3::pyclass(
        module = "nautilus_trader.execution",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Provide `underlying_px` in the call context when commissioning non-inverse option fills.
  2. Use the plain `get_commission` path (no underlying context) or an appropriate fee model for non-option instruments.
  3. Verify instrument type: only linear options require the underlying price; inverse instruments do not.

Example fix

// before
let fee = model.get_commission_with_context(&order, qty, px, &instrument, None)?;
// after
let fee = model.get_commission_with_context(&order, qty, px, &instrument,
    Some(underlying_price))?;
Defensive patterns

Strategy: type-guard

Validate before calling

if instrument.is_option() and not instrument.is_inverse():
    assert underlying_px is not None, "underlying price required for option fee cap model"

Type guard

fn needs_underlying_px(instrument: &InstrumentAny) -> bool {
    instrument.is_option() && !instrument.is_inverse()
}

Try / catch

let fee = match model.get_commission_with_context(&order, qty, px, &inst, underlying_px) {
    Ok(f) => f,
    Err(e) if e.to_string().contains("Underlying price is required") => fetch_underlying_and_retry(),
};

Prevention

When it happens

Trigger: Calling `get_commission_with_context` for a non-inverse option fee cap model while passing `None` for `underlying_px` in the context; also triggered in tests validating rejection of non-option instruments.

Common situations: Wiring a Python/Rust fee model and forgetting to populate the underlying price in the context; using the option fee model on spot/futures (non-option) instruments; inverse-vs-linear instrument misconfiguration.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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