HKUDS/Vibe-Trading · error · UsdMObservationError
Binance USD-M Shadow Account requires one-way position mode
Error message
Binance USD-M Shadow Account requires one-way position mode
What it means
Raised by _require_one_way when any position row has positionSide != 'BOTH' (case-insensitive). Binance Hedge Mode sets positionSide to LONG or SHORT per side; this connector's Shadow Accounting only supports One-way Mode where a symbol has a single position with positionSide BOTH. The account must be switched to one-way mode on the exchange before the connector can read it.
Source
Thrown at agent/src/trading/connectors/binance/usdm.py:292
),
(
account["margin_balance"],
account["wallet_balance"] + account["total_unrealized_pnl"],
),
)
if any(not close_enough(reported, derived) for reported, derived in comparisons):
raise UsdMObservationError("Binance USD-M account totals are incoherent")
def _mapping_rows(value: Any, name: str) -> list[Mapping[str, Any]]:
if not isinstance(value, list) or any(not isinstance(row, Mapping) for row in value):
raise UsdMObservationError(f"Binance USD-M {name} payload is invalid")
return value
def _require_one_way(rows: list[Mapping[str, Any]]) -> None:
if any(str(row.get("positionSide") or "").upper() != "BOTH" for row in rows):
raise UsdMObservationError("Binance USD-M Shadow Account requires one-way position mode")
def _active_by_symbol(rows: list[Mapping[str, Any]], source: str) -> dict[str, Mapping[str, Any]]:
active: dict[str, Mapping[str, Any]] = {}
for row in rows:
quantity = _number(row.get("positionAmt"), "positionAmt")
if quantity == 0:
continue
symbol = str(row.get("symbol") or "").upper()
_canonical_symbol(symbol)
if symbol in active:
raise UsdMObservationError(f"duplicate {source} position symbol")
active[symbol] = row
return active
def _canonical_symbol(symbol: str) -> str:
if not symbol.endswith("USDT") or len(symbol) <= 4 or not symbol.isalnum():View on GitHub (pinned to 80ffdda44c)
Solutions
- Close all open positions and open orders, then switch to One-way Mode (Binance UI or POST /fapi/v1/positionSide/dual with dualSidePosition=false)
- Remove conflicting strategies/bots that require hedge mode from this account
- Update test fixtures so positionSide is 'BOTH' or absent (row.get defaults to '')... ensure it is literally BOTH
Example fix
# before
{"symbol": "BTCUSDT", "positionAmt": "1", "positionSide": "LONG"}
# after
{"symbol": "BTCUSDT", "positionAmt": "1", "positionSide": "BOTH"} Defensive patterns
Strategy: validation
Validate before calling
def is_one_way(position_rows: list[dict]) -> bool:
return all(str(r.get("positionSide") or "").upper() == "BOTH" for r in position_rows)
if not is_one_way(rows):
raise RuntimeError("account is in hedge mode; switch to one-way") Try / catch
try:
obs = connector.read_account_observation(...)
except UsdMObservationError as exc:
if "one-way position mode" in str(exc):
notify_operator("switch Binance account to one-way mode and restart")
raise Prevention
- Verify dualSidePosition=false via GET /fapi/v1/positionSide/dual before starting
- Don't share the API account with hedge-mode bots
- Set position mode during account provisioning, not at runtime
When it happens
Trigger: The Binance futures account has Position Mode set to Hedge Side (dual-side); positionRisk rows then carry positionSide='LONG'/'SHORT' and _join_positions raises on the first such row.
Common situations: Account was switched to Hedge Mode manually on the Binance UI or via POST /fapi/v1/positionSide/dual to run another strategy; existing open hedge-mode positions block switching back; CI fixtures written for hedge mode.
Related errors
- Binance USD-M assets must include USDT
- Binance USD-M account totals are incoherent
- Binance USD-M {name} payload is invalid
- duplicate {source} position symbol
- Binance USD-M field {name} must be numeric
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/cf5ea9148289a03b.
Report an issue: GitHub.