nautechsystems/nautilus_trader · error

Cannot convert SHORT position from quote to base: avg_px is

Error message

Cannot convert SHORT position from quote to base: avg_px is zero for {instrument_id}

What it means

In parse_position_status_report, a SHORT position reported in quote currency must be converted to base-currency quantity by dividing the absolute position size by the average price. If avg_px parses to zero the division is undefined, so the parser bails rather than emitting a bogus quantity.

Source

Thrown at crates/adapters/okx/src/common/parse.rs:1079

        if pos_ccy.is_empty() || pos_dec.is_zero() {
            // Flat position: no position or zero quantity
            (PositionSide::Flat, Decimal::ZERO)
        } else if pos_ccy == base_ccy {
            // Long position: pos_ccy is base currency, pos is already in base
            (PositionSide::Long, pos_dec.abs())
        } else if pos_ccy == quote_ccy {
            // Short position: pos_ccy is quote currency, need to convert to base
            // Use Decimal arithmetic to avoid floating-point precision errors
            let avg_px_str = if position.avg_px.is_empty() {
                // If no avg_px, use mark_px as fallback
                &position.mark_px
            } else {
                &position.avg_px
            };
            let avg_px_dec = Decimal::from_str(avg_px_str)?;

            if avg_px_dec.is_zero() {
                anyhow::bail!(
                    "Cannot convert SHORT position from quote to base: avg_px is zero for {instrument_id}"
                );
            }

            let quantity_dec = (pos_dec.abs() / avg_px_dec).round_dp(size_precision as u32);
            (PositionSide::Short, quantity_dec)
        } else {
            anyhow::bail!(
                "Unknown position currency '{pos_ccy}' for instrument {instrument_id} (base={base_ccy}, quote={quote_ccy})"
            );
        }
    } else {
        // For SWAP/FUTURES/OPTION: use existing logic
        // Determine position side based on OKX position mode:
        // - Net mode: posSide="net", uses signed quantities (positive=long, negative=short)
        // - Long/Short mode: posSide="long"/"short", quantities are always positive, side from field
        let side = match position.pos_side {
            OKXPositionSide::Net | OKXPositionSide::None => {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Skip/filter position rows with zero avg_px before parsing (treat as flat/closed)
  2. Refresh position status after a short delay instead of parsing the stale zero-avg-px snapshot
  3. If it persists, verify the OKX account mode (net vs long/short) matches the adapter configuration

Example fix

// before
let report = parse_position_status_report(&row)?;
// after
if row.avg_px == "0" { continue; } // skip zero-avg-px SHORT rows
let report = parse_position_status_report(&row)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust
if pos_side == "short" && avg_px_str.parse::<Decimal>().map(|d| d.is_zero()).unwrap_or(true) {
    // skip: position effectively closed, cannot convert quote->base
    return Ok(None);
}

Try / catch

// Rust
match parse_position_status_report(&row) {
    Err(e) if e.to_string().contains("avg_px is zero") => {
        debug!("ignoring stale SHORT row with zero avg_px");
        Ok(vec![])
    }
    other => other.map(|r| vec![r]),
}

Prevention

When it happens

Trigger: OKX position report for a SHORT position where the average price field is '0' or otherwise zero — typically a stale/just-closed position record or a venue field-population quirk in long/short (hedge) mode.

Common situations: Polling positions right after a close when OKX still returns the row with avgPx=0; hedge-mode accounts with empty side rows; netting mode quirks producing zero-priced SHORT rows.

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/d6b21d9977c7892a. Report an issue: GitHub.