nautechsystems/nautilus_trader · error · anyhow::Error

Cannot cache futures spread: no reference futures price for

Error message

Cannot cache futures spread: no reference futures price for {futures_instrument_id}

What it means

`cache_futures_spread` computes a synthetic futures spread price from call/put option prices against a reference futures price. Before anything else it fetches the reference futures price via `get_price_object`; if the cache holds no price for that futures instrument it bails with this error, because the spread cannot be anchored without it.

Source

Thrown at crates/common/src/greeks.rs:1117

            anyhow::bail!(
                "Cannot cache futures spread: option underlyings differ call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}"
            );
        }

        if call_instrument.strike_price() != put_instrument.strike_price() {
            anyhow::bail!(
                "Cannot cache futures spread: strike prices differ call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}"
            );
        }

        if call_instrument.expiration_ns() != put_instrument.expiration_ns() {
            anyhow::bail!(
                "Cannot cache futures spread: expiration dates differ call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}"
            );
        }

        let reference_future_price = self.get_price_object(&futures_instrument_id).ok_or_else(|| {
            anyhow::anyhow!(
                "Cannot cache futures spread: no reference futures price for {futures_instrument_id}"
            )
        })?;
        let call_price = self.get_price(&call_instrument_id).ok_or_else(|| {
            anyhow::anyhow!(
                "Cannot cache futures spread: missing option price for {call_instrument_id}"
            )
        })?;
        let put_price = self.get_price(&put_instrument_id).ok_or_else(|| {
            anyhow::anyhow!(
                "Cannot cache futures spread: missing option price for {put_instrument_id}"
            )
        })?;

        let underlying_instrument_id =
            InstrumentId::from(format!("{call_underlying}.{}", call_instrument_id.venue));

        // Reject if the underlying is present in cache but is not a future

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Subscribe to quote/trade data for futures_instrument_id before calling cache_futures_spread.
  2. Check the futures instrument ID is the actual contract (e.g. ESZ5.GLBX), not the synthetic underlying.
  3. Verify the contract is still active/not expired and present in the cache.
  4. Seed the reference price in the cache if the venue does not stream it, or fall back to an earlier cached price.

Example fix

// before
engine.cache_futures_spread(&fut_id, &call_id, &put_id, &underlying)?;
// after
if engine.cache.price(&fut_id).is_none() {
    engine.subscribe_quotes(fut_id)?; // ensure reference future has data
}
engine.cache_futures_spread(&fut_id, &call_id, &put_id, &underlying)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust: verify reference future price exists first
if cache.price(&futures_instrument_id).is_none() {
    anyhow::bail!("reference future {futures_instrument_id} not priced; subscribe before caching spread");
}

Type guard

fn has_price(cache: &Cache, id: &InstrumentId) -> bool { cache.price(id).is_some() }

Try / catch

if let Err(e) = engine.cache_futures_spread(&fut_id, &call_id, &put_id, &underlying) {
    warn!("spread cache skipped: {e}");
}

Prevention

When it happens

Trigger: Calling cache_futures_spread(futures_instrument_id, call_instrument_id, put_instrument_id, ...) where the reference futures instrument has no cached price (no subscription, no trade/quote yet, or wrong instrument ID).

Common situations: Subscribing only to options but not the underlying future; referencing an expired or delisted futures contract; using the options-chain synthetic underlying ID instead of the tradable futures ID; calling before first market data arrives on a cold start.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — 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/223174dd480609ec. Report an issue: GitHub.