{"record":{"id":"61ca285a76cfd345","repo":"nautechsystems/nautilus_trader","slug":"no-rate-data-for-currency-currency","errorCode":null,"errorMessage":"No rate data for currency {currency}","messagePattern":"No rate data for currency (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/modules/fx_rollover.rs","lineNumber":179,"sourceCode":"        let symbol = instrument_id.symbol.as_str();\n        if symbol.len() < 6 {\n            anyhow::bail!(\"FX symbol must be at least 6 characters: {symbol}\");\n        }\n\n        let base_currency = &symbol[..3];\n        let quote_currency = &symbol[symbol.len() - 3..];\n\n        let base_rate = self.lookup_rate(base_currency, date)?;\n        let quote_rate = self.lookup_rate(quote_currency, date)?;\n\n        Ok((base_rate - quote_rate) / 365.0 / 100.0)\n    }\n\n    fn lookup_rate(&self, currency: &str, date: Date) -> anyhow::Result<f64> {\n        let currency_rates = self\n            .rates\n            .get(currency)\n            .ok_or_else(|| anyhow::anyhow!(\"No rate data for currency {currency}\"))?;\n\n        // Try monthly key first\n        let monthly_key = format!(\"{}-{:02}\", date.year(), date.month());\n        if let Some(&rate) = currency_rates.get(&monthly_key) {\n            return Ok(rate);\n        }\n\n        // Fall back to quarterly key\n        let quarter = (date.month() - 1) / 3 + 1;\n        let quarterly_key = format!(\"{}-Q{quarter}\", date.year());\n        if let Some(&rate) = currency_rates.get(&quarterly_key) {\n            return Ok(rate);\n        }\n\n        anyhow::bail!(\"No rate data for {currency} at {monthly_key} or {quarterly_key}\")\n    }\n}\n","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/modules/fx_rollover.rs#L161-L197","documentation":"Raised by `lookup_rate` (used by `calc_overnight_rate`) when there is no rates entry at all for the requested currency in the loaded FX rollover rate table. The module cannot compute an overnight/rollover rate without baseline interest-rate data for that currency.","triggerScenarios":"Computing an overnight rate for a currency absent from the rates map — e.g. trading an instrument quoted in a currency not included in the provided rate dataset, or a currency-code mismatch (USD vs USDT vs USD.T).","commonSituations":"Backtesting instruments in exotic or crypto-settled currencies while the rate file only covers majors; passing currency codes with differing case or suffixes than the rate file keys.","solutions":["Add rate data for the missing currency to the dataset supplied to the FX rollover module.","Verify currency code casing/format matches exactly between instrument definitions and the rate table keys.","Restrict the backtest universe to instruments whose currencies are covered by your rate data.","Provide a default/override rate for unsupported currencies if your strategy tolerates approximation."],"exampleFix":"// before\nlet rates = load_rates(\"rates_major.csv\"); // missing SGD\nlet rate = lookup_rate(\"SGD\", date)?;\n\n// after\nlet rates = load_rates(\"rates_all.csv\"); // includes SGD\nanyhow::ensure!(rates.contains_key(\"SGD\"), \"SGD rates missing\");","handlingStrategy":"validation","validationCode":"let currencies: HashSet<_> = instruments.iter().map(|i| i.base_currency()).collect();\nlet missing: Vec<_> = currencies.filter(|c| !rates.contains_key(c.as_str())).collect();\nanyhow::ensure!(missing.is_empty(), \"rate data missing for: {missing:?}\");","typeGuard":"fn has_rates(rates: &HashMap<String, _>, currency: &str) -> bool { rates.contains_key(currency) }","tryCatchPattern":"match calc_overnight_rate(currency, date) {\n    Ok(rate) => rate,\n    Err(e) if e.to_string().starts_with(\"No rate data\") => {\n        log::warn!(\"falling back to zero rate for {currency}\");\n        0.0\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Cross-check instrument currencies against rate-file keys before the run","Normalize currency code casing and suffixes consistently","Ship a complete rate dataset covering every traded currency"],"tags":["fx","missing-data","currency","lookup"],"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"}