{"record":{"id":"bc6a72b655cb87db","repo":"nautechsystems/nautilus_trader","slug":"cannot-cache-futures-spread-no-reference-futures","errorCode":null,"errorMessage":"Cannot cache futures spread: no reference futures instrument for {futures_instrument_id}","messagePattern":"Cannot cache futures spread: no reference futures instrument for (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/common/src/greeks.rs","lineNumber":1066,"sourceCode":"    ) -> anyhow::Result<Price> {\n        let cache = self.cache.borrow();\n        let call_instrument = cache.instrument(&call_instrument_id).cloned();\n        let put_instrument = cache.instrument(&put_instrument_id).cloned();\n        let reference_future_instrument = cache.instrument(&futures_instrument_id).cloned();\n        drop(cache);\n\n        let Some(call_instrument) = call_instrument else {\n            anyhow::bail!(\n                \"Cannot cache futures spread: missing option instrument {call_instrument_id}\"\n            );\n        };\n        let Some(put_instrument) = put_instrument else {\n            anyhow::bail!(\n                \"Cannot cache futures spread: missing option instrument {put_instrument_id}\"\n            );\n        };\n        let Some(reference_future_instrument) = reference_future_instrument else {\n            anyhow::bail!(\n                \"Cannot cache futures spread: no reference futures instrument for {futures_instrument_id}\"\n            );\n        };\n\n        if call_instrument.instrument_class() != InstrumentClass::Option\n            || put_instrument.instrument_class() != InstrumentClass::Option\n        {\n            anyhow::bail!(\n                \"Cannot cache futures spread: non-option instruments provided call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}\"\n            );\n        }\n\n        if call_instrument.option_kind() != Some(OptionKind::Call)\n            || put_instrument.option_kind() != Some(OptionKind::Put)\n        {\n            anyhow::bail!(\n                \"Cannot cache futures spread: expected call/put pair call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}\"\n            );","sourceCodeStart":1048,"sourceCodeEnd":1084,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/greeks.rs#L1048-L1084","documentation":"GreeksCalculator::cache_futures_spread derives a futures spread from a call/put option pair against a reference future. Before doing any math it looks up the reference future instrument in the Cache; if the Cache has no instrument registered under futures_instrument_id it bails with this error. The library requires all three instruments (call, put, reference future) to be loaded into the Cache before spread caching can run.","triggerScenarios":"Calling cache_futures_spread(call_id, put_id, futures_id) where futures_id was never added to the Cache via add_instrument — e.g. the future definition was not received from the venue/adapter before the options, or the ID is misspelled or belongs to a different venue.","commonSituations":"Subscribing to option greeks before the data client has downloaded the futures instrument definitions; passing a synthetic or truncated instrument ID (wrong symbol/expiry in the future's ID); switching adapters where only the options were loaded into cache.","solutions":["Ensure the reference future instrument is added to the Cache (cache.add_instrument) before calling cache_futures_spread; wait for the instrument-definition response from the data client.","Verify futures_instrument_id matches an instrument actually defined on the venue (symbol, expiry, venue code all correct).","If the future is intentionally unavailable, derive the underlying ID differently or skip spread caching and handle the Err instead of unwrapping."],"exampleFix":"// before\nlet price = greeks.cache_futures_spread(call_id, put_id, future_id)?;\n// after\nif cache.instrument(&future_id).is_none() {\n    // request/await the future's instrument definition first\n    client.request_instrument(&future_id);\n    return Ok(None);\n}\nlet price = greeks.cache_futures_spread(call_id, put_id, future_id)?;","handlingStrategy":"validation","validationCode":"// rust\nfn have_reference_future(cache: &Cache, future_id: &InstrumentId) -> bool {\n    cache.instrument(future_id).is_some()\n}\nif !have_reference_future(&cache, &future_id) {\n    client.request_instrument(&future_id); // load definition first\n    return Ok(None);\n}","typeGuard":"fn reference_future(cache: &Cache, id: &InstrumentId) -> Option<&InstrumentAny> {\n    cache.instrument(id)\n}","tryCatchPattern":"match greeks.cache_futures_spread(call_id, put_id, future_id) {\n    Ok(price) => use(price),\n    Err(e) if e.to_string().contains(\"no reference futures instrument\") => request_future_definition(),\n    Err(e) => return Err(e),\n}","preventionTips":["Load all instrument definitions (options and the reference future) before enabling greeks computation.","Centralize instrument-ID construction so venue/symbol formatting is consistent.","Subscribe to instrument-definition events and gate spread caching on their arrival."],"tags":["rust","cache","futures","instrument-not-found"],"backgroundTag":"resource-not-found","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"}