nautechsystems/nautilus_trader · error · ValueError

account report contains multiple currencies

Error message

account report contains multiple currencies

What it means

_calculate_account_returns derives an account balance/returns series from an account report DataFrame. When no target_currency is given, the code requires the report to be single-currency; a report containing rows in more than one currency cannot be aggregated into one balance series without exchange-rate conversion, so it raises ValueError.

Solutions

  1. Pass target_currency explicitly (e.g. target_currency='USD') so the report is filtered to one currency before series extraction.
  2. Split the tearsheet generation per account/currency, calling it once per currency.
  3. Configure the backtest with a single-currency account or a currency conversion setup so the account report is single-currency.

Example fix

// before
returns = _calculate_account_returns(report, target_currency=None)
// after
returns = _calculate_account_returns(report, target_currency='USD')
Defensive patterns

Strategy: validation

Validate before calling

currencies = set(report['currency'].dropna())
if len(currencies) > 1 and target_currency is None:
    raise ValueError(f'Multi-currency report {currencies}: pass target_currency')

Try / catch

try:
    acct_returns = _calculate_account_returns(report, target_currency=None)
except ValueError as e:
    if 'multiple currencies' in str(e):
        acct_returns = _calculate_account_returns(report, target_currency=base_currency)
    else:
        raise

Prevention

When it happens

Trigger: Calling _calculate_account_returns (via create_tearsheet's account-returns path) with an account report whose 'currency' column has multiple distinct values (e.g. a multi-currency account) and target_currency=None.

Common situations: Multi-currency backtest accounts (USD deposits plus EUR/JPY instruments); producing a tearsheet across a portfolio spanning several account currencies; forgetting to pass target_currency after changing the strategy's instruments.

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/0223dce99d3c57f7. Report an issue: GitHub.

Appendix: source

Thrown at python/nautilus_trader/analysis/tearsheet.py:920

                currency_report["total"].iloc[-1],
            )

    return account_info


def _extract_account_balance_series(
    report: pd.DataFrame,
    target_currency: str | None,
) -> tuple[pd.Series | None, str | None]:
    if report.empty or "currency" not in report or "total" not in report:
        return None, None

    observed_currency: str | None = None

    if target_currency is None:
        account_currencies = set(report["currency"].dropna())
        if len(account_currencies) != 1:
            raise ValueError("account report contains multiple currencies")
        observed_currency = next(iter(account_currencies))
    else:
        report = report[report["currency"] == target_currency]

    if report.empty:
        return None, observed_currency

    totals = pd.to_numeric(report["total"], errors="coerce")
    totals.index = report.index
    totals = totals.dropna().sort_index()
    if totals.empty:
        return None, observed_currency

    return totals.groupby(level=0).last(), observed_currency


def _calculate_daily_balance_returns(total_balance: pd.Series) -> pd.Series | None:
    account_returns = (

View on GitHub (pinned to 18893faf8b)