nautechsystems/nautilus_trader · error
total PnL overflow
Error message
total PnL overflow
What it means
try_total_pnl returns 'total PnL overflow' when Money::checked_add of realized and unrealized PnL fails because the sum cannot be represented in the Money type (fixed-precision raw value overflow for that currency). The currency check passed, but the arithmetic result exceeds the representable range.
Source
Thrown at crates/model/src/position.rs:1231
/// Returns total P&L (realized + unrealized) based on the last price.
///
/// # Errors
///
/// Returns an error if unrealized P&L cannot be calculated, the realized and unrealized
/// currencies differ, or the total cannot be represented as [`Money`].
pub fn try_total_pnl(&self, last: Price) -> anyhow::Result<Money> {
let unrealized = self.try_unrealized_pnl(last)?;
match self.realized_pnl {
Some(realized) => {
anyhow::ensure!(
realized.currency == unrealized.currency,
"realized and unrealized PnL currencies differ"
);
realized
.checked_add(unrealized)
.ok_or_else(|| anyhow::anyhow!("total PnL overflow"))
}
None => Ok(unrealized),
}
}
/// Returns total P&L (realized + unrealized) based on the last price.
#[must_use]
pub fn total_pnl(&self, last: Price) -> Money {
self.try_total_pnl(last).unwrap_or_else(|e| {
log::error!("Error calculating total PnL: {e}");
Money::zero(self.settlement_currency)
})
}
/// Returns unrealized P&L based on the last price.
///
/// # Errors
///View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the instrument's multiplier, size precision, and price precision are configured correctly — inflated values overflow Money.
- Check for duplicated fills inflating realized PnL and rebuild the position from authoritative history.
- Work with raw f64 PnL components (calculate_pnl_raw paths) and aggregate in a wider numeric type if your magnitudes are genuinely large.
Example fix
// before
let total = position.try_total_pnl(last)?; // Err: total PnL overflow
// after: fall back to f64 aggregation for huge magnitudes
let total = match position.try_total_pnl(last) {
Ok(m) => m,
Err(_) => {
let r = position.realized_pnl.map(|m| m.as_f64()).unwrap_or(0.0);
Money::new(r + position.try_unrealized_pnl(last)?.as_f64(), currency, precision)
}
}; Defensive patterns
Strategy: try-catch
Validate before calling
// estimate magnitude before calling
let approx = position.realized_pnl.as_ref().map(|m| m.as_f64()).unwrap_or(0.0)
+ position.try_unrealized_pnl(last)?.as_f64();
if approx.abs() > 9.0e15 { /* use f64 aggregation path */ } Try / catch
let total = match position.try_total_pnl(last) {
Ok(m) => m,
Err(e) if e.to_string().contains("overflow") => {
let r = position.realized_pnl.map(|m| m.as_f64()).unwrap_or(0.0);
let u = position.try_unrealized_pnl(last)?.as_f64();
Money::new(r + u, position.quote_currency, position.size_precision)
}
Err(e) => return Err(e),
}; Prevention
- Verify instrument multiplier and precision configuration — inflated values overflow Money.
- Watch for duplicate fills inflating realized PnL over long-lived positions.
- Fall back to f64 aggregation when PnL magnitudes approach Money limits.
When it happens
Trigger: Summing extremely large realized and unrealized PnL values whose combined raw integer amount exceeds the Money precision limit — e.g. very high notional instruments, wrong multiplier (contract size) configured orders of magnitude too large, or accumulated PnL over a very long-lived position.
Common situations: Misconfigured contract multiplier or size precision inflating PnL amounts; simulators generating unrealistic prices; running the same fills through the position repeatedly so realized PnL accumulates beyond bounds.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- realized and unrealized PnL currencies differ
- Cannot calculate inverse points: open price is not positive
- Cannot calculate inverse points: close price is not positive
- position fill void exceeds known fragments for {}
- stale position fill void for {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/6d1b2523c8754624.
Report an issue: GitHub.