nautechsystems/nautilus_trader · error

reduce_only requires spot_account_type=Margin (current: Cash

Error message

reduce_only requires spot_account_type=Margin (current: Cash)

What it means

reduce_only is a margin/leverage concept — it closes existing leveraged exposure and has no meaning for a Cash spot account. The adapter rejects reduce_only=true on Cash accounts before sending an order Kraken would refuse.

Source

Thrown at crates/adapters/kraken/src/http/spot/client.rs:3174

                OrderSide::Buy => "buy",
                _ => "sell",
            };

            if valid_tiers.is_empty() {
                anyhow::bail!("Leverage not supported for {raw_symbol} on {side_label} side");
            }

            if !valid_tiers.contains(&(n as i32)) {
                anyhow::bail!(
                    "Leverage {n}:1 not supported for {raw_symbol} on {side_label} side (valid: {valid_tiers:?})"
                );
            }
            builder.leverage(format!("{n}:1"));
        }

        if reduce_only {
            if account_type != AccountType::Margin {
                anyhow::bail!("reduce_only requires spot_account_type=Margin (current: Cash)");
            }
            builder.reduce_only(true);
        }

        builder
            .build()
            .map_err(|e| anyhow::anyhow!("Failed to build order params: {e}"))
    }
}

fn collect_spot_statuses(
    asset_pairs: &AssetPairsResponse,
) -> AHashMap<InstrumentId, MarketStatusAction> {
    asset_pairs
        .iter()
        .map(|(_, definition)| {
            let symbol_str = definition.wsname.as_ref().unwrap_or(&definition.altname);
            let normalized_symbol = normalize_spot_symbol(symbol_str.as_str());

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set reduce_only = false (or omit it) for cash-account orders.
  2. Reconfigure the client with spot_account_type = AccountType::Margin if the orders genuinely reduce margin positions.
  3. Gate reduce_only on account type in strategy code so it is only set when trading a margin account.

Example fix

// before
reduce_only: true, // account_type: AccountType::Cash
// after
reduce_only: false
Defensive patterns

Strategy: validation

Validate before calling

let reduce_only = reduce_only && account_config.spot_account_type == AccountType::Margin;

Try / catch

if let Err(e) = client.submit_order(req) {
    if e.to_string().contains("reduce_only requires spot_account_type=Margin") {
        // resubmit with reduce_only=false or switch to a margin client
    }
}

Prevention

When it happens

Trigger: Submitting a Kraken Spot order with reduce_only = true while the client's account_type is AccountType::Cash; typical when a position-exit signal path always sets reduce_only regardless of venue/account configuration.

Common situations: Sharing exit-order logic between futures and spot; account switched from Margin to Cash while strategy state still flags exits as reduce-only.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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