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
- Skip/filter position rows with zero avg_px before parsing (treat as flat/closed)
- Refresh position status after a short delay instead of parsing the stale zero-avg-px snapshot
- 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
- Treat zero avg_px rows as closed positions and skip them
- Re-poll positions shortly after close events
- Confirm account mode (net vs long/short) matches adapter config
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
- instrument update lock poisoned
- option_summary_family_subs mutex poisoned
- Conditional order types must use OKXAlgoOrderType
- Invalid `OrderType` cannot be represented on OKX: {value:?}
- Not a conditional order type: {order_type:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d6b21d9977c7892a.
Report an issue: GitHub.