nautechsystems/nautilus_trader · error · anyhow::Error
Cannot cache futures spread: strike prices differ call_instr
Error message
Cannot cache futures spread: strike prices differ call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id} What it means
cache_futures_spread enforces put-call parity, so both legs must share the same strike. When call_instrument.strike_price() differs from put_instrument.strike_price() the method bails, since combining different strikes would not yield a valid implied future price.
Source
Thrown at crates/common/src/greeks.rs:1105
let Some(call_underlying) = call_instrument.underlying() else {
anyhow::bail!(
"Cannot cache futures spread: missing call underlying for {call_instrument_id}"
);
};
let Some(put_underlying) = put_instrument.underlying() else {
anyhow::bail!(
"Cannot cache futures spread: missing put underlying for {put_instrument_id}"
);
};
if call_underlying != put_underlying {
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}"View on GitHub (pinned to 18893faf8b)
Solutions
- Select the pair at the same strike (typically at-the-money) before calling cache_futures_spread.
- Compare strike_price() on both instruments before invoking and skip unequal pairs.
- Fix the strike parser if strikes were extracted incorrectly from instrument symbols.
Example fix
// before
let price = greeks.cache_futures_spread(call_6000_id, put_6050_id, future_id)?;
// after
if call.strike_price() != put.strike_price() {
tracing::warn!("strike mismatch: {} vs {}", call.strike_price().unwrap(), put.strike_price().unwrap());
return Ok(None);
}
let price = greeks.cache_futures_spread(call_6000_id, put_6000_id, future_id)?; Defensive patterns
Strategy: validation
Validate before calling
// rust
fn same_strike(cache: &Cache, call_id: &InstrumentId, put_id: &InstrumentId) -> bool {
cache.instrument(call_id).map(|i| i.strike_price()) == cache.instrument(put_id).map(|i| i.strike_price())
} Type guard
fn strike_of(cache: &Cache, id: &InstrumentId) -> Option<Price> {
cache.instrument(id).and_then(|i| i.strike_price())
} Try / catch
let res = greeks.cache_futures_spread(call_id, put_id, future_id);
if let Err(e) = res {
if e.to_string().contains("strike prices differ") {
reselect_pair_at_same_strike();
}
} Prevention
- Select parity pairs by (underlying, expiry, strike) composite key.
- Test strike parsing against vendor symbol formats to avoid truncation.
- Reject strangles/strangles-like combinations early — they are not parity pairs.
When it happens
Trigger: Passing a call and put with different strikes (e.g. from a strangle rather than an at-the-money parity pair); mis-parsing strike from symbol strings (ES 6000 call vs ES 6050 put); rounding differences in strike parsing.
Common situations: Symbol-to-ID parsing bugs where the strike field is truncated or misread; pairing logic that matches by expiry only; feeds that quote strikes in different tick sizes.
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
- Cannot cache futures spread: non-option instruments provided
- Cannot cache futures spread: expected call/put pair call_ins
- Cannot cache futures spread: option underlyings differ call_
- Cannot cache futures spread: expiration dates differ call_in
- option_summary_family_subs mutex poisoned
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9dc2d2d0597d3d04.
Report an issue: GitHub.