Repository navigation
v0.7.1 — OKX live validation + dashboard polish
Validation fixes and dashboard polish from a live OKX demo trading round-trip.
OKX adapter fixes (from live validation)
clOrdId format (src/execution/order_manager.cpp): replaced hyphen-separated CID format spr-<ms>-<n> with alphanumeric spr<ms>z<n>. OKX rejects hyphens in clOrdId with code 51000 "Parameter clOrdId error". Binance accepted hyphens; OKX does not. The 'z' is a non-digit alphanumeric separator that satisfies both.
Per-item sCode/sMsg surfaced (src/execution/okx_rest_client.cpp): OKX returns the actual order-rejection reason inside data[0].sCode / data[0].sMsg. When the top-level code != "0", process_status now extracts the per-item code/msg and logs both:
okx_rest_fail stage=app exchange_code=1 msg="All operations failed" item_code=51010 item_msg="..." endpoint=...
Without this, every order rejection just showed "All operations failed" — useless for diagnosis. With it, the user saw the actual chain of operator-side issues (account mode → demo balance → auto-borrow) in seconds.
Live trading mid → dashboard
src/main.cpp: strat_thread now calls pt.update_mid(sig.mid) after aggregator.ingest(...). Without this, pos_tracker.last_mid() stayed at 0 in live mode (it was only ever set in the backtest runner), so position_snapshots.mid_price was always 0 and the dashboard showed MID: 0 even with the WS streaming real OKX prices. Confirmed live: dashboard now reads mid=78252.35 against the real BTC-USDT-SWAP feed.
Dashboard polish
dashboard/src/api.ts:WebSocketClient::close()now handles theCONNECTINGstate gracefully (detaches handlers, defersws.close()until afteronopenif still connecting). React 18 StrictMode double-mounts effects in dev, which used to spam"WebSocket is closed before the connection is established"on every page load.dashboard/src/index.css: removed themin-height: 180pxfrom.paneland addedalign-self: startto.row-2 > *. Bottom panels (trades + events) now collapse to header height when empty instead of stretching to fill the grid row.dashboard/src/App.tsx: footer readsSPREADARA v0.7.0 · DSLabs.dashboard/package.json: version bumped to0.7.0.
Live OKX demo validation result
Round-tripped against wss://wspap.okx.com:8443/ws/v5/public?brokerId=9999 + https://www.okx.com with x-simulated-trading: 1:
| Operation | Result |
|---|---|
| WS market data (tickers + books5 + trades + ping/pong) | ✅ |
| HMAC-SHA256 base64 signing | ✅ no 401s |
place_order LIMIT GTX (post-only) |
✅ to=ACKNOWLEDGED |
cancel_order |
✅ sCode:"0" |
query_open_orders |
✅ |
| Per-item error visibility | ✅ |
Three operator-side gates surfaced during validation and were resolved by the user/API (not in code): OKX account mode → Multi-currency Margin Cross; demo wallet balance → claimed via demo UI; auto-borrow → enabled via POST /api/v5/account/set-auto-loan (since the SWAP collateral is USDT-margined and most demo balance was in other assets).
Build hygiene
- Added
data/recorded/*.binto.gitignoreso--recordoutput doesn't get committed. [testnet] enabled = falseis the committed default. Operators flip locally for paper trading.
Not in scope
- Bid/ask/spread fields aren't yet in
DbPositionSnapshot— the dashboard renders—for those. Extending the C++ writer + Go scan is a small follow-up. - The OKX
books5channel has noprevSeqId, so orderbook gap-detection always trips → tries (and fails) the Binance-style REST gap recovery → falls back to WS snapshot. Functionally fine, log-noisy.