{"record":{"id":"886edf17ef89ceff","repo":"nautechsystems/nautilus_trader","slug":"cfd-swap-diagnostic-total-overflow","errorCode":null,"errorMessage":"CFD swap diagnostic total overflow","messagePattern":"CFD swap diagnostic total overflow","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/modules/cfd_swap.rs","lineNumber":485,"sourceCode":"                .pending_adjustments\n                .take()\n                .ok_or_else(|| anyhow::anyhow!(\"no completed CFD swap batch to acknowledge\"))?;\n            let end_date = day\n                .pending_end_date\n                .ok_or_else(|| anyhow::anyhow!(\"CFD swap batch end date was not recorded\"))?;\n            (adjustments, end_date)\n        };\n\n        let mut failed = Vec::new();\n\n        for (adjustment, outcome) in adjustments.into_iter().zip(outcomes) {\n            match outcome {\n                AccountAdjustmentOutcome::Applied => {\n                    let mut totals = self.swap_totals.borrow_mut();\n                    let total = totals.entry(adjustment.amount.currency).or_default();\n                    *total = total\n                        .checked_add(adjustment.amount.as_decimal())\n                        .ok_or_else(|| anyhow::anyhow!(\"CFD swap diagnostic total overflow\"))?;\n                }\n                AccountAdjustmentOutcome::Failed(error) if error.is_retryable() => {\n                    log::warn!(\n                        \"Cannot apply CFD swap adjustment for {} on {}: {error}\",\n                        adjustment.amount.currency,\n                        adjustment.booking_date\n                    );\n                    failed.push(adjustment);\n                }\n                AccountAdjustmentOutcome::Failed(error) => {\n                    log::warn!(\n                        \"CFD swap adjustment {} on {} is recorded as unapplied: {error}\",\n                        adjustment.amount,\n                        adjustment.booking_date\n                    );\n                    let mut totals = self.unapplied_swap_totals.borrow_mut();\n                    let total = totals.entry(adjustment.amount.currency).or_default();\n                    *total = total","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/modules/cfd_swap.rs#L467-L503","documentation":"Raised when accumulating an applied CFD swap adjustment into the per-currency diagnostic `swap_totals` would overflow the Decimal total. The totals are diagnostic aggregates; a checked_add failure stops the run rather than silently corrupting the reported totals.","triggerScenarios":"Accumulating swap amounts whose sum exceeds the Decimal precision/maximum for the accumulator over a long backtest or with extremely large swap amounts (huge notional or swap rate inputs).","commonSituations":"Very long backtests with daily swaps in one currency; bad swap-rate data files containing implausibly large rates; misconfigured account balances/instrument sizes feeding the adjustment amounts.","solutions":["Validate swap rate inputs and account sizes before the run so per-day adjustments are within realistic bounds.","Shorten the backtest window or periodically reset/emit diagnostic totals if running over decades of simulated days.","Sanitize the rates data source for outlier values (e.g. rates entered as 5250 instead of 5.25)."],"exampleFix":"// before\nlet rate = parse_rate(raw)?; // raw \"5250\" taken literally\n\n// after\nlet rate = parse_rate(raw)?;\nanyhow::ensure!(rate.abs() < 100.0, \"implausible swap rate {rate}\");","handlingStrategy":"validation","validationCode":"anyhow::ensure!(swap_rate.abs() < 100.0, \"swap rate out of plausible range: {swap_rate}\");\nanyhow::ensure!(notional.is_finite() && notional.abs() < Decimal::from(1_000_000_000), \"notional too large\");","typeGuard":"fn plausible_rate(v: f64) -> bool { v.is_finite() && v.abs() < 100.0 }","tryCatchPattern":"if let Err(e) = engine.acknowledge(&outcomes) {\n    if e.to_string().contains(\"total overflow\") {\n        log::error!(\"diagnostic totals overflowed; shorten run or fix inputs\");\n    } else { return Err(e); }\n}","preventionTips":["Sanity-check swap rates and notionals before long runs","Screen rate data files for outliers and unit mistakes (bps vs %)","Emit/reset diagnostic totals periodically on very long backtests"],"tags":["backtest","cfd","decimal-overflow","diagnostics"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}