Skip to content

fix: OKX spot orders below 1 unit rejected with 51000 (sz precision misread as 0 for small lotSz)#159

Open
lollipopkit wants to merge 2 commits into
brokermr810:mainfrom
lollipopkit:fix/okx-lotsz-precision
Open

fix: OKX spot orders below 1 unit rejected with 51000 (sz precision misread as 0 for small lotSz)#159
lollipopkit wants to merge 2 commits into
brokermr810:mainfrom
lollipopkit:fix/okx-lotsz-precision

Conversation

@lollipopkit

Copy link
Copy Markdown

Problem

Placing a spot market order through the OKX adapter fails with:

OKX error: {'code': '1', 'data': [{'sCode': '51000', 'sMsg': 'Parameter sz error', ...}], 'msg': 'All operations failed'}

This affects any spot order below one whole base unit — e.g. a 50 USDT quick-trade buy of BTC/USDT (~0.0008 BTC).

Root cause

OkxClient._normalize_order_size() infers the size precision from lotSz by string-parsing the normalized Decimal:

lot_sz_normalized = lot_sz.normalize()   # Decimal('0.00000001') -> Decimal('1E-8')
lot_sz_str = str(lot_sz_normalized)      # '1E-8' — no '.' present
if '.' in lot_sz_str:                    # not taken
    ...
else:
    size_precision = 0                   # precision misread as 0

Decimal.normalize() renders small steps in scientific notation, so BTC-USDT spot (lotSz=0.00000001) yields precision 0. _dec_str(sz, strict_precision=0) then quantizes 0.00081471 down to sz="0", which OKX rejects with 51000.

Fix

Derive the precision from the Decimal exponent instead of parsing the string representation:

exp = lot_sz.normalize().as_tuple().exponent
if isinstance(exp, int):
    size_precision = min(max(0, -exp), 18)

Handles 0.00000001 → 8, 0.000001 → 6, 1 → 0 (whole swap contracts), 10 → 0.

Testing

  • Added tests/test_okx_order_size_precision.py (3 regression tests, instrument cache pre-seeded so no network needed) — all pass; the first case fails on the old code.
  • Verified end-to-end against OKX demo trading (x-simulated-trading: 1) via /api/quick-trade/place-order: a 50 USDT market buy of BTC/USDT that previously failed with 51000 now fills correctly (0.00081677 BTC @ 61246).

Decimal.normalize() renders lotSz values like 0.00000001 in scientific
notation (1E-8). The string-based precision parser found no '.' in
'1E-8' and fell back to precision 0, so any spot order below one whole
unit was quantized to sz="0" and rejected by OKX with error 51000
(Parameter sz error). Derive precision from the Decimal exponent
instead, and add regression tests.
@lollipopkit lollipopkit marked this pull request as ready for review July 2, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant