# OKX Raw REST API Workflow (when ccxt times out) When ccxt's `fetch_balance()` times out over Mihomo proxy (SSL handshake on `fetch_currencies()`), use raw `curl` + `openssl` HMAC signing instead. This approach works reliably for all operations. ## Common Setup ```bash # Read credentials from file (avoids bashrc non-interactive guard and $ expansion) P=$(cat ~/.bashrc | grep "PASSPHRASE" | head -1 | sed 's/.*=//') A=$(cat ~/.bashrc | grep "API_KEY" | head -1 | sed 's/.*=//') S=$(cat ~/.bashrc | grep "OKX_SECRET" | head -1 | sed 's/.*=//') # Generate timestamp and signature TS=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") MSG="${TS}GET/api/v5/account/balance" SIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$S" -binary | base64) # For POST requests, include body in signature BODY='{"instId":"MU-USDT-SWAP","tdMode":"cross","side":"sell","posSide":"net","ordType":"market","sz":"0.39"}' MSG="${TS}POST/api/v5/trade/order${BODY}" SIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$S" -binary | base64) ``` ## Operations ### 1. Check Balance (`GET /api/v5/account/balance`) ```bash TS=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") MSG="${TS}GET/api/v5/account/balance" SIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$S" -binary | base64) curl -s --max-time 15 --proxy http://127.0.0.1:7890 \ -H "OK-ACCESS-KEY: $A" \ -H "OK-ACCESS-SIGN: $SIG" \ -H "OK-ACCESS-TIMESTAMP: $TS" \ -H "OK-ACCESS-PASSPHRASE: $P" \ "https://www.okx.com/api/v5/account/balance" ``` ### 2. Set Leverage (`POST /api/v5/account/set-leverage`) ```bash BODY='{"instId":"MU-USDT-SWAP","mgnMode":"cross","lever":"10"}' TS=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") MSG="${TS}POST/api/v5/account/set-leverage${BODY}" SIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$S" -binary | base64) curl -s -X POST -H "Content-Type: application/json" --max-time 15 --proxy http://127.0.0.1:7890 \ -H "OK-ACCESS-KEY: $A" -H "OK-ACCESS-SIGN: $SIG" \ -H "OK-ACCESS-TIMESTAMP: $TS" -H "OK-ACCESS-PASSPHRASE: $P" \ -d "$BODY" "https://www.okx.com/api/v5/account/set-leverage" ``` ### 3. Place Market Order (`POST /api/v5/trade/order`) ```bash # Short BODY='{"instId":"MU-USDT-SWAP","tdMode":"cross","side":"sell","posSide":"net","ordType":"market","sz":"0.39"}' # Long BODY='{"instId":"MU-USDT-SWAP","tdMode":"cross","side":"buy","posSide":"net","ordType":"market","sz":"1"}' TS=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") MSG="${TS}POST/api/v5/trade/order${BODY}" SIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$S" -binary | base64) curl -s -X POST -H "Content-Type: application/json" --max-time 20 --proxy http://127.0.0.1:7890 \ -H "OK-ACCESS-KEY: $A" -H "OK-ACCESS-SIGN: $SIG" \ -H "OK-ACCESS-TIMESTAMP: $TS" -H "OK-ACCESS-PASSPHRASE: $P" \ -d "$BODY" "https://www.okx.com/api/v5/trade/order" ``` ### 4. Check Position (`GET /api/v5/account/positions`) ```bash TS=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") MSG="${TS}GET/api/v5/account/positions?instType=SWAP&instId=MU-USDT-SWAP" SIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$S" -binary | base64) curl -s --max-time 15 --proxy http://127.0.0.1:7890 \ -H "OK-ACCESS-KEY: $A" -H "OK-ACCESS-SIGN: $SIG" \ -H "OK-ACCESS-TIMESTAMP: $TS" -H "OK-ACCESS-PASSPHRASE: $P" \ "https://www.okx.com/api/v5/account/positions?instType=SWAP&instId=MU-USDT-SWAP" ``` Key fields returned: - `pos`: negative = short, positive = long - `avgPx`: entry price - `markPx`: current mark price - `liqPx`: liquidation price - `upl`: unrealized PnL - `imr`: initial margin (保证金) - `mgnRatio`: margin ratio - `closeOrderAlgo`: existing TP/SL algo orders ### 5. Set TP/SL (POST /api/v5/trade/order-algo) **Preferred: use ordType 'oco' for paired TP+SL in one call:** ```bash # Short: side=buy (buy to close), TP below, SL above BODY='{"instId":"MU-USDT-SWAP","tdMode":"cross","side":"buy","posSide":"net","ordType":"oco","sz":"0.39","tpTriggerPx":"1041.83","tpOrdPx":"-1","tpTriggerPxType":"last","slTriggerPx":"1200.37","slOrdPx":"-1","slTriggerPxType":"last","reduceOnly":"true"}' # Long: side=sell (sell to close), TP above, SL below BODY='{"instId":"MU-USDT-SWAP","tdMode":"cross","side":"sell","posSide":"net","ordType":"oco","sz":"1","tpTriggerPx":"1300","tpOrdPx":"-1","tpTriggerPxType":"last","slTriggerPx":"1100","slOrdPx":"-1","slTriggerPxType":"last","reduceOnly":"true"}' ``` **WARNING**: When using ordType 'conditional' with BOTH tpTriggerPx and slTriggerPx in a single request, only the SL is actually created -- the TP is silently dropped (returns code 0, no error, but tpTriggerPx is empty in the response). If you must use 'conditional' for both, place TWO separate requests: ```bash # SL only (one request) BODY_SL='{"instId":"SOL-USDT-SWAP","tdMode":"cross","side":"buy","posSide":"net","ordType":"conditional","sz":"0.1","slTriggerPx":"84.50","slOrdPx":"-1","slTriggerPxType":"last"}' # TP only (separate request) BODY_TP='{"instId":"SOL-USDT-SWAP","tdMode":"cross","side":"buy","posSide":"net","ordType":"conditional","sz":"0.1","tpTriggerPx":"80.00","tpOrdPx":"-1","tpTriggerPxType":"last"}' ``` Verify pending algo orders with: ```bash curl -s --max-time 15 --proxy http://127.0.0.1:7890 \ -H "OK-ACCESS-KEY: $A" -H "OK-ACCESS-SIGN: $SIG" \ -H "OK-ACCESS-TIMESTAMP: $TS" -H "OK-ACCESS-PASSPHRASE: $P" \ "https://www.okx.com/api/v5/trade/orders-algo-pending?instType=SWAP&instId=SOL-USDT-SWAP&ordType=conditional" ``` TS=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") MSG="${TS}POST/api/v5/trade/order-algo${BODY}" SIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "$S" -binary | base64) curl -s -X POST -H "Content-Type: application/json" --max-time 20 --proxy http://127.0.0.1:7890 \ -H "OK-ACCESS-KEY: $A" -H "OK-ACCESS-SIGN: $SIG" \ -H "OK-ACCESS-TIMESTAMP: $TS" -H "OK-ACCESS-PASSPHRASE: $P" \ -d "$BODY" "https://www.okx.com/api/v5/trade/order-algo" ``` ### 6. Get Current Price (`GET /api/v5/market/ticker`) Public endpoint — no signing needed: ```bash curl -s --max-time 10 --proxy http://127.0.0.1:7890 \ "https://www.okx.com/api/v5/market/ticker?instId=MU-USDT-SWAP" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['data'][0]['last'])" ``` ### 7. Get 4H ATR (via candle data) ```bash CANDLES=$(curl -s --max-time 15 --proxy http://127.0.0.1:7890 \ "https://www.okx.com/api/v5/market/history-candles?instId=MU-USDT-SWAP&bar=4H&limit=30") ATR=$(echo "$CANDLES" | python3 -c " import sys, json d = json.load(sys.stdin)['data'] trs = [] for i in range(1, len(d)): h = float(d[i][2]); l = float(d[i][3]); pc = float(d[i-1][4]) trs.append(max(h-l, abs(h-pc), abs(l-pc))) print(sum(trs)/len(trs)) ") echo "ATR(4H): $ATR" ``` ## Common Response Codes | Code | Meaning | Fix | |------|---------|-----| | 0 | Success | — | | 50103 | OK-ACCESS-KEY empty | Credentials not loaded; use file grep | | 50105 | OK-ACCESS-PASSPHRASE incorrect | Passphrase contains `$` that bash expanded; read from file literally | | 51000 | Parameter posSide error | Account is net_mode, pass `"posSide":"net"` or omit | | exit 28 | curl timeout | Proxy or SSL issue; retry or check Mihomo |