From 8b5a51968a458a652c47b0e0e38d46e4553bd1f5 Mon Sep 17 00:00:00 2001 From: Jerko J <83344666+JJ-Cro@users.noreply.github.com> Date: Thu, 17 Sep 2026 19:33:14 +0200 Subject: [PATCH] feat: add Delta Hedge Currencies endpoint and related types This commit introduces the `getDeltaHedgeCurrencies` method in the `RestClient` class, along with the `DeltaHedgeCurrency` type for response handling. Additionally, the package version is updated to 3.2.4, and a new example demonstrating the usage of the endpoint is added. --- docs/endpointFunctionList.md | 767 +- .../RestClient/getDeltaHedgeCurrencies.js | 23 + llms.txt | 15152 ++++++++-------- package-lock.json | 4 +- package.json | 2 +- src/rest-client.ts | 7 + src/types/rest/response/public-data.ts | 5 + 7 files changed, 8011 insertions(+), 7949 deletions(-) create mode 100644 examples/apidoc/RestClient/getDeltaHedgeCurrencies.js diff --git a/docs/endpointFunctionList.md b/docs/endpointFunctionList.md index 3008ee2..f1c797d 100644 --- a/docs/endpointFunctionList.md +++ b/docs/endpointFunctionList.md @@ -49,389 +49,390 @@ This table includes all endpoints from the official Exchange API docs and corres | Function | AUTH | HTTP Method | Endpoint | | -------- | :------: | :------: | -------- | -| [getAccountInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L502) | :closed_lock_with_key: | GET | `/api/v5/account/instruments` | -| [getBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L508) | :closed_lock_with_key: | GET | `/api/v5/account/balance` | -| [getPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L512) | :closed_lock_with_key: | GET | `/api/v5/account/positions` | -| [getPositionsHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L516) | :closed_lock_with_key: | GET | `/api/v5/account/positions-history` | -| [getAccountPositionRisk()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L522) | :closed_lock_with_key: | GET | `/api/v5/account/account-position-risk` | -| [getBills()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L529) | :closed_lock_with_key: | GET | `/api/v5/account/bills` | -| [getBillsArchive()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L534) | :closed_lock_with_key: | GET | `/api/v5/account/bills-archive` | -| [getAccountBillSubtypes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L542) | :closed_lock_with_key: | GET | `/api/v5/account/subtypes` | -| [requestBillsHistoryDownloadLink()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L556) | :closed_lock_with_key: | POST | `/api/v5/account/bills-history-archive` | -| [getRequestedBillsHistoryLink()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L565) | :closed_lock_with_key: | GET | `/api/v5/account/bills-history-archive` | -| [getAccountConfiguration()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L571) | :closed_lock_with_key: | GET | `/api/v5/account/config` | -| [setPositionMode()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L575) | :closed_lock_with_key: | POST | `/api/v5/account/set-position-mode` | -| [setSettleCurrency()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L581) | :closed_lock_with_key: | POST | `/api/v5/account/set-settle-currency` | -| [setFeeType()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L587) | :closed_lock_with_key: | POST | `/api/v5/account/set-fee-type` | -| [setLeverage()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L591) | :closed_lock_with_key: | POST | `/api/v5/account/set-leverage` | -| [getMaxBuySellAmount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L596) | :closed_lock_with_key: | GET | `/api/v5/account/max-size` | -| [getMaxAvailableTradableAmount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L609) | :closed_lock_with_key: | GET | `/api/v5/account/max-avail-size` | -| [changePositionMargin()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L619) | :closed_lock_with_key: | POST | `/api/v5/account/position/margin-balance` | -| [movePositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L630) | :closed_lock_with_key: | POST | `/api/v5/account/move-positions` | -| [getMovePositionsHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L638) | :closed_lock_with_key: | GET | `/api/v5/account/move-positions-history` | -| [getLeverage()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L644) | :closed_lock_with_key: | GET | `/api/v5/account/leverage-info` | -| [getLeverageV2()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L656) | :closed_lock_with_key: | GET | `/api/v5/account/leverage-info` | -| [getLeverageEstimatedInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L664) | :closed_lock_with_key: | GET | `/api/v5/account/adjust-leverage-info` | -| [getMaxLoan()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L675) | :closed_lock_with_key: | GET | `/api/v5/account/max-loan` | -| [getFeeRates()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L684) | :closed_lock_with_key: | GET | `/api/v5/account/trade-fee` | -| [getInterestAccrued()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L695) | :closed_lock_with_key: | GET | `/api/v5/account/interest-accrued` | -| [getInterestRate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L707) | :closed_lock_with_key: | GET | `/api/v5/account/interest-rate` | -| [setGreeksDisplayType()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L711) | :closed_lock_with_key: | POST | `/api/v5/account/set-greeks` | -| [setIsolatedMode()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L715) | :closed_lock_with_key: | POST | `/api/v5/account/set-isolated-mode` | -| [getMaxWithdrawals()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L722) | :closed_lock_with_key: | GET | `/api/v5/account/max-withdrawal` | -| [getAccountRiskState()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L726) | :closed_lock_with_key: | GET | `/api/v5/account/risk-state` | -| [setAccountCollateralAssets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L730) | :closed_lock_with_key: | POST | `/api/v5/account/set-collateral-assets` | -| [getAccountCollateralAssets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L744) | :closed_lock_with_key: | GET | `/api/v5/account/collateral-assets` | -| [submitQuickMarginBorrowRepay()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L756) | :closed_lock_with_key: | POST | `/api/v5/account/quick-margin-borrow-repay` | -| [getQuickMarginBorrowRepayHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L765) | :closed_lock_with_key: | GET | `/api/v5/account/quick-margin-borrow-repay-history` | -| [borrowRepayVIPLoan()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L774) | :closed_lock_with_key: | POST | `/api/v5/account/borrow-repay` | -| [getVIPLoanBorrowRepayHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L783) | :closed_lock_with_key: | GET | `/api/v5/account/borrow-repay-history` | -| [getVIPInterestAccrued()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L787) | :closed_lock_with_key: | GET | `/api/v5/account/vip-interest-accrued` | -| [getVIPInterestDeducted()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L791) | :closed_lock_with_key: | GET | `/api/v5/account/vip-interest-deducted` | -| [getVIPLoanOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L797) | :closed_lock_with_key: | GET | `/api/v5/account/vip-loan-order-list` | -| [getVIPLoanOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L803) | :closed_lock_with_key: | GET | `/api/v5/account/vip-loan-order-detail` | -| [getBorrowInterestLimits()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L809) | :closed_lock_with_key: | GET | `/api/v5/account/interest-limits` | -| [getFixedLoanBorrowLimit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L816) | :closed_lock_with_key: | GET | `/api/v5/account/fixed-loan/borrowing-limit` | -| [getFixedLoanBorrowQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L820) | :closed_lock_with_key: | GET | `/api/v5/account/fixed-loan/borrowing-quote` | -| [submitFixedLoanBorrowOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L829) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/borrowing-order` | -| [updateFixedLoanBorrowOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L842) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/amend-borrowing-order` | -| [manualRenewFixedLoanBorrowOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L855) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/manual-reborrow` | -| [repayFixedLoanBorrowOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L869) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/repay-borrowing-order` | -| [convertFixedLoanToMarketLoan()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L880) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/convert-to-market-loan` | -| [reduceFixedLoanLiabilities()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L891) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/reduce-liabilities` | -| [getFixedLoanBorrowOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L906) | :closed_lock_with_key: | GET | `/api/v5/account/fixed-loan/borrowing-orders-list` | -| [manualBorrowRepay()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L915) | :closed_lock_with_key: | POST | `/api/v5/account/spot-manual-borrow-repay` | -| [setAutoRepay()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L929) | :closed_lock_with_key: | POST | `/api/v5/account/set-auto-repay` | -| [getBorrowRepayHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L937) | :closed_lock_with_key: | GET | `/api/v5/account/spot-borrow-repay-history` | -| [positionBuilder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L943) | :closed_lock_with_key: | POST | `/api/v5/account/position-builder` | -| [updateRiskOffsetAmount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L947) | :closed_lock_with_key: | POST | `/api/v5/account/set-riskOffset-amt` | -| [getGreeks()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L959) | :closed_lock_with_key: | GET | `/api/v5/account/greeks` | -| [getPMLimitation()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L963) | :closed_lock_with_key: | GET | `/api/v5/account/position-tiers` | -| [updateRiskOffsetType()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L971) | :closed_lock_with_key: | POST | `/api/v5/account/set-riskOffset-type` | -| [activateOption()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L979) | :closed_lock_with_key: | POST | `/api/v5/account/activate-option` | -| [setAutoLoan()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L987) | :closed_lock_with_key: | POST | `/api/v5/account/set-auto-loan` | -| [presetAccountLevelSwitch()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L991) | :closed_lock_with_key: | POST | `/api/v5/account/account-level-switch-preset` | -| [getAccountSwitchPrecheck()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1002) | :closed_lock_with_key: | GET | `/api/v5/account/set-account-switch-precheck` | -| [setAccountMode()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1011) | :closed_lock_with_key: | POST | `/api/v5/account/set-account-level` | -| [resetMMPStatus()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1017) | :closed_lock_with_key: | POST | `/api/v5/account/mmp-reset` | -| [setMMPConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1025) | :closed_lock_with_key: | POST | `/api/v5/account/mmp-config` | -| [getMMPConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1029) | :closed_lock_with_key: | GET | `/api/v5/account/mmp-config` | -| [setTradingConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1033) | :closed_lock_with_key: | POST | `/api/v5/account/set-trading-config` | -| [precheckSetDeltaNeutral()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1039) | :closed_lock_with_key: | GET | `/api/v5/account/precheck-set-delta-neutral` | -| [submitOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1054) | :closed_lock_with_key: | POST | `/api/v5/trade/order` | -| [submitMultipleOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1058) | :closed_lock_with_key: | POST | `/api/v5/trade/batch-orders` | -| [cancelOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1062) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-order` | -| [cancelMultipleOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1066) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-batch-orders` | -| [amendOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1072) | :closed_lock_with_key: | POST | `/api/v5/trade/amend-order` | -| [amendMultipleOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1076) | :closed_lock_with_key: | POST | `/api/v5/trade/amend-batch-orders` | -| [closePositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1080) | :closed_lock_with_key: | POST | `/api/v5/trade/close-position` | -| [getOrderDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1084) | :closed_lock_with_key: | GET | `/api/v5/trade/order` | -| [getOrderList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1088) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-pending` | -| [getOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1095) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-history` | -| [getOrderHistoryArchive()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1102) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-history-archive` | -| [getFills()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1111) | :closed_lock_with_key: | GET | `/api/v5/trade/fills` | -| [getFillsHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1118) | :closed_lock_with_key: | GET | `/api/v5/trade/fills-history` | -| [getEasyConvertCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1123) | :closed_lock_with_key: | GET | `/api/v5/trade/easy-convert-currency-list` | -| [submitEasyConvert()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1136) | :closed_lock_with_key: | POST | `/api/v5/trade/easy-convert` | -| [getEasyConvertHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1145) | :closed_lock_with_key: | GET | `/api/v5/trade/easy-convert-history` | -| [getOneClickRepayCurrencyList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1154) | :closed_lock_with_key: | GET | `/api/v5/trade/one-click-repay-currency-list` | -| [submitOneClickRepay()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1168) | :closed_lock_with_key: | POST | `/api/v5/trade/one-click-repay` | -| [getOneClickRepayHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1176) | :closed_lock_with_key: | GET | `/api/v5/trade/one-click-repay-history` | -| [cancelMassOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1180) | :closed_lock_with_key: | POST | `/api/v5/trade/mass-cancel` | -| [cancelAllAfter()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1192) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-all-after` | -| [getAccountRateLimit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1199) | :closed_lock_with_key: | GET | `/api/v5/trade/account-rate-limit` | -| [submitOrderPrecheck()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1203) | :closed_lock_with_key: | POST | `/api/v5/trade/order-precheck` | -| [placeAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1213) | :closed_lock_with_key: | POST | `/api/v5/trade/order-algo` | -| [cancelAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1217) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-algos` | -| [amendAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1223) | :closed_lock_with_key: | POST | `/api/v5/trade/amend-algos` | -| [cancelAdvanceAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1229) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-advance-algos` | -| [getAlgoOrderDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1235) | :closed_lock_with_key: | GET | `/api/v5/trade/order-algo` | -| [getAlgoOrderList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1241) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-algo-pending` | -| [getAlgoOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1247) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-algo-history` | -| [placeGridAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1259) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/order-algo` | -| [amendGridAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1263) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/amend-order-algo` | -| [stopGridAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1280) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/stop-order-algo` | -| [closeGridContractPosition()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1284) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/close-position` | -| [cancelGridContractCloseOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1290) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/cancel-close-order` | -| [instantTriggerGridAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1300) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/order-instant-trigger` | -| [getGridAlgoOrderList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1312) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/orders-algo-pending` | -| [getGridAlgoOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1319) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/orders-algo-history` | -| [getGridAlgoOrderDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1326) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/orders-algo-details` | -| [getGridAlgoSubOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1336) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/sub-orders` | -| [getGridAlgoOrderPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1348) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/positions` | -| [spotGridWithdrawIncome()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1355) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/withdraw-income` | -| [computeGridMarginBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1359) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/compute-margin-balance` | -| [adjustGridMarginBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1370) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/margin-balance` | -| [adjustGridInvestment()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1379) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/adjust-investment` | -| [getGridAIParameter()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1390) | | GET | `/api/v5/tradingBot/grid/ai-param` | -| [computeGridMinInvestment()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1399) | | POST | `/api/v5/tradingBot/grid/min-investment` | -| [getRSIBackTesting()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1406) | | GET | `/api/v5/tradingBot/public/rsi-back-testing` | -| [getMaxGridQuantity()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1414) | | GET | `/api/v5/tradingBot/grid/grid-quantity` | -| [createSignal()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1428) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/create-signal` | -| [getSignals()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1432) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/signals` | -| [createSignalBot()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1436) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/order-algo` | -| [cancelSignalBots()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1442) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/stop-order-algo` | -| [updateSignalMargin()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1451) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/margin-balance` | -| [updateSignalTPSL()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1459) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/amendTPSL` | -| [setSignalInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1467) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/set-instruments` | -| [getSignalBotOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1478) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/orders-algo-details` | -| [getActiveSignalBot()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1488) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/orders-algo-details` | -| [getSignalBotHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1495) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/orders-algo-history` | -| [getSignalBotPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1502) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/positions` | -| [getSignalBotPositionHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1509) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/positions-history` | -| [closeSignalBotPosition()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1518) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/close-position` | -| [placeSignalBotSubOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1526) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/sub-order` | -| [cancelSubOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1530) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/cancel-sub-order` | -| [getSignalBotSubOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1537) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/sub-orders` | -| [getSignalBotEventHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1541) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/event-history` | -| [submitRecurringBuyOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1553) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/recurring/order-algo` | -| [amendRecurringBuyOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1559) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/recurring/amend-order-algo` | -| [stopRecurringBuyOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1568) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/recurring/stop-order-algo` | -| [getRecurringBuyOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1577) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/recurring/orders-algo-pending` | -| [getRecurringBuyOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1586) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/recurring/orders-algo-history` | -| [getRecurringBuyOrderDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1595) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/recurring/orders-algo-details` | -| [getRecurringBuySubOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1604) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/recurring/sub-orders` | -| [getCopytradingSubpositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1616) | :closed_lock_with_key: | GET | `/api/v5/copytrading/current-subpositions` | -| [getCopytradingSubpositionsHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1622) | :closed_lock_with_key: | GET | `/api/v5/copytrading/subpositions-history` | -| [submitCopytradingAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1628) | :closed_lock_with_key: | POST | `/api/v5/copytrading/algo-order` | -| [closeCopytradingSubposition()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1634) | :closed_lock_with_key: | POST | `/api/v5/copytrading/close-subposition` | -| [getCopytradingInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1643) | :closed_lock_with_key: | GET | `/api/v5/copytrading/instruments` | -| [setCopytradingInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1652) | :closed_lock_with_key: | POST | `/api/v5/copytrading/set-instruments` | -| [getCopytradingProfitDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1664) | :closed_lock_with_key: | GET | `/api/v5/copytrading/profit-sharing-details` | -| [getCopytradingTotalProfit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1673) | :closed_lock_with_key: | GET | `/api/v5/copytrading/total-profit-sharing` | -| [getCopytradingUnrealizedProfit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1679) | :closed_lock_with_key: | GET | `/api/v5/copytrading/unrealized-profit-sharing-details` | -| [getCopytradingTotalUnrealizedProfit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1688) | :closed_lock_with_key: | GET | `/api/v5/copytrading/total-unrealized-profit-sharing` | -| [applyCopytradingLeadTrading()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1700) | :closed_lock_with_key: | POST | `/api/v5/copytrading/apply-lead-trading` | -| [stopCopytradingLeadTrading()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1711) | :closed_lock_with_key: | POST | `/api/v5/copytrading/stop-lead-trading` | -| [updateCopytradingProfitSharing()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1719) | :closed_lock_with_key: | POST | `/api/v5/copytrading/amend-profit-sharing-ratio` | -| [getCopytradingAccount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1733) | :closed_lock_with_key: | GET | `/api/v5/copytrading/config` | -| [setCopytradingFirstCopy()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1737) | :closed_lock_with_key: | POST | `/api/v5/copytrading/first-copy-settings` | -| [updateCopytradingCopySettings()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1745) | :closed_lock_with_key: | POST | `/api/v5/copytrading/amend-copy-settings` | -| [stopCopytradingCopy()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1753) | :closed_lock_with_key: | POST | `/api/v5/copytrading/stop-copy-trading` | -| [getCopytradingCopySettings()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1765) | :closed_lock_with_key: | GET | `/api/v5/copytrading/copy-settings` | -| [getCopytradingBatchLeverageInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1772) | :closed_lock_with_key: | GET | `/api/v5/copytrading/batch-leverage-info` | -| [setCopytradingBatchLeverage()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1778) | :closed_lock_with_key: | POST | `/api/v5/copytrading/batch-set-leverage` | -| [getCopytradingMyLeadTraders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1784) | :closed_lock_with_key: | GET | `/api/v5/copytrading/current-lead-traders` | -| [getCopytradingLeadTradersHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1790) | :closed_lock_with_key: | GET | `/api/v5/copytrading/lead-traders-history` | -| [getCopytradingConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1796) | | GET | `/api/v5/copytrading/public-config` | -| [getCopytradingLeadRanks()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1802) | | GET | `/api/v5/copytrading/public-lead-traders` | -| [getCopytradingLeadWeeklyPnl()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1808) | | GET | `/api/v5/copytrading/public-weekly-pnl` | -| [getCopytradingLeadDailyPnl()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1815) | | GET | `/api/v5/copytrading/public-pnl` | -| [getCopytradingLeadStats()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1821) | | GET | `/api/v5/copytrading/public-stats` | -| [getCopytradingLeadPreferences()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1827) | | GET | `/api/v5/copytrading/public-preference-currency` | -| [getCopytradingLeadOpenPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1834) | | GET | `/api/v5/copytrading/public-current-subpositions` | -| [getCopytradingLeadPositionHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1840) | | GET | `/api/v5/copytrading/public-subpositions-history` | -| [getCopyTraders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1846) | | GET | `/api/v5/copytrading/public-copy-traders` | -| [getCopytradingLeadPrivateRanks()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1852) | :closed_lock_with_key: | GET | `/api/v5/copytrading/lead-traders` | -| [getCopytradingLeadPrivateWeeklyPnl()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1858) | :closed_lock_with_key: | GET | `/api/v5/copytrading/weekly-pnl` | -| [getCopytradingPLeadPrivateDailyPnl()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1865) | :closed_lock_with_key: | GET | `/api/v5/copytrading/pnl` | -| [geCopytradingLeadPrivateStats()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1871) | :closed_lock_with_key: | GET | `/api/v5/copytrading/stats` | -| [getCopytradingLeadPrivatePreferences()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1877) | :closed_lock_with_key: | GET | `/api/v5/copytrading/preference-currency` | -| [getCopytradingLeadPrivateOpenPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1884) | :closed_lock_with_key: | GET | `/api/v5/copytrading/performance-current-subpositions` | -| [getCopytradingLeadPrivatePositionHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1893) | :closed_lock_with_key: | GET | `/api/v5/copytrading/performance-subpositions-history` | -| [getCopyTradersPrivate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1902) | :closed_lock_with_key: | GET | `/api/v5/copytrading/copy-traders` | -| [getTickers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1914) | | GET | `/api/v5/market/tickers` | -| [getTicker()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1922) | | GET | `/api/v5/market/ticker` | -| [getOrderBook()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1926) | | GET | `/api/v5/market/books` | -| [getRpiOrderBook()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1933) | | GET | `/api/v5/market/books-rpi` | -| [getFullOrderBook()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1940) | | GET | `/api/v5/market/books-full` | -| [getCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1947) | | GET | `/api/v5/market/candles` | -| [getHistoricCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1951) | | GET | `/api/v5/market/history-candles` | -| [getTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1955) | | GET | `/api/v5/market/trades` | -| [getHistoricTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1959) | | GET | `/api/v5/market/history-trades` | -| [getOptionTradesByInstrument()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1969) | | GET | `/api/v5/market/option/instrument-family-trades` | -| [getOptionTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1975) | | GET | `/api/v5/public/option-trades` | -| [get24hrTotalVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1979) | | GET | `/api/v5/market/platform-24-volume` | -| [getBlockCounterParties()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1989) | :closed_lock_with_key: | GET | `/api/v5/rfq/counterparties` | -| [createBlockRFQ()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1993) | :closed_lock_with_key: | POST | `/api/v5/rfq/create-rfq` | -| [cancelBlockRFQ()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1997) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-rfq` | -| [cancelMultipleBlockRFQs()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2003) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-batch-rfqs` | -| [cancelAllRFQs()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2009) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-all-rfqs` | -| [executeBlockQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2013) | :closed_lock_with_key: | POST | `/api/v5/rfq/execute-quote` | -| [getQuoteProducts()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2019) | :closed_lock_with_key: | GET | `/api/v5/rfq/maker-instrument-settings` | -| [updateBlockQuoteProducts()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2023) | :closed_lock_with_key: | POST | `/api/v5/rfq/maker-instrument-settings` | -| [resetBlockMmp()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2031) | :closed_lock_with_key: | POST | `/api/v5/rfq/mmp-reset` | -| [updateBlockMmpConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2039) | :closed_lock_with_key: | POST | `/api/v5/rfq/mmp-config` | -| [getBlockMmpConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2045) | :closed_lock_with_key: | GET | `/api/v5/rfq/mmp-config` | -| [createBlockQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2049) | :closed_lock_with_key: | POST | `/api/v5/rfq/create-quote` | -| [cancelBlockQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2055) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-quote` | -| [cancelMultipleBlockQuotes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2061) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-batch-quotes` | -| [cancelAllBlockQuotes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2067) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-all-quotes` | -| [cancelAllBlockAfter()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2071) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-all-after` | -| [getBlockRFQs()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2080) | :closed_lock_with_key: | GET | `/api/v5/rfq/rfqs` | -| [getBlockQuotes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2084) | :closed_lock_with_key: | GET | `/api/v5/rfq/quotes` | -| [getBlockTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2088) | :closed_lock_with_key: | GET | `/api/v5/rfq/trades` | -| [getPublicRFQBlockTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2092) | | GET | `/api/v5/rfq/public-trades` | -| [getBlockTickers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2096) | | GET | `/api/v5/market/block-tickers` | -| [getBlockTicker()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2103) | | GET | `/api/v5/market/block-ticker` | -| [getBlockPublicTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2107) | | GET | `/api/v5/public/block-trades` | -| [submitSpreadOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2119) | :closed_lock_with_key: | POST | `/api/v5/sprd/order` | -| [cancelSpreadOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2125) | :closed_lock_with_key: | POST | `/api/v5/sprd/cancel-order` | -| [cancelAllSpreadOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2132) | :closed_lock_with_key: | POST | `/api/v5/sprd/mass-cancel` | -| [updateSpreadOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2140) | :closed_lock_with_key: | POST | `/api/v5/sprd/amend-order` | -| [getSpreadOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2146) | :closed_lock_with_key: | GET | `/api/v5/sprd/order` | -| [getSpreadActiveOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2153) | :closed_lock_with_key: | GET | `/api/v5/sprd/orders-pending` | -| [getSpreadOrdersRecent()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2159) | :closed_lock_with_key: | GET | `/api/v5/sprd/orders-history` | -| [getSpreadOrdersArchive()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2165) | :closed_lock_with_key: | GET | `/api/v5/sprd/orders-history-archive` | -| [getSpreadTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2171) | :closed_lock_with_key: | GET | `/api/v5/sprd/trades` | -| [getSpreads()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2175) | | GET | `/api/v5/sprd/spreads` | -| [getSpreadOrderBook()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2179) | | GET | `/api/v5/sprd/books` | -| [getSpreadTicker()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2186) | | GET | `/api/v5/market/sprd-ticker` | -| [getSpreadPublicTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2190) | | GET | `/api/v5/sprd/public-trades` | -| [getSpreadCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2196) | | GET | `/api/v5/market/sprd-candles` | -| [getSpreadHistoryCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2200) | | GET | `/api/v5/market/sprd-history-candles` | -| [cancelSpreadAllAfter()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2206) | :closed_lock_with_key: | POST | `/api/v5/sprd/cancel-all-after` | -| [getInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2221) | | GET | `/api/v5/public/instruments` | -| [getEventContractSeries()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2229) | | GET | `/api/v5/public/event-contract/series` | -| [getEventContractEvents()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2239) | | GET | `/api/v5/public/event-contract/events` | -| [getEventContractMarkets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2249) | | GET | `/api/v5/public/event-contract/markets` | -| [getDeliveryExerciseHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2255) | | GET | `/api/v5/public/delivery-exercise-history` | -| [getOpenInterest()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2259) | | GET | `/api/v5/public/open-interest` | -| [getFundingRate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2263) | | GET | `/api/v5/public/funding-rate` | -| [getFundingRateHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2267) | | GET | `/api/v5/public/funding-rate-history` | -| [getMinMaxLimitPrice()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2273) | | GET | `/api/v5/public/price-limit` | -| [getOptionMarketData()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2277) | | GET | `/api/v5/public/opt-summary` | -| [getEstimatedDeliveryExercisePrice()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2285) | | GET | `/api/v5/public/estimated-price` | -| [getDiscountRateAndInterestFreeQuota()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2291) | | GET | `/api/v5/public/discount-rate-interest-free-quota` | -| [getSystemTime()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2295) | | GET | `/api/v5/public/time` | -| [getHistoricalMarketData()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2299) | | GET | `/api/v5/public/market-data-history` | -| [getMarkPrice()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2305) | | GET | `/api/v5/public/mark-price` | -| [getPositionTiers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2309) | | GET | `/api/v5/public/position-tiers` | -| [getInterestRateAndLoanQuota()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2313) | | GET | `/api/v5/public/interest-rate-loan-quota` | -| [getVIPInterestRateAndLoanQuota()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2317) | | GET | `/api/v5/public/vip-interest-rate-loan-quota` | -| [getUnderlying()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2321) | | GET | `/api/v5/public/underlying` | -| [getInsuranceFund()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2325) | | GET | `/api/v5/public/insurance-fund` | -| [getMmInstrumentTypes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2329) | | GET | `/api/v5/public/mm-instrument-types` | -| [getUnitConvert()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2336) | | GET | `/api/v5/public/convert-contract-coin` | -| [getOptionTickBands()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2340) | | GET | `/api/v5/public/instrument-tick-bands` | -| [getPremiumHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2347) | | GET | `/api/v5/public/premium-history` | -| [getIndexTickers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2351) | | GET | `/api/v5/market/index-tickers` | -| [getIndexCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2358) | | GET | `/api/v5/market/index-candles` | -| [getHistoricIndexCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2362) | | GET | `/api/v5/market/history-index-candles` | -| [getMarkPriceCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2366) | | GET | `/api/v5/market/mark-price-candles` | -| [getHistoricMarkPriceCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2370) | | GET | `/api/v5/market/history-mark-price-candles` | -| [getOracle()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2376) | | GET | `/api/v5/market/open-oracle` | -| [getExchangeRate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2380) | | GET | `/api/v5/market/exchange-rate` | -| [getIndexComponents()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2384) | | GET | `/api/v5/market/index-components` | -| [getEconomicCalendar()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2388) | :closed_lock_with_key: | GET | `/api/v5/public/economic-calendar` | -| [getPublicBlockTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2394) | | GET | `/api/v5/market/block-trades` | -| [getSupportCoin()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2404) | | GET | `/api/v5/rubik/stat/trading-data/support-coin` | -| [getOpenInterestHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2408) | | GET | `/api/v5/rubik/stat/contracts/open-interest-history` | -| [getTakerVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2417) | | GET | `/api/v5/rubik/stat/taker-volume` | -| [getContractTakerVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2427) | | GET | `/api/v5/rubik/stat/taker-volume-contract` | -| [getMarginLendingRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2433) | | GET | `/api/v5/rubik/stat/margin/loan-ratio` | -| [getTopTradersAccountRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2442) | | GET | `/api/v5/rubik/stat/contracts/long-short-account-ratio-contract-top-trader` | -| [getTopTradersContractPositionRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2451) | | GET | `/api/v5/rubik/stat/contracts/long-short-position-ratio-contract-top-trader` | -| [getLongShortContractRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2460) | | GET | `/api/v5/rubik/stat/contracts/long-short-account-ratio-contract` | -| [getLongShortRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2469) | | GET | `/api/v5/rubik/stat/contracts/long-short-account-ratio` | -| [getContractsOpenInterestAndVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2481) | | GET | `/api/v5/rubik/stat/contracts/open-interest-volume` | -| [getOptionsOpenInterestAndVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2493) | | GET | `/api/v5/rubik/stat/option/open-interest-volume` | -| [getPutCallRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2500) | | GET | `/api/v5/rubik/stat/option/open-interest-volume-ratio` | -| [getOpenInterestAndVolumeExpiry()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2510) | | GET | `/api/v5/rubik/stat/option/open-interest-volume-expiry` | -| [getOpenInterestAndVolumeStrike()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2520) | | GET | `/api/v5/rubik/stat/option/open-interest-volume-strike` | -| [getTakerFlow()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2531) | | GET | `/api/v5/rubik/stat/option/taker-block-volume` | -| [getCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2541) | :closed_lock_with_key: | GET | `/api/v5/asset/currencies` | -| [getBalances()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2545) | :closed_lock_with_key: | GET | `/api/v5/asset/balances` | -| [getNonTradableAssets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2549) | :closed_lock_with_key: | GET | `/api/v5/asset/non-tradable-assets` | -| [getAccountAssetValuation()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2553) | :closed_lock_with_key: | GET | `/api/v5/asset/asset-valuation` | -| [fundsTransfer()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2559) | :closed_lock_with_key: | POST | `/api/v5/asset/transfer` | -| [getFundsTransferState()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2564) | :closed_lock_with_key: | GET | `/api/v5/asset/transfer-state` | -| [getAssetBillsDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2575) | :closed_lock_with_key: | GET | `/api/v5/asset/bills` | -| [getAssetBillsHistoric()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2597) | :closed_lock_with_key: | GET | `/api/v5/asset/bills-history` | -| [getLightningDeposits()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2611) | :closed_lock_with_key: | GET | `/api/v5/asset/deposit-lightning` | -| [getDepositAddress()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2619) | :closed_lock_with_key: | GET | `/api/v5/asset/deposit-address` | -| [getDepositHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2623) | :closed_lock_with_key: | GET | `/api/v5/asset/deposit-history` | -| [submitWithdraw()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2629) | :closed_lock_with_key: | POST | `/api/v5/asset/withdrawal` | -| [submitWithdrawLightning()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2633) | :closed_lock_with_key: | POST | `/api/v5/asset/withdrawal-lightning` | -| [cancelWithdrawal()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2641) | :closed_lock_with_key: | POST | `/api/v5/asset/cancel-withdrawal` | -| [getWithdrawalHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2645) | :closed_lock_with_key: | GET | `/api/v5/asset/withdrawal-history` | -| [getDepositWithdrawStatus()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2649) | :closed_lock_with_key: | GET | `/api/v5/asset/deposit-withdraw-status` | -| [getExchanges()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2655) | | GET | `/api/v5/asset/exchange-list` | -| [applyForMonthlyStatement()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2659) | :closed_lock_with_key: | POST | `/api/v5/asset/monthly-statement` | -| [getMonthlyStatement()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2663) | :closed_lock_with_key: | GET | `/api/v5/asset/monthly-statement` | -| [getConvertCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2667) | :closed_lock_with_key: | GET | `/api/v5/asset/convert/currencies` | -| [getConvertCurrencyPair()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2671) | :closed_lock_with_key: | GET | `/api/v5/asset/convert/currency-pair` | -| [estimateConvertQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2680) | :closed_lock_with_key: | POST | `/api/v5/asset/convert/estimate-quote` | -| [convertTrade()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2684) | :closed_lock_with_key: | POST | `/api/v5/asset/convert/trade` | -| [getConvertHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2688) | :closed_lock_with_key: | GET | `/api/v5/asset/convert/history` | -| [getSubAccountList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2699) | :closed_lock_with_key: | GET | `/api/v5/users/subaccount/list` | -| [resetSubAccountAPIKey()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2703) | :closed_lock_with_key: | POST | `/api/v5/users/subaccount/modify-apikey` | -| [getSubAccountBalances()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2713) | :closed_lock_with_key: | GET | `/api/v5/account/subaccount/balances` | -| [getSubAccountFundingBalances()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2719) | :closed_lock_with_key: | GET | `/api/v5/asset/subaccount/balances` | -| [getSubAccountMaxWithdrawal()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2726) | :closed_lock_with_key: | GET | `/api/v5/account/subaccount/max-withdrawal` | -| [getSubAccountTransferHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2733) | :closed_lock_with_key: | GET | `/api/v5/asset/subaccount/bills` | -| [getManagedSubAccountTransferHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2744) | :closed_lock_with_key: | GET | `/api/v5/asset/subaccount/managed-subaccount-bills` | -| [transferSubAccountBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2754) | :closed_lock_with_key: | POST | `/api/v5/asset/subaccount/transfer` | -| [setSubAccountTransferOutPermission()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2760) | :closed_lock_with_key: | POST | `/api/v5/users/subaccount/set-transfer-out` | -| [getSubAccountCustodyTradingList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2770) | :closed_lock_with_key: | GET | `/api/v5/users/entrust-subaccount-list` | -| [setSubAccountLoanAllocation()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2776) | :closed_lock_with_key: | POST | `/api/v5/account/subaccount/set-loan-allocation` | -| [getSubAccountBorrowInterestAndLimit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2789) | :closed_lock_with_key: | GET | `/api/v5/account/subaccount/interest-limits` | -| [getStakingOffers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2806) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/offers` | -| [submitStake()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2814) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/purchase` | -| [redeemStake()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2825) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/redeem` | -| [cancelStakingRequest()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2833) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/cancel` | -| [getActiveStakingOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2841) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/orders-active` | -| [getStakingOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2854) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/orders-history` | -| [getETHStakingProductInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2874) | | GET | `/api/v5/finance/staking-defi/eth/product-info` | -| [getSOLStakingProductInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2878) | | GET | `/api/v5/finance/staking-defi/sol/product-info` | -| [purchaseETHStaking()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2882) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/eth/purchase` | -| [redeemETHStaking()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2889) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/eth/redeem` | -| [getETHStakingBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2893) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/eth/balance` | -| [getETHStakingHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2897) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/eth/purchase-redeem-history` | -| [cancelRedeemETHStaking()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2910) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/eth/cancel-redeem` | -| [getAPYHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2921) | | GET | `/api/v5/finance/staking-defi/eth/apy-history` | -| [getSavingBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2931) | :closed_lock_with_key: | GET | `/api/v5/finance/savings/balance` | -| [savingsPurchaseRedemption()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2935) | :closed_lock_with_key: | POST | `/api/v5/finance/savings/purchase-redempt` | -| [setLendingRate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2944) | :closed_lock_with_key: | POST | `/api/v5/finance/savings/set-lending-rate` | -| [getLendingHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2951) | :closed_lock_with_key: | GET | `/api/v5/finance/savings/lending-history` | -| [getPublicBorrowInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2955) | | GET | `/api/v5/finance/savings/lending-rate-summary` | -| [getPublicBorrowHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2959) | | GET | `/api/v5/finance/savings/lending-rate-history` | -| [getLendingOffers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2971) | | GET | `/api/v5/finance/fixed-loan/lending-offers` | -| [getLendingAPYHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2975) | | GET | `/api/v5/finance/fixed-loan/lending-apy-history` | -| [getLendingVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2979) | | GET | `/api/v5/finance/fixed-loan/pending-lending-volume` | -| [placeLendingOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2986) | :closed_lock_with_key: | POST | `/api/v5/finance/fixed-loan/lending-order` | -| [amendLendingOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2990) | :closed_lock_with_key: | POST | `/api/v5/finance/fixed-loan/amend-lending-order` | -| [getLendingOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2997) | :closed_lock_with_key: | GET | `/api/v5/finance/fixed-loan/lending-orders-list` | -| [getLendingSubOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3004) | :closed_lock_with_key: | GET | `/api/v5/finance/fixed-loan/lending-sub-orders` | -| [getBorrowableCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3017) | | GET | `/api/v5/finance/flexible-loan/borrow-currencies` | -| [getCollateralAssets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3025) | | GET | `/api/v5/finance/flexible-loan/collateral-assets` | -| [getMaxLoanAmount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3031) | :closed_lock_with_key: | POST | `/api/v5/finance/flexible-loan/max-loan` | -| [adjustCollateral()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3035) | :closed_lock_with_key: | POST | `/api/v5/finance/flexible-loan/adjust-collateral` | -| [getLoanInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3042) | :closed_lock_with_key: | GET | `/api/v5/finance/flexible-loan/loan-info` | -| [getLoanHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3046) | :closed_lock_with_key: | GET | `/api/v5/finance/flexible-loan/loan-history` | -| [getAccruedInterest()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3053) | :closed_lock_with_key: | GET | `/api/v5/finance/flexible-loan/interest-accrued` | -| [getDcdCurrencyPairs()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3069) | :closed_lock_with_key: | GET | `/api/v5/finance/sfp/dcd/currency-pair` | -| [getDcdProducts()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3073) | :closed_lock_with_key: | GET | `/api/v5/finance/sfp/dcd/products` | -| [requestDcdQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3077) | :closed_lock_with_key: | POST | `/api/v5/finance/sfp/dcd/quote` | -| [submitDcdTrade()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3081) | :closed_lock_with_key: | POST | `/api/v5/finance/sfp/dcd/trade` | -| [requestDcdRedeemQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3085) | :closed_lock_with_key: | POST | `/api/v5/finance/sfp/dcd/redeem-quote` | -| [submitDcdRedeem()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3091) | :closed_lock_with_key: | POST | `/api/v5/finance/sfp/dcd/redeem` | -| [getDcdOrderStatus()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3095) | :closed_lock_with_key: | GET | `/api/v5/finance/sfp/dcd/order-status` | -| [getDcdOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3101) | :closed_lock_with_key: | GET | `/api/v5/finance/sfp/dcd/order-history` | -| [getStableRewardsProductInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3114) | :closed_lock_with_key: | GET | `/api/v5/finance/stable-rewards/product-info` | -| [requestStableRewardsQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3124) | :closed_lock_with_key: | POST | `/api/v5/finance/stable-rewards/quote` | -| [submitStableRewardsTrade()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3131) | :closed_lock_with_key: | POST | `/api/v5/finance/stable-rewards/trade` | -| [getStableRewardsBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3137) | :closed_lock_with_key: | GET | `/api/v5/finance/stable-rewards/balance` | -| [getStableRewardsApyHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3143) | | GET | `/api/v5/finance/stable-rewards/apy-history` | -| [getStableRewardsSubscribeRedeemHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3150) | :closed_lock_with_key: | GET | `/api/v5/finance/stable-rewards/subscribe-redeem-history` | -| [getOkusdLimits()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3165) | :closed_lock_with_key: | GET | `/api/v5/finance/okusd/limits` | -| [subscribeOkusd()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3169) | :closed_lock_with_key: | POST | `/api/v5/finance/okusd/subscribe` | -| [redeemOkusd()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3175) | :closed_lock_with_key: | POST | `/api/v5/finance/okusd/redeem` | -| [getGlpTodayPerformance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3185) | :closed_lock_with_key: | GET | `/api/v5/users/glp/today-performance` | -| [getGlpHistoricalPerformance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3189) | :closed_lock_with_key: | GET | `/api/v5/users/glp/historical-performance` | -| [getAffiliatePerformanceSummary()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3202) | :closed_lock_with_key: | GET | `/api/v5/affiliate/performance/summary` | -| [getInviteeDetail()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3208) | :closed_lock_with_key: | GET | `/api/v5/affiliate/invitee/detail` | -| [getAffiliateInviteeList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3212) | :closed_lock_with_key: | GET | `/api/v5/affiliate/invitee/list` | -| [getAffiliateLinkList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3218) | :closed_lock_with_key: | GET | `/api/v5/affiliate/link/list` | -| [getAffiliateCoInviterLinkList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3224) | :closed_lock_with_key: | GET | `/api/v5/affiliate/co-inviter/list` | -| [getAffiliateSubAffiliateList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3230) | :closed_lock_with_key: | GET | `/api/v5/affiliate/sub-affiliate/list` | -| [getAffiliateRebateInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3236) | :closed_lock_with_key: | GET | `/api/v5/users/partner/if-rebate` | -| [getSystemStatus()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3246) | | GET | `/api/v5/system/status` | -| [getAnnouncements()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3258) | | GET | `/api/v5/support/announcements` | -| [getAnnouncementTypes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3267) | | GET | `/api/v5/support/announcement-types` | -| [createSubAccount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3282) | :closed_lock_with_key: | POST | `/api/v5/broker/nd/create-subaccount` | -| [deleteSubAccount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3291) | :closed_lock_with_key: | POST | `/api/v5/broker/nd/delete-subaccount` | -| [createSubAccountAPIKey()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3295) | :closed_lock_with_key: | POST | `/api/v5/broker/nd/subaccount/apikey` | +| [getAccountInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L503) | :closed_lock_with_key: | GET | `/api/v5/account/instruments` | +| [getBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L509) | :closed_lock_with_key: | GET | `/api/v5/account/balance` | +| [getPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L513) | :closed_lock_with_key: | GET | `/api/v5/account/positions` | +| [getPositionsHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L517) | :closed_lock_with_key: | GET | `/api/v5/account/positions-history` | +| [getAccountPositionRisk()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L523) | :closed_lock_with_key: | GET | `/api/v5/account/account-position-risk` | +| [getBills()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L530) | :closed_lock_with_key: | GET | `/api/v5/account/bills` | +| [getBillsArchive()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L535) | :closed_lock_with_key: | GET | `/api/v5/account/bills-archive` | +| [getAccountBillSubtypes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L543) | :closed_lock_with_key: | GET | `/api/v5/account/subtypes` | +| [requestBillsHistoryDownloadLink()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L557) | :closed_lock_with_key: | POST | `/api/v5/account/bills-history-archive` | +| [getRequestedBillsHistoryLink()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L566) | :closed_lock_with_key: | GET | `/api/v5/account/bills-history-archive` | +| [getAccountConfiguration()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L572) | :closed_lock_with_key: | GET | `/api/v5/account/config` | +| [setPositionMode()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L576) | :closed_lock_with_key: | POST | `/api/v5/account/set-position-mode` | +| [setSettleCurrency()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L582) | :closed_lock_with_key: | POST | `/api/v5/account/set-settle-currency` | +| [setFeeType()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L588) | :closed_lock_with_key: | POST | `/api/v5/account/set-fee-type` | +| [setLeverage()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L592) | :closed_lock_with_key: | POST | `/api/v5/account/set-leverage` | +| [getMaxBuySellAmount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L597) | :closed_lock_with_key: | GET | `/api/v5/account/max-size` | +| [getMaxAvailableTradableAmount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L610) | :closed_lock_with_key: | GET | `/api/v5/account/max-avail-size` | +| [changePositionMargin()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L620) | :closed_lock_with_key: | POST | `/api/v5/account/position/margin-balance` | +| [movePositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L631) | :closed_lock_with_key: | POST | `/api/v5/account/move-positions` | +| [getMovePositionsHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L639) | :closed_lock_with_key: | GET | `/api/v5/account/move-positions-history` | +| [getLeverage()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L645) | :closed_lock_with_key: | GET | `/api/v5/account/leverage-info` | +| [getLeverageV2()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L657) | :closed_lock_with_key: | GET | `/api/v5/account/leverage-info` | +| [getLeverageEstimatedInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L665) | :closed_lock_with_key: | GET | `/api/v5/account/adjust-leverage-info` | +| [getMaxLoan()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L676) | :closed_lock_with_key: | GET | `/api/v5/account/max-loan` | +| [getFeeRates()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L685) | :closed_lock_with_key: | GET | `/api/v5/account/trade-fee` | +| [getInterestAccrued()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L696) | :closed_lock_with_key: | GET | `/api/v5/account/interest-accrued` | +| [getInterestRate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L708) | :closed_lock_with_key: | GET | `/api/v5/account/interest-rate` | +| [setGreeksDisplayType()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L712) | :closed_lock_with_key: | POST | `/api/v5/account/set-greeks` | +| [setIsolatedMode()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L716) | :closed_lock_with_key: | POST | `/api/v5/account/set-isolated-mode` | +| [getMaxWithdrawals()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L723) | :closed_lock_with_key: | GET | `/api/v5/account/max-withdrawal` | +| [getAccountRiskState()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L727) | :closed_lock_with_key: | GET | `/api/v5/account/risk-state` | +| [setAccountCollateralAssets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L731) | :closed_lock_with_key: | POST | `/api/v5/account/set-collateral-assets` | +| [getAccountCollateralAssets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L745) | :closed_lock_with_key: | GET | `/api/v5/account/collateral-assets` | +| [submitQuickMarginBorrowRepay()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L757) | :closed_lock_with_key: | POST | `/api/v5/account/quick-margin-borrow-repay` | +| [getQuickMarginBorrowRepayHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L766) | :closed_lock_with_key: | GET | `/api/v5/account/quick-margin-borrow-repay-history` | +| [borrowRepayVIPLoan()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L775) | :closed_lock_with_key: | POST | `/api/v5/account/borrow-repay` | +| [getVIPLoanBorrowRepayHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L784) | :closed_lock_with_key: | GET | `/api/v5/account/borrow-repay-history` | +| [getVIPInterestAccrued()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L788) | :closed_lock_with_key: | GET | `/api/v5/account/vip-interest-accrued` | +| [getVIPInterestDeducted()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L792) | :closed_lock_with_key: | GET | `/api/v5/account/vip-interest-deducted` | +| [getVIPLoanOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L798) | :closed_lock_with_key: | GET | `/api/v5/account/vip-loan-order-list` | +| [getVIPLoanOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L804) | :closed_lock_with_key: | GET | `/api/v5/account/vip-loan-order-detail` | +| [getBorrowInterestLimits()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L810) | :closed_lock_with_key: | GET | `/api/v5/account/interest-limits` | +| [getFixedLoanBorrowLimit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L817) | :closed_lock_with_key: | GET | `/api/v5/account/fixed-loan/borrowing-limit` | +| [getFixedLoanBorrowQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L821) | :closed_lock_with_key: | GET | `/api/v5/account/fixed-loan/borrowing-quote` | +| [submitFixedLoanBorrowOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L830) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/borrowing-order` | +| [updateFixedLoanBorrowOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L843) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/amend-borrowing-order` | +| [manualRenewFixedLoanBorrowOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L856) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/manual-reborrow` | +| [repayFixedLoanBorrowOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L870) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/repay-borrowing-order` | +| [convertFixedLoanToMarketLoan()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L881) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/convert-to-market-loan` | +| [reduceFixedLoanLiabilities()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L892) | :closed_lock_with_key: | POST | `/api/v5/account/fixed-loan/reduce-liabilities` | +| [getFixedLoanBorrowOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L907) | :closed_lock_with_key: | GET | `/api/v5/account/fixed-loan/borrowing-orders-list` | +| [manualBorrowRepay()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L916) | :closed_lock_with_key: | POST | `/api/v5/account/spot-manual-borrow-repay` | +| [setAutoRepay()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L930) | :closed_lock_with_key: | POST | `/api/v5/account/set-auto-repay` | +| [getBorrowRepayHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L938) | :closed_lock_with_key: | GET | `/api/v5/account/spot-borrow-repay-history` | +| [positionBuilder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L944) | :closed_lock_with_key: | POST | `/api/v5/account/position-builder` | +| [updateRiskOffsetAmount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L948) | :closed_lock_with_key: | POST | `/api/v5/account/set-riskOffset-amt` | +| [getGreeks()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L960) | :closed_lock_with_key: | GET | `/api/v5/account/greeks` | +| [getPMLimitation()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L964) | :closed_lock_with_key: | GET | `/api/v5/account/position-tiers` | +| [updateRiskOffsetType()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L972) | :closed_lock_with_key: | POST | `/api/v5/account/set-riskOffset-type` | +| [activateOption()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L980) | :closed_lock_with_key: | POST | `/api/v5/account/activate-option` | +| [setAutoLoan()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L988) | :closed_lock_with_key: | POST | `/api/v5/account/set-auto-loan` | +| [presetAccountLevelSwitch()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L992) | :closed_lock_with_key: | POST | `/api/v5/account/account-level-switch-preset` | +| [getAccountSwitchPrecheck()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1003) | :closed_lock_with_key: | GET | `/api/v5/account/set-account-switch-precheck` | +| [setAccountMode()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1012) | :closed_lock_with_key: | POST | `/api/v5/account/set-account-level` | +| [resetMMPStatus()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1018) | :closed_lock_with_key: | POST | `/api/v5/account/mmp-reset` | +| [setMMPConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1026) | :closed_lock_with_key: | POST | `/api/v5/account/mmp-config` | +| [getMMPConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1030) | :closed_lock_with_key: | GET | `/api/v5/account/mmp-config` | +| [setTradingConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1034) | :closed_lock_with_key: | POST | `/api/v5/account/set-trading-config` | +| [precheckSetDeltaNeutral()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1040) | :closed_lock_with_key: | GET | `/api/v5/account/precheck-set-delta-neutral` | +| [submitOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1055) | :closed_lock_with_key: | POST | `/api/v5/trade/order` | +| [submitMultipleOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1059) | :closed_lock_with_key: | POST | `/api/v5/trade/batch-orders` | +| [cancelOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1063) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-order` | +| [cancelMultipleOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1067) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-batch-orders` | +| [amendOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1073) | :closed_lock_with_key: | POST | `/api/v5/trade/amend-order` | +| [amendMultipleOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1077) | :closed_lock_with_key: | POST | `/api/v5/trade/amend-batch-orders` | +| [closePositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1081) | :closed_lock_with_key: | POST | `/api/v5/trade/close-position` | +| [getOrderDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1085) | :closed_lock_with_key: | GET | `/api/v5/trade/order` | +| [getOrderList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1089) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-pending` | +| [getOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1096) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-history` | +| [getOrderHistoryArchive()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1103) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-history-archive` | +| [getFills()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1112) | :closed_lock_with_key: | GET | `/api/v5/trade/fills` | +| [getFillsHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1119) | :closed_lock_with_key: | GET | `/api/v5/trade/fills-history` | +| [getEasyConvertCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1124) | :closed_lock_with_key: | GET | `/api/v5/trade/easy-convert-currency-list` | +| [submitEasyConvert()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1137) | :closed_lock_with_key: | POST | `/api/v5/trade/easy-convert` | +| [getEasyConvertHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1146) | :closed_lock_with_key: | GET | `/api/v5/trade/easy-convert-history` | +| [getOneClickRepayCurrencyList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1155) | :closed_lock_with_key: | GET | `/api/v5/trade/one-click-repay-currency-list` | +| [submitOneClickRepay()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1169) | :closed_lock_with_key: | POST | `/api/v5/trade/one-click-repay` | +| [getOneClickRepayHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1177) | :closed_lock_with_key: | GET | `/api/v5/trade/one-click-repay-history` | +| [cancelMassOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1181) | :closed_lock_with_key: | POST | `/api/v5/trade/mass-cancel` | +| [cancelAllAfter()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1193) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-all-after` | +| [getAccountRateLimit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1200) | :closed_lock_with_key: | GET | `/api/v5/trade/account-rate-limit` | +| [submitOrderPrecheck()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1204) | :closed_lock_with_key: | POST | `/api/v5/trade/order-precheck` | +| [placeAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1214) | :closed_lock_with_key: | POST | `/api/v5/trade/order-algo` | +| [cancelAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1218) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-algos` | +| [amendAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1224) | :closed_lock_with_key: | POST | `/api/v5/trade/amend-algos` | +| [cancelAdvanceAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1230) | :closed_lock_with_key: | POST | `/api/v5/trade/cancel-advance-algos` | +| [getAlgoOrderDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1236) | :closed_lock_with_key: | GET | `/api/v5/trade/order-algo` | +| [getAlgoOrderList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1242) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-algo-pending` | +| [getAlgoOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1248) | :closed_lock_with_key: | GET | `/api/v5/trade/orders-algo-history` | +| [placeGridAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1260) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/order-algo` | +| [amendGridAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1264) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/amend-order-algo` | +| [stopGridAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1281) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/stop-order-algo` | +| [closeGridContractPosition()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1285) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/close-position` | +| [cancelGridContractCloseOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1291) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/cancel-close-order` | +| [instantTriggerGridAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1301) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/order-instant-trigger` | +| [getGridAlgoOrderList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1313) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/orders-algo-pending` | +| [getGridAlgoOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1320) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/orders-algo-history` | +| [getGridAlgoOrderDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1327) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/orders-algo-details` | +| [getGridAlgoSubOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1337) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/sub-orders` | +| [getGridAlgoOrderPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1349) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/grid/positions` | +| [spotGridWithdrawIncome()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1356) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/withdraw-income` | +| [computeGridMarginBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1360) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/compute-margin-balance` | +| [adjustGridMarginBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1371) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/margin-balance` | +| [adjustGridInvestment()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1380) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/grid/adjust-investment` | +| [getGridAIParameter()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1391) | | GET | `/api/v5/tradingBot/grid/ai-param` | +| [computeGridMinInvestment()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1400) | | POST | `/api/v5/tradingBot/grid/min-investment` | +| [getRSIBackTesting()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1407) | | GET | `/api/v5/tradingBot/public/rsi-back-testing` | +| [getMaxGridQuantity()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1415) | | GET | `/api/v5/tradingBot/grid/grid-quantity` | +| [createSignal()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1429) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/create-signal` | +| [getSignals()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1433) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/signals` | +| [createSignalBot()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1437) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/order-algo` | +| [cancelSignalBots()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1443) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/stop-order-algo` | +| [updateSignalMargin()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1452) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/margin-balance` | +| [updateSignalTPSL()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1460) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/amendTPSL` | +| [setSignalInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1468) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/set-instruments` | +| [getSignalBotOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1479) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/orders-algo-details` | +| [getActiveSignalBot()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1489) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/orders-algo-details` | +| [getSignalBotHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1496) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/orders-algo-history` | +| [getSignalBotPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1503) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/positions` | +| [getSignalBotPositionHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1510) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/positions-history` | +| [closeSignalBotPosition()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1519) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/close-position` | +| [placeSignalBotSubOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1527) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/sub-order` | +| [cancelSubOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1531) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/signal/cancel-sub-order` | +| [getSignalBotSubOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1538) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/sub-orders` | +| [getSignalBotEventHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1542) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/signal/event-history` | +| [submitRecurringBuyOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1554) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/recurring/order-algo` | +| [amendRecurringBuyOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1560) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/recurring/amend-order-algo` | +| [stopRecurringBuyOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1569) | :closed_lock_with_key: | POST | `/api/v5/tradingBot/recurring/stop-order-algo` | +| [getRecurringBuyOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1578) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/recurring/orders-algo-pending` | +| [getRecurringBuyOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1587) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/recurring/orders-algo-history` | +| [getRecurringBuyOrderDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1596) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/recurring/orders-algo-details` | +| [getRecurringBuySubOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1605) | :closed_lock_with_key: | GET | `/api/v5/tradingBot/recurring/sub-orders` | +| [getCopytradingSubpositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1617) | :closed_lock_with_key: | GET | `/api/v5/copytrading/current-subpositions` | +| [getCopytradingSubpositionsHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1623) | :closed_lock_with_key: | GET | `/api/v5/copytrading/subpositions-history` | +| [submitCopytradingAlgoOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1629) | :closed_lock_with_key: | POST | `/api/v5/copytrading/algo-order` | +| [closeCopytradingSubposition()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1635) | :closed_lock_with_key: | POST | `/api/v5/copytrading/close-subposition` | +| [getCopytradingInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1644) | :closed_lock_with_key: | GET | `/api/v5/copytrading/instruments` | +| [setCopytradingInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1653) | :closed_lock_with_key: | POST | `/api/v5/copytrading/set-instruments` | +| [getCopytradingProfitDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1665) | :closed_lock_with_key: | GET | `/api/v5/copytrading/profit-sharing-details` | +| [getCopytradingTotalProfit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1674) | :closed_lock_with_key: | GET | `/api/v5/copytrading/total-profit-sharing` | +| [getCopytradingUnrealizedProfit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1680) | :closed_lock_with_key: | GET | `/api/v5/copytrading/unrealized-profit-sharing-details` | +| [getCopytradingTotalUnrealizedProfit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1689) | :closed_lock_with_key: | GET | `/api/v5/copytrading/total-unrealized-profit-sharing` | +| [applyCopytradingLeadTrading()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1701) | :closed_lock_with_key: | POST | `/api/v5/copytrading/apply-lead-trading` | +| [stopCopytradingLeadTrading()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1712) | :closed_lock_with_key: | POST | `/api/v5/copytrading/stop-lead-trading` | +| [updateCopytradingProfitSharing()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1720) | :closed_lock_with_key: | POST | `/api/v5/copytrading/amend-profit-sharing-ratio` | +| [getCopytradingAccount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1734) | :closed_lock_with_key: | GET | `/api/v5/copytrading/config` | +| [setCopytradingFirstCopy()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1738) | :closed_lock_with_key: | POST | `/api/v5/copytrading/first-copy-settings` | +| [updateCopytradingCopySettings()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1746) | :closed_lock_with_key: | POST | `/api/v5/copytrading/amend-copy-settings` | +| [stopCopytradingCopy()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1754) | :closed_lock_with_key: | POST | `/api/v5/copytrading/stop-copy-trading` | +| [getCopytradingCopySettings()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1766) | :closed_lock_with_key: | GET | `/api/v5/copytrading/copy-settings` | +| [getCopytradingBatchLeverageInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1773) | :closed_lock_with_key: | GET | `/api/v5/copytrading/batch-leverage-info` | +| [setCopytradingBatchLeverage()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1779) | :closed_lock_with_key: | POST | `/api/v5/copytrading/batch-set-leverage` | +| [getCopytradingMyLeadTraders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1785) | :closed_lock_with_key: | GET | `/api/v5/copytrading/current-lead-traders` | +| [getCopytradingLeadTradersHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1791) | :closed_lock_with_key: | GET | `/api/v5/copytrading/lead-traders-history` | +| [getCopytradingConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1797) | | GET | `/api/v5/copytrading/public-config` | +| [getCopytradingLeadRanks()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1803) | | GET | `/api/v5/copytrading/public-lead-traders` | +| [getCopytradingLeadWeeklyPnl()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1809) | | GET | `/api/v5/copytrading/public-weekly-pnl` | +| [getCopytradingLeadDailyPnl()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1816) | | GET | `/api/v5/copytrading/public-pnl` | +| [getCopytradingLeadStats()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1822) | | GET | `/api/v5/copytrading/public-stats` | +| [getCopytradingLeadPreferences()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1828) | | GET | `/api/v5/copytrading/public-preference-currency` | +| [getCopytradingLeadOpenPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1835) | | GET | `/api/v5/copytrading/public-current-subpositions` | +| [getCopytradingLeadPositionHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1841) | | GET | `/api/v5/copytrading/public-subpositions-history` | +| [getCopyTraders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1847) | | GET | `/api/v5/copytrading/public-copy-traders` | +| [getCopytradingLeadPrivateRanks()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1853) | :closed_lock_with_key: | GET | `/api/v5/copytrading/lead-traders` | +| [getCopytradingLeadPrivateWeeklyPnl()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1859) | :closed_lock_with_key: | GET | `/api/v5/copytrading/weekly-pnl` | +| [getCopytradingPLeadPrivateDailyPnl()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1866) | :closed_lock_with_key: | GET | `/api/v5/copytrading/pnl` | +| [geCopytradingLeadPrivateStats()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1872) | :closed_lock_with_key: | GET | `/api/v5/copytrading/stats` | +| [getCopytradingLeadPrivatePreferences()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1878) | :closed_lock_with_key: | GET | `/api/v5/copytrading/preference-currency` | +| [getCopytradingLeadPrivateOpenPositions()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1885) | :closed_lock_with_key: | GET | `/api/v5/copytrading/performance-current-subpositions` | +| [getCopytradingLeadPrivatePositionHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1894) | :closed_lock_with_key: | GET | `/api/v5/copytrading/performance-subpositions-history` | +| [getCopyTradersPrivate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1903) | :closed_lock_with_key: | GET | `/api/v5/copytrading/copy-traders` | +| [getTickers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1915) | | GET | `/api/v5/market/tickers` | +| [getTicker()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1923) | | GET | `/api/v5/market/ticker` | +| [getOrderBook()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1927) | | GET | `/api/v5/market/books` | +| [getRpiOrderBook()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1934) | | GET | `/api/v5/market/books-rpi` | +| [getFullOrderBook()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1941) | | GET | `/api/v5/market/books-full` | +| [getCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1948) | | GET | `/api/v5/market/candles` | +| [getHistoricCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1952) | | GET | `/api/v5/market/history-candles` | +| [getTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1956) | | GET | `/api/v5/market/trades` | +| [getHistoricTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1960) | | GET | `/api/v5/market/history-trades` | +| [getOptionTradesByInstrument()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1970) | | GET | `/api/v5/market/option/instrument-family-trades` | +| [getOptionTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1976) | | GET | `/api/v5/public/option-trades` | +| [get24hrTotalVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1980) | | GET | `/api/v5/market/platform-24-volume` | +| [getBlockCounterParties()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1990) | :closed_lock_with_key: | GET | `/api/v5/rfq/counterparties` | +| [createBlockRFQ()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1994) | :closed_lock_with_key: | POST | `/api/v5/rfq/create-rfq` | +| [cancelBlockRFQ()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L1998) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-rfq` | +| [cancelMultipleBlockRFQs()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2004) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-batch-rfqs` | +| [cancelAllRFQs()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2010) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-all-rfqs` | +| [executeBlockQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2014) | :closed_lock_with_key: | POST | `/api/v5/rfq/execute-quote` | +| [getQuoteProducts()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2020) | :closed_lock_with_key: | GET | `/api/v5/rfq/maker-instrument-settings` | +| [updateBlockQuoteProducts()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2024) | :closed_lock_with_key: | POST | `/api/v5/rfq/maker-instrument-settings` | +| [resetBlockMmp()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2032) | :closed_lock_with_key: | POST | `/api/v5/rfq/mmp-reset` | +| [updateBlockMmpConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2040) | :closed_lock_with_key: | POST | `/api/v5/rfq/mmp-config` | +| [getBlockMmpConfig()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2046) | :closed_lock_with_key: | GET | `/api/v5/rfq/mmp-config` | +| [createBlockQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2050) | :closed_lock_with_key: | POST | `/api/v5/rfq/create-quote` | +| [cancelBlockQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2056) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-quote` | +| [cancelMultipleBlockQuotes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2062) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-batch-quotes` | +| [cancelAllBlockQuotes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2068) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-all-quotes` | +| [cancelAllBlockAfter()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2072) | :closed_lock_with_key: | POST | `/api/v5/rfq/cancel-all-after` | +| [getBlockRFQs()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2081) | :closed_lock_with_key: | GET | `/api/v5/rfq/rfqs` | +| [getBlockQuotes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2085) | :closed_lock_with_key: | GET | `/api/v5/rfq/quotes` | +| [getBlockTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2089) | :closed_lock_with_key: | GET | `/api/v5/rfq/trades` | +| [getPublicRFQBlockTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2093) | | GET | `/api/v5/rfq/public-trades` | +| [getBlockTickers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2097) | | GET | `/api/v5/market/block-tickers` | +| [getBlockTicker()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2104) | | GET | `/api/v5/market/block-ticker` | +| [getBlockPublicTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2108) | | GET | `/api/v5/public/block-trades` | +| [submitSpreadOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2120) | :closed_lock_with_key: | POST | `/api/v5/sprd/order` | +| [cancelSpreadOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2126) | :closed_lock_with_key: | POST | `/api/v5/sprd/cancel-order` | +| [cancelAllSpreadOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2133) | :closed_lock_with_key: | POST | `/api/v5/sprd/mass-cancel` | +| [updateSpreadOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2141) | :closed_lock_with_key: | POST | `/api/v5/sprd/amend-order` | +| [getSpreadOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2147) | :closed_lock_with_key: | GET | `/api/v5/sprd/order` | +| [getSpreadActiveOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2154) | :closed_lock_with_key: | GET | `/api/v5/sprd/orders-pending` | +| [getSpreadOrdersRecent()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2160) | :closed_lock_with_key: | GET | `/api/v5/sprd/orders-history` | +| [getSpreadOrdersArchive()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2166) | :closed_lock_with_key: | GET | `/api/v5/sprd/orders-history-archive` | +| [getSpreadTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2172) | :closed_lock_with_key: | GET | `/api/v5/sprd/trades` | +| [getSpreads()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2176) | | GET | `/api/v5/sprd/spreads` | +| [getSpreadOrderBook()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2180) | | GET | `/api/v5/sprd/books` | +| [getSpreadTicker()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2187) | | GET | `/api/v5/market/sprd-ticker` | +| [getSpreadPublicTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2191) | | GET | `/api/v5/sprd/public-trades` | +| [getSpreadCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2197) | | GET | `/api/v5/market/sprd-candles` | +| [getSpreadHistoryCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2201) | | GET | `/api/v5/market/sprd-history-candles` | +| [cancelSpreadAllAfter()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2207) | :closed_lock_with_key: | POST | `/api/v5/sprd/cancel-all-after` | +| [getInstruments()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2222) | | GET | `/api/v5/public/instruments` | +| [getEventContractSeries()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2230) | | GET | `/api/v5/public/event-contract/series` | +| [getEventContractEvents()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2240) | | GET | `/api/v5/public/event-contract/events` | +| [getEventContractMarkets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2250) | | GET | `/api/v5/public/event-contract/markets` | +| [getDeliveryExerciseHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2256) | | GET | `/api/v5/public/delivery-exercise-history` | +| [getOpenInterest()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2260) | | GET | `/api/v5/public/open-interest` | +| [getFundingRate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2264) | | GET | `/api/v5/public/funding-rate` | +| [getFundingRateHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2268) | | GET | `/api/v5/public/funding-rate-history` | +| [getMinMaxLimitPrice()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2274) | | GET | `/api/v5/public/price-limit` | +| [getOptionMarketData()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2278) | | GET | `/api/v5/public/opt-summary` | +| [getEstimatedDeliveryExercisePrice()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2286) | | GET | `/api/v5/public/estimated-price` | +| [getDiscountRateAndInterestFreeQuota()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2292) | | GET | `/api/v5/public/discount-rate-interest-free-quota` | +| [getSystemTime()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2296) | | GET | `/api/v5/public/time` | +| [getHistoricalMarketData()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2300) | | GET | `/api/v5/public/market-data-history` | +| [getMarkPrice()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2306) | | GET | `/api/v5/public/mark-price` | +| [getPositionTiers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2310) | | GET | `/api/v5/public/position-tiers` | +| [getInterestRateAndLoanQuota()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2314) | | GET | `/api/v5/public/interest-rate-loan-quota` | +| [getVIPInterestRateAndLoanQuota()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2318) | | GET | `/api/v5/public/vip-interest-rate-loan-quota` | +| [getUnderlying()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2322) | | GET | `/api/v5/public/underlying` | +| [getInsuranceFund()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2326) | | GET | `/api/v5/public/insurance-fund` | +| [getMmInstrumentTypes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2330) | | GET | `/api/v5/public/mm-instrument-types` | +| [getDeltaHedgeCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2337) | | GET | `/api/v5/public/delta-hedge-currencies` | +| [getUnitConvert()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2343) | | GET | `/api/v5/public/convert-contract-coin` | +| [getOptionTickBands()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2347) | | GET | `/api/v5/public/instrument-tick-bands` | +| [getPremiumHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2354) | | GET | `/api/v5/public/premium-history` | +| [getIndexTickers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2358) | | GET | `/api/v5/market/index-tickers` | +| [getIndexCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2365) | | GET | `/api/v5/market/index-candles` | +| [getHistoricIndexCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2369) | | GET | `/api/v5/market/history-index-candles` | +| [getMarkPriceCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2373) | | GET | `/api/v5/market/mark-price-candles` | +| [getHistoricMarkPriceCandles()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2377) | | GET | `/api/v5/market/history-mark-price-candles` | +| [getOracle()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2383) | | GET | `/api/v5/market/open-oracle` | +| [getExchangeRate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2387) | | GET | `/api/v5/market/exchange-rate` | +| [getIndexComponents()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2391) | | GET | `/api/v5/market/index-components` | +| [getEconomicCalendar()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2395) | :closed_lock_with_key: | GET | `/api/v5/public/economic-calendar` | +| [getPublicBlockTrades()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2401) | | GET | `/api/v5/market/block-trades` | +| [getSupportCoin()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2411) | | GET | `/api/v5/rubik/stat/trading-data/support-coin` | +| [getOpenInterestHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2415) | | GET | `/api/v5/rubik/stat/contracts/open-interest-history` | +| [getTakerVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2424) | | GET | `/api/v5/rubik/stat/taker-volume` | +| [getContractTakerVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2434) | | GET | `/api/v5/rubik/stat/taker-volume-contract` | +| [getMarginLendingRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2440) | | GET | `/api/v5/rubik/stat/margin/loan-ratio` | +| [getTopTradersAccountRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2449) | | GET | `/api/v5/rubik/stat/contracts/long-short-account-ratio-contract-top-trader` | +| [getTopTradersContractPositionRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2458) | | GET | `/api/v5/rubik/stat/contracts/long-short-position-ratio-contract-top-trader` | +| [getLongShortContractRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2467) | | GET | `/api/v5/rubik/stat/contracts/long-short-account-ratio-contract` | +| [getLongShortRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2476) | | GET | `/api/v5/rubik/stat/contracts/long-short-account-ratio` | +| [getContractsOpenInterestAndVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2488) | | GET | `/api/v5/rubik/stat/contracts/open-interest-volume` | +| [getOptionsOpenInterestAndVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2500) | | GET | `/api/v5/rubik/stat/option/open-interest-volume` | +| [getPutCallRatio()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2507) | | GET | `/api/v5/rubik/stat/option/open-interest-volume-ratio` | +| [getOpenInterestAndVolumeExpiry()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2517) | | GET | `/api/v5/rubik/stat/option/open-interest-volume-expiry` | +| [getOpenInterestAndVolumeStrike()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2527) | | GET | `/api/v5/rubik/stat/option/open-interest-volume-strike` | +| [getTakerFlow()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2538) | | GET | `/api/v5/rubik/stat/option/taker-block-volume` | +| [getCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2548) | :closed_lock_with_key: | GET | `/api/v5/asset/currencies` | +| [getBalances()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2552) | :closed_lock_with_key: | GET | `/api/v5/asset/balances` | +| [getNonTradableAssets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2556) | :closed_lock_with_key: | GET | `/api/v5/asset/non-tradable-assets` | +| [getAccountAssetValuation()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2560) | :closed_lock_with_key: | GET | `/api/v5/asset/asset-valuation` | +| [fundsTransfer()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2566) | :closed_lock_with_key: | POST | `/api/v5/asset/transfer` | +| [getFundsTransferState()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2571) | :closed_lock_with_key: | GET | `/api/v5/asset/transfer-state` | +| [getAssetBillsDetails()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2582) | :closed_lock_with_key: | GET | `/api/v5/asset/bills` | +| [getAssetBillsHistoric()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2604) | :closed_lock_with_key: | GET | `/api/v5/asset/bills-history` | +| [getLightningDeposits()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2618) | :closed_lock_with_key: | GET | `/api/v5/asset/deposit-lightning` | +| [getDepositAddress()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2626) | :closed_lock_with_key: | GET | `/api/v5/asset/deposit-address` | +| [getDepositHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2630) | :closed_lock_with_key: | GET | `/api/v5/asset/deposit-history` | +| [submitWithdraw()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2636) | :closed_lock_with_key: | POST | `/api/v5/asset/withdrawal` | +| [submitWithdrawLightning()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2640) | :closed_lock_with_key: | POST | `/api/v5/asset/withdrawal-lightning` | +| [cancelWithdrawal()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2648) | :closed_lock_with_key: | POST | `/api/v5/asset/cancel-withdrawal` | +| [getWithdrawalHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2652) | :closed_lock_with_key: | GET | `/api/v5/asset/withdrawal-history` | +| [getDepositWithdrawStatus()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2656) | :closed_lock_with_key: | GET | `/api/v5/asset/deposit-withdraw-status` | +| [getExchanges()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2662) | | GET | `/api/v5/asset/exchange-list` | +| [applyForMonthlyStatement()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2666) | :closed_lock_with_key: | POST | `/api/v5/asset/monthly-statement` | +| [getMonthlyStatement()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2670) | :closed_lock_with_key: | GET | `/api/v5/asset/monthly-statement` | +| [getConvertCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2674) | :closed_lock_with_key: | GET | `/api/v5/asset/convert/currencies` | +| [getConvertCurrencyPair()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2678) | :closed_lock_with_key: | GET | `/api/v5/asset/convert/currency-pair` | +| [estimateConvertQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2687) | :closed_lock_with_key: | POST | `/api/v5/asset/convert/estimate-quote` | +| [convertTrade()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2691) | :closed_lock_with_key: | POST | `/api/v5/asset/convert/trade` | +| [getConvertHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2695) | :closed_lock_with_key: | GET | `/api/v5/asset/convert/history` | +| [getSubAccountList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2706) | :closed_lock_with_key: | GET | `/api/v5/users/subaccount/list` | +| [resetSubAccountAPIKey()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2710) | :closed_lock_with_key: | POST | `/api/v5/users/subaccount/modify-apikey` | +| [getSubAccountBalances()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2720) | :closed_lock_with_key: | GET | `/api/v5/account/subaccount/balances` | +| [getSubAccountFundingBalances()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2726) | :closed_lock_with_key: | GET | `/api/v5/asset/subaccount/balances` | +| [getSubAccountMaxWithdrawal()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2733) | :closed_lock_with_key: | GET | `/api/v5/account/subaccount/max-withdrawal` | +| [getSubAccountTransferHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2740) | :closed_lock_with_key: | GET | `/api/v5/asset/subaccount/bills` | +| [getManagedSubAccountTransferHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2751) | :closed_lock_with_key: | GET | `/api/v5/asset/subaccount/managed-subaccount-bills` | +| [transferSubAccountBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2761) | :closed_lock_with_key: | POST | `/api/v5/asset/subaccount/transfer` | +| [setSubAccountTransferOutPermission()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2767) | :closed_lock_with_key: | POST | `/api/v5/users/subaccount/set-transfer-out` | +| [getSubAccountCustodyTradingList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2777) | :closed_lock_with_key: | GET | `/api/v5/users/entrust-subaccount-list` | +| [setSubAccountLoanAllocation()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2783) | :closed_lock_with_key: | POST | `/api/v5/account/subaccount/set-loan-allocation` | +| [getSubAccountBorrowInterestAndLimit()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2796) | :closed_lock_with_key: | GET | `/api/v5/account/subaccount/interest-limits` | +| [getStakingOffers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2813) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/offers` | +| [submitStake()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2821) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/purchase` | +| [redeemStake()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2832) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/redeem` | +| [cancelStakingRequest()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2840) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/cancel` | +| [getActiveStakingOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2848) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/orders-active` | +| [getStakingOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2861) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/orders-history` | +| [getETHStakingProductInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2881) | | GET | `/api/v5/finance/staking-defi/eth/product-info` | +| [getSOLStakingProductInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2885) | | GET | `/api/v5/finance/staking-defi/sol/product-info` | +| [purchaseETHStaking()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2889) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/eth/purchase` | +| [redeemETHStaking()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2896) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/eth/redeem` | +| [getETHStakingBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2900) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/eth/balance` | +| [getETHStakingHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2904) | :closed_lock_with_key: | GET | `/api/v5/finance/staking-defi/eth/purchase-redeem-history` | +| [cancelRedeemETHStaking()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2917) | :closed_lock_with_key: | POST | `/api/v5/finance/staking-defi/eth/cancel-redeem` | +| [getAPYHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2928) | | GET | `/api/v5/finance/staking-defi/eth/apy-history` | +| [getSavingBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2938) | :closed_lock_with_key: | GET | `/api/v5/finance/savings/balance` | +| [savingsPurchaseRedemption()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2942) | :closed_lock_with_key: | POST | `/api/v5/finance/savings/purchase-redempt` | +| [setLendingRate()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2951) | :closed_lock_with_key: | POST | `/api/v5/finance/savings/set-lending-rate` | +| [getLendingHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2958) | :closed_lock_with_key: | GET | `/api/v5/finance/savings/lending-history` | +| [getPublicBorrowInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2962) | | GET | `/api/v5/finance/savings/lending-rate-summary` | +| [getPublicBorrowHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2966) | | GET | `/api/v5/finance/savings/lending-rate-history` | +| [getLendingOffers()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2978) | | GET | `/api/v5/finance/fixed-loan/lending-offers` | +| [getLendingAPYHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2982) | | GET | `/api/v5/finance/fixed-loan/lending-apy-history` | +| [getLendingVolume()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2986) | | GET | `/api/v5/finance/fixed-loan/pending-lending-volume` | +| [placeLendingOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2993) | :closed_lock_with_key: | POST | `/api/v5/finance/fixed-loan/lending-order` | +| [amendLendingOrder()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L2997) | :closed_lock_with_key: | POST | `/api/v5/finance/fixed-loan/amend-lending-order` | +| [getLendingOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3004) | :closed_lock_with_key: | GET | `/api/v5/finance/fixed-loan/lending-orders-list` | +| [getLendingSubOrders()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3011) | :closed_lock_with_key: | GET | `/api/v5/finance/fixed-loan/lending-sub-orders` | +| [getBorrowableCurrencies()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3024) | | GET | `/api/v5/finance/flexible-loan/borrow-currencies` | +| [getCollateralAssets()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3032) | | GET | `/api/v5/finance/flexible-loan/collateral-assets` | +| [getMaxLoanAmount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3038) | :closed_lock_with_key: | POST | `/api/v5/finance/flexible-loan/max-loan` | +| [adjustCollateral()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3042) | :closed_lock_with_key: | POST | `/api/v5/finance/flexible-loan/adjust-collateral` | +| [getLoanInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3049) | :closed_lock_with_key: | GET | `/api/v5/finance/flexible-loan/loan-info` | +| [getLoanHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3053) | :closed_lock_with_key: | GET | `/api/v5/finance/flexible-loan/loan-history` | +| [getAccruedInterest()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3060) | :closed_lock_with_key: | GET | `/api/v5/finance/flexible-loan/interest-accrued` | +| [getDcdCurrencyPairs()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3076) | :closed_lock_with_key: | GET | `/api/v5/finance/sfp/dcd/currency-pair` | +| [getDcdProducts()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3080) | :closed_lock_with_key: | GET | `/api/v5/finance/sfp/dcd/products` | +| [requestDcdQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3084) | :closed_lock_with_key: | POST | `/api/v5/finance/sfp/dcd/quote` | +| [submitDcdTrade()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3088) | :closed_lock_with_key: | POST | `/api/v5/finance/sfp/dcd/trade` | +| [requestDcdRedeemQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3092) | :closed_lock_with_key: | POST | `/api/v5/finance/sfp/dcd/redeem-quote` | +| [submitDcdRedeem()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3098) | :closed_lock_with_key: | POST | `/api/v5/finance/sfp/dcd/redeem` | +| [getDcdOrderStatus()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3102) | :closed_lock_with_key: | GET | `/api/v5/finance/sfp/dcd/order-status` | +| [getDcdOrderHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3108) | :closed_lock_with_key: | GET | `/api/v5/finance/sfp/dcd/order-history` | +| [getStableRewardsProductInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3121) | :closed_lock_with_key: | GET | `/api/v5/finance/stable-rewards/product-info` | +| [requestStableRewardsQuote()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3131) | :closed_lock_with_key: | POST | `/api/v5/finance/stable-rewards/quote` | +| [submitStableRewardsTrade()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3138) | :closed_lock_with_key: | POST | `/api/v5/finance/stable-rewards/trade` | +| [getStableRewardsBalance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3144) | :closed_lock_with_key: | GET | `/api/v5/finance/stable-rewards/balance` | +| [getStableRewardsApyHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3150) | | GET | `/api/v5/finance/stable-rewards/apy-history` | +| [getStableRewardsSubscribeRedeemHistory()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3157) | :closed_lock_with_key: | GET | `/api/v5/finance/stable-rewards/subscribe-redeem-history` | +| [getOkusdLimits()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3172) | :closed_lock_with_key: | GET | `/api/v5/finance/okusd/limits` | +| [subscribeOkusd()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3176) | :closed_lock_with_key: | POST | `/api/v5/finance/okusd/subscribe` | +| [redeemOkusd()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3182) | :closed_lock_with_key: | POST | `/api/v5/finance/okusd/redeem` | +| [getGlpTodayPerformance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3192) | :closed_lock_with_key: | GET | `/api/v5/users/glp/today-performance` | +| [getGlpHistoricalPerformance()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3196) | :closed_lock_with_key: | GET | `/api/v5/users/glp/historical-performance` | +| [getAffiliatePerformanceSummary()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3209) | :closed_lock_with_key: | GET | `/api/v5/affiliate/performance/summary` | +| [getInviteeDetail()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3215) | :closed_lock_with_key: | GET | `/api/v5/affiliate/invitee/detail` | +| [getAffiliateInviteeList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3219) | :closed_lock_with_key: | GET | `/api/v5/affiliate/invitee/list` | +| [getAffiliateLinkList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3225) | :closed_lock_with_key: | GET | `/api/v5/affiliate/link/list` | +| [getAffiliateCoInviterLinkList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3231) | :closed_lock_with_key: | GET | `/api/v5/affiliate/co-inviter/list` | +| [getAffiliateSubAffiliateList()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3237) | :closed_lock_with_key: | GET | `/api/v5/affiliate/sub-affiliate/list` | +| [getAffiliateRebateInfo()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3243) | :closed_lock_with_key: | GET | `/api/v5/users/partner/if-rebate` | +| [getSystemStatus()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3253) | | GET | `/api/v5/system/status` | +| [getAnnouncements()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3265) | | GET | `/api/v5/support/announcements` | +| [getAnnouncementTypes()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3274) | | GET | `/api/v5/support/announcement-types` | +| [createSubAccount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3289) | :closed_lock_with_key: | POST | `/api/v5/broker/nd/create-subaccount` | +| [deleteSubAccount()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3298) | :closed_lock_with_key: | POST | `/api/v5/broker/nd/delete-subaccount` | +| [createSubAccountAPIKey()](https://github.com/sieblyio/okx-api/blob/master/src/rest-client.ts#L3302) | :closed_lock_with_key: | POST | `/api/v5/broker/nd/subaccount/apikey` | # websocket-api-client.ts diff --git a/examples/apidoc/RestClient/getDeltaHedgeCurrencies.js b/examples/apidoc/RestClient/getDeltaHedgeCurrencies.js new file mode 100644 index 0000000..f39f3c4 --- /dev/null +++ b/examples/apidoc/RestClient/getDeltaHedgeCurrencies.js @@ -0,0 +1,23 @@ +import { RestClient } from 'okx-api'; +// or, if require is preferred: +// const { RestClient } = require('okx-api'); + +// This example shows how to call this OKX API endpoint with either node.js, javascript (js) or typescript (ts) with the npm module "okx-api" for OKX exchange +// This OKX API SDK is available on npm via "npm install okx-api" +// ENDPOINT: /api/v5/public/delta-hedge-currencies +// METHOD: GET +// PUBLIC: YES + +const client = new RestClient({ + apiKey: 'apiKeyHere', + apiSecret: 'apiSecretHere', + apiPass: 'apiPassHere', +}); + +client.getDeltaHedgeCurrencies(params) + .then((response) => { + console.log(response); + }) + .catch((error) => { + console.error(error); + }); diff --git a/llms.txt b/llms.txt index f3d3829..a8100a6 100644 --- a/llms.txt +++ b/llms.txt @@ -131,6 +131,7 @@ webpack/ .eslintrc.cjs .gitignore .jshintrc +.npmrc .nvmrc .prettierrc jest.config.ts @@ -301,6 +302,114 @@ export enum ASSET_BILL_TYPE { ⋮---- export type AssetBillType = `${ASSET_BILL_TYPE}`; +================ +File: src/types/rest/request/block-trading.ts +================ +import { OrderSide, RFQLeg } from '../shared.js'; +export interface AccountAllocationLeg { + sz: string; + instId: string; + tdMode?: string; + ccy?: string; + posSide?: string; +} +⋮---- +export interface AccountAllocation { + acct: string; + legs: AccountAllocationLeg[]; +} +⋮---- +export interface CreateBlockRFQRequest { + counterparties: string[]; + anonymous?: boolean; + clRfqId?: string; + tag?: string; + allowPartialExecution?: boolean; + legs: RFQLeg[]; + acctAlloc?: AccountAllocation[]; +} +⋮---- +export interface CancelBlockRFQRequest { + rfqId?: string; + clRfqId?: string; +} +⋮---- +export interface CancelMultipleBlockRFQRequest { + rfqIds?: string[]; + clRfqIds?: string[]; +} +⋮---- +export interface ExecuteBlockQuoteRequest { + rfqId: string; + quoteId: string; +} +⋮---- +export interface CreateBlockQuoteLeg { + px: string; + sz: string; + instId: string; + side: OrderSide; + tgtCcy?: 'base_ccy' | 'quote_ccy'; +} +⋮---- +export interface CreateBlockQuoteRequest { + rfqId: string; + clQuoteId?: string; + quoteSide: OrderSide; + anonymous?: boolean; + expiresIn?: string; + legs: CreateBlockQuoteLeg[]; +} +⋮---- +export interface CancelBlockQuoteRequest { + quoteId?: string; + clQuoteId?: string; +} +⋮---- +export interface CancelMultipleBlockQuoteRequest { + quoteIds?: string[]; + clQuoteIds?: string[]; +} +⋮---- +export interface GetBlockRFQSParams { + rfqId?: string; + clRfqId?: string; + state?: string; + beginId?: string; + endId?: string; + limit?: string; +} +⋮---- +export interface GetBlockQuoteParams { + rfqId?: string; + clRfqId?: string; + quoteId?: string; + clQuoteId?: string; + state?: string; + beginId?: string; + endId?: string; + limit?: string; +} +⋮---- +export interface MakerInstrumentData { + uly?: string; + instId?: string; + maxBlockSz?: string; + makerPxBand?: string; +} +⋮---- +export interface SetQuoteProductsRequest { + instType: string; + includeAll?: boolean; + data: MakerInstrumentData[]; +} +⋮---- +export interface SetMmpConfigRequest { + timeInterval: string; + frozenInterval: string; + countLimit: string; +} + ================ File: src/types/rest/request/copy-trading.ts ================ @@ -834,110 +943,336 @@ export interface SetSubAccountLoanAllocationRequest { } ================ -File: src/types/rest/response/private-copy-trading.ts +File: src/types/rest/response/private-block-trading.ts ================ -export interface CurrentSubposition { - algoId: string; - ccy: string; - instId: string; - instType: string; - lever: string; - margin: string; - markPx: string; - mgnMode: string; - openAvgPx: string; - openOrdId: string; - openTime: string; - posSide: string; - slOrdPx: string; - slTriggerPx: string; - subPos: string; - subPosId: string; - tpOrdPx: string; - tpTriggerPx: string; - uniqueCode: string; - upl: string; - uplRatio: string; - availSubPos: string; +import { RFQLeg, RFQQuoteLegExtended } from '../shared.js'; +⋮---- +export interface BlockCounterParty { + traderName: string; + traderCode: string; + type: never; // Currently not live } ⋮---- -export interface SubpositionsHistory { - ccy: string; - closeAvgPx: string; - closeTime: string; +type: never; // Currently not live +⋮---- +export interface AccountAllocationLegResult { instId: string; - instType: string; - lever: string; - margin: string; - markPx: string; - mgnMode: string; - openAvgPx: string; - openOrdId: string; - openTime: string; - pnl: string; - pnlRatio: string; + sz: string; + tdMode: string; + ccy: string; posSide: string; - profitSharingAmt: string; - subPos: string; - closeSubPos: string; - type: string; - subPosId: string; - uniqueCode: string; } -⋮---- -export interface PlaceCTAlgoOrderResult { - subPosId: string; - tag: string; +export interface AccountAllocationResult { + acct: string; + sCode: string; + sMsg: string; + legs: AccountAllocationLegResult[]; } ⋮---- -export interface GetCTProfitDetailsResult { - ccy: string; - nickName: string; - profitSharingAmt: string; - profitSharingId: string; - portLink: string; - ts: string; - instType: string; +export interface CreateRFQResult { + cTime: string; + uTime: string; + traderCode: string; + rfqId: string; + clRfqId: string; + state: string; + validUntil: string; + counterparties: string[]; + legs: Required[]; + groupId?: string; + acctAlloc?: AccountAllocationResult[]; } ⋮---- -export interface GetCTTotalProfitResult { - ccy: string; - totalProfitSharingAmt: string; - instType: string; +export interface CancelBlockRFQResult { + rfqId: string; + clRfqId: string; + sCode: string; + sMsg: string; } ⋮---- -export interface GetCTUnrealizedProfitResult { - ccy: string; - nickName: string; - portLink: string; - ts: string; - unrealizedProfitSharingAmt: string; - instType: string; +export interface AccountAllocationLegExecutionResult { + instId: string; + sz: string; + fee: string; + feeCcy: string; + tradeId: string; } ⋮---- -export interface AccountConfigurationDetails { - copyTraderNum: string; - instType: 'SPOT' | 'SWAP'; - maxCopyTraderNum: string; - profitSharingRatio: string; - roleType: '0' | '1' | '2'; +export interface AccountAllocationExecutionResult { + acct: string; + blockTdId: string; + sCode: string; + sMsg: string; + legs: AccountAllocationLegExecutionResult[]; } -⋮---- -export interface GetAccountConfigurationResult { - uniqueCode: string; - nickName: string; - portLink: string; - details: AccountConfigurationDetails[]; +export interface ExecuteBlockQuoteResult { + blockTdId: string; + rfqId: string; + clRfqId: string; + quoteId: string; + clQuoteId: string; + tTraderCode: string; + mTraderCode: string; + cTime: string; + tag?: string; + legs: RFQQuoteLegExtended[]; + acctAlloc?: AccountAllocationExecutionResult[]; } ⋮---- -export interface CopySettingsInstId { +export interface CreatedBlockQuoteLeg { + px: string; + sz: string; instId: string; - enabled: string; + side: string; + tgtCcy: string; } ⋮---- -export interface GetCopySettingsResult { - ccy: string; - copyAmt: string; +export interface CreateBlockQuoteResult { + cTime: string; + uTime: string; + quoteId: string; + clQuoteId: string; + rfqId: string; + quoteSide: string; + state: string; + validUntil: string; + legs: CreatedBlockQuoteLeg[]; +} +⋮---- +export interface CancelBlockQuoteResult { + rfqId: string; + clQuoteId: string; + sCode: string; + sMsg: string; +} +⋮---- +export interface BlockRFQResult { + rfqId: string; + clRfqId: string; + traderCode: string; + validUntil: string; + state: string; + counterparties: string[]; + legs: Required[]; + cTime: string; + uTime: string; + allowPartialExecution?: boolean; + groupId?: string; + acctAlloc?: AccountAllocationResult[]; +} +⋮---- +export interface BlockQuoteLeg { + px: string; + sz: string; + instId: string; + side: string; + tgtCcy: string; +} +⋮---- +export interface GetBlockQuoteResult { + validUntil: string; + uTime: string; + cTime: string; + legs: BlockQuoteLeg[]; + quoteId: string; + rfqId: string; + quoteSide: string; + state: string; + clQuoteId: string; + clRfqId: string; + traderCode: string; +} +⋮---- +export interface BlockMakerInstrumentData { + uly?: string; + instId?: string; + maxBlockSz?: string; + makerPxBand?: string; +} +⋮---- +export interface AccountAllocationTradeLegResult { + instId: string; + sz: string; + tradeId: string; + fee: string; + feeCcy: string; +} +export interface AccountAllocationTradeResult { + blockTdId: string; + errorCode: string; + acct: string; + legs: AccountAllocationTradeLegResult[]; +} +⋮---- +export interface BlockTradeLeg { + instId: string; + side: string; + sz: string; + px: string; + tradeId: string; + fee: string; + feeCcy: string; + tradeQuoteCcy?: string; +} +⋮---- +export interface BlockTradeResult { + rfqId: string; + clRfqId: string; + quoteId: string; + clQuoteId: string; + blockTdId: string; + tag: string; + isSuccessful: boolean; + errorCode: string; + cTime: string; + tTraderCode: string; + mTraderCode: string; + legs: BlockTradeLeg[]; + groupId?: string; + acctAlloc?: AccountAllocationTradeResult[]; +} +⋮---- +export interface BlockMakerInstrumentSettings { + instType: string; + includeALL: boolean; + data: BlockMakerInstrumentData[]; +} +⋮---- +export interface SetMmpConfigResult { + timeInterval: string; + frozenInterval: string; + countLimit: string; +} +⋮---- +export interface BlockMMPConfig { + frozenInterval: string; + mmpFrozen: boolean; + mmpFrozenUntil: string; + countLimit: string; + timeInterval: string; +} +⋮---- +export interface PublicBlockTradeLeg { + instId: string; + tradeId: string; + px: string; + sz: string; + side: 'buy' | 'sell'; +} +⋮---- +export interface PublicBlockTrade { + blockTdId: string; + groupId?: string; + legs: PublicBlockTradeLeg[]; + strategy?: string; + cTime: string; +} + +================ +File: src/types/rest/response/private-copy-trading.ts +================ +export interface CurrentSubposition { + algoId: string; + ccy: string; + instId: string; + instType: string; + lever: string; + margin: string; + markPx: string; + mgnMode: string; + openAvgPx: string; + openOrdId: string; + openTime: string; + posSide: string; + slOrdPx: string; + slTriggerPx: string; + subPos: string; + subPosId: string; + tpOrdPx: string; + tpTriggerPx: string; + uniqueCode: string; + upl: string; + uplRatio: string; + availSubPos: string; +} +⋮---- +export interface SubpositionsHistory { + ccy: string; + closeAvgPx: string; + closeTime: string; + instId: string; + instType: string; + lever: string; + margin: string; + markPx: string; + mgnMode: string; + openAvgPx: string; + openOrdId: string; + openTime: string; + pnl: string; + pnlRatio: string; + posSide: string; + profitSharingAmt: string; + subPos: string; + closeSubPos: string; + type: string; + subPosId: string; + uniqueCode: string; +} +⋮---- +export interface PlaceCTAlgoOrderResult { + subPosId: string; + tag: string; +} +⋮---- +export interface GetCTProfitDetailsResult { + ccy: string; + nickName: string; + profitSharingAmt: string; + profitSharingId: string; + portLink: string; + ts: string; + instType: string; +} +⋮---- +export interface GetCTTotalProfitResult { + ccy: string; + totalProfitSharingAmt: string; + instType: string; +} +⋮---- +export interface GetCTUnrealizedProfitResult { + ccy: string; + nickName: string; + portLink: string; + ts: string; + unrealizedProfitSharingAmt: string; + instType: string; +} +⋮---- +export interface AccountConfigurationDetails { + copyTraderNum: string; + instType: 'SPOT' | 'SWAP'; + maxCopyTraderNum: string; + profitSharingRatio: string; + roleType: '0' | '1' | '2'; +} +⋮---- +export interface GetAccountConfigurationResult { + uniqueCode: string; + nickName: string; + portLink: string; + details: AccountConfigurationDetails[]; +} +⋮---- +export interface CopySettingsInstId { + instId: string; + enabled: string; +} +⋮---- +export interface GetCopySettingsResult { + ccy: string; + copyAmt: string; copyInstIdType: 'custom' | 'copy'; copyMgnMode: 'cross' | 'isolated' | 'copy'; copyMode: 'fixed_amount' | 'ratio_copy'; @@ -1802,13 +2137,239 @@ export interface WsAPIOperationResponseMap { // https://www.okx.com/docs-v5/en/#spread-trading-websocket-trade-api-ws-cancel-all-orders ================ -File: .eslintrc.cjs +File: src/websocket-client-legacy.ts ================ -'require-extensions', // only once moved to ESM -⋮---- -'plugin:require-extensions/recommended', // only once moved to ESM +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import { EventEmitter } from 'events'; +import WebSocket from 'isomorphic-ws'; ⋮---- -// 'no-unused-vars': ['warn'], +import { APICredentials } from './types/shared.js'; +import { + WsAuthRequest, + WsSubRequest, + WsUnsubRequest, +} from './types/websockets/ws-api.js'; +import { WsDataEvent } from './types/websockets/ws-events.js'; +import { + WebsocketClientOptions, + WSClientConfigurableOptions, +} from './types/websockets/ws-general.js'; +import { + WsAuthRequestArg, + WsChannelSubUnSubRequestArg, +} from './types/websockets/ws-request.js'; +import { WSClientEventMap } from './util/BaseWSClient.js'; +import { DefaultLogger } from './util/logger.js'; +import { + isConnCountEvent, + isWsDataEvent, + isWsErrorEvent, + isWsLoginEvent, + isWsSubscribeEvent, + isWsUnsubscribeEvent, +} from './util/typeGuards.js'; +import { signMessage } from './util/webCryptoAPI.js'; +import { + getMaxTopicsPerSubscribeEventForMarket, + getWsKeyForMarket, + getWsKeyForTopicChannel, + getWsUrlForWsKey, + isWsPong, + PRIVATE_WS_KEYS, + PUBLIC_WS_KEYS, + safeTerminateWs, + WS_EVENT_CODE_ENUM, + WS_KEY_MAP, + WS_LOGGER_CATEGORY, + WsKey, +} from './util/websocket-util.js'; +import WsStore from './util/WsStore.js'; +import { WsConnectionStateEnum } from './util/WsStore.types.js'; +⋮---- +// Type safety for on and emit handlers: https://stackoverflow.com/a/61609010/880837 +export declare interface WebsocketClientLegacy { + on>( + event: U, + listener: WSClientEventMap[U], + ): this; + + emit>( + event: U, + ...args: Parameters[U]> + ): boolean; +} +⋮---- +on>( + event: U, + listener: WSClientEventMap[U], + ): this; +⋮---- +emit>( + event: U, + ...args: Parameters[U]> + ): boolean; +⋮---- +/** + * @deprecated This is the old WebsocketClient that was part of the SDK prior to the V3 release. This legacy WebsocketClient is temporarily included but will be removed with the next major release. + */ +export class WebsocketClientLegacy extends EventEmitter +⋮---- +constructor(options: WSClientConfigurableOptions, logger?: DefaultLogger) +⋮---- +// Automatically send an authentication op/request after a connection opens, for private connections. +⋮---- +// Individual requests do not require a signature, so this is disabled. +⋮---- +/** + * Subscribe to topics & track/persist them. They will be automatically resubscribed to if the connection drops/reconnects. + * @param wsEvents topic or list of topics + * @param isPrivateTopic optional - the library will try to detect private topics, you can use this to mark a topic as private (if the topic isn't recognised yet) + */ +public subscribe( + wsEvents: WsChannelSubUnSubRequestArg[] | WsChannelSubUnSubRequestArg, + isPrivateTopic?: boolean, +) +⋮---- +// Persist topic for reconnects +⋮---- +// if connected, send subscription request +⋮---- +// start connection process if it hasn't yet begun. Topics are automatically subscribed to on-connect +⋮---- +/** + * Unsubscribe from topics & remove them from memory. They won't be re-subscribed to if the connection reconnects. + * @param wsTopics topic or list of topics + * @param isPrivateTopic optional - the library will try to detect private topics, you can use this to mark a topic as private (if the topic isn't recognised yet) + */ +public unsubscribe( + wsTopics: WsChannelSubUnSubRequestArg[] | WsChannelSubUnSubRequestArg, + isPrivateTopic?: boolean, +) +⋮---- +// Remove topic from persistence for reconnects +⋮---- +// unsubscribe request only necessary if active connection exists +⋮---- +/** Get the WsStore that tracks websocket & topic state */ +public getWsStore(): WsStore +⋮---- +public close(wsKey: WsKey, force?: boolean) +⋮---- +public closeAll(force?: boolean) +⋮---- +/** + * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library + */ +public connectAll(): Promise[] +⋮---- +public connectPublic( + businessEndpoint?: boolean, +): Promise +⋮---- +public connectPrivate( + businessEndpoint?: boolean, +): Promise +⋮---- +private async connect(wsKey: WsKey): Promise +⋮---- +private parseWsError(context: string, error: any, wsKey: WsKey) +⋮---- +/** + * Return params required to make authorized request + */ +private async getWsAuthRequest( + wsKey: WsKey, +): Promise | undefined> +⋮---- +// Filter out failed accounts +⋮---- +private async getWsAuthSignature( + wsKey: WsKey, + credentials: APICredentials, +): Promise< +⋮---- +// const signatureExpiresAt = timestamp + 5; +⋮---- +private async sendAuthRequest(wsKey: WsKey): Promise +⋮---- +private reconnectWithDelay(wsKey: WsKey, connectionDelayMs: number) +⋮---- +private ping(wsKey: WsKey) +⋮---- +/** + * Closes a connection, if it's even open. If open, this will trigger a reconnect asynchronously. + * If closed, trigger a reconnect immediately. + */ +private executeReconnectableClose(wsKey: WsKey, reason: string) +⋮---- +private clearTimers(wsKey: WsKey) +⋮---- +// Send a ping at intervals +private clearPingTimer(wsKey: WsKey) +⋮---- +// Expect a pong within a time limit +private clearPongTimer(wsKey: WsKey) +⋮---- +private clearReconnectTimer(wsKey: WsKey) +⋮---- +/** + * @private Use the `subscribe(topics)` method to subscribe to topics. Send WS message to subscribe to topics. + */ +private requestSubscribeTopics( + wsKey: WsKey, + topics: WsChannelSubUnSubRequestArg[], +) +⋮---- +/** + * @private Use the `unsubscribe(topics)` method to unsubscribe from topics. Send WS message to unsubscribe from topics. + */ +private requestUnsubscribeTopics( + wsKey: WsKey, + topics: WsChannelSubUnSubRequestArg[], +) +⋮---- +public tryWsSend(wsKey: WsKey, wsMessage: string): void +⋮---- +private connectToWsUrl(url: string, wsKey: WsKey): WebSocket +⋮---- +private async onWsOpen( + event: WebSocket.Event, + wsKey: WsKey, + url: string, + ws: WebSocket, +) +⋮---- +// Private websockets require an auth packet to be sent after opening the connection +⋮---- +// Any requested private topics will be subscribed to once authentication succeeds (in onWsMessage handler) +⋮---- +// Private topics will be subscribed to once authentication is confirmed as successful +⋮---- +// Public topics can be subscribed to immediately +⋮---- +// Since public channels have their own ws key, these topics must be public ones already +⋮---- +private onWsMessage(event: any, wsKey: WsKey, _ws: WebSocket) +⋮---- +// any message can clear the pong timer - wouldn't get a message if the ws dropped +⋮---- +// Successfully authenticated +⋮---- +// Since private topics have a dedicated WsKey, these are automatically all private topics (no filtering required before the subscribe call) +⋮---- +// this.logger.trace(`Ws subscribe reply:`, { ...msg, wsKey }); +⋮---- +private onWsClose(event: any, wsKey: WsKey) + +================ +File: .eslintrc.cjs +================ +'require-extensions', // only once moved to ESM +⋮---- +'plugin:require-extensions/recommended', // only once moved to ESM +⋮---- +// 'no-unused-vars': ['warn'], ================ File: .jshintrc @@ -2135,5220 +2696,3883 @@ File: tsconfig.linting.json } ================ -File: docs/OKX_SDK_QUICKSTART_GUIDE.md +File: examples/Auth/fasterHmacSign.ts ================ - - -# OKX API JavaScript Tutorial for Node.js and TypeScript +import { createHmac } from 'crypto'; +⋮---- +import { + DefaultLogger, + RestClient, + WebsocketClient, +} from '../../src/index.js'; +⋮---- +// or +// import { createHmac } from 'crypto'; +// import { DefaultLogger, RestClient, WebsocketClient } from 'okx-api'; +⋮---- +/** + * Injecting a custom signMessage function. + * + * As of version 3.0.0 of the okx-api Node.js/TypeScript/JavaScript + * SDK for OKX, the SDK uses the Web Crypto API for signing requests. + * While it is compatible with Node and Browser environments, it is + * slightly slower than using Node's native crypto module (only + * available in backend Node environments). + * + * For latency sensitive users, you can inject the previous node crypto sign + * method (or your own even faster implementation), if this change affects you. + * + * This example demonstrates how to inject a custom sign function, to achieve + * the same peformance as seen before the Web Crypto API was introduced. + * + * For context on standard usage, the "signMessage" function is used: + * - During every single API call + * - After opening a new private WebSocket connection + */ +⋮---- +// If running from CLI in unix, you can pass env vars as such: +// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/rest-private-trade.ts +⋮---- +// note the single quotes, preventing special characters such as $ from being incorrectly passed +⋮---- +// apiKey: 'apiKeyHere', +⋮---- +// apiSecret: 'apiSecretHere', +⋮---- +// apiPass: 'apiPassHere', +/** + * Overkill in almost every case, but if you need any optimisation available, + * you can inject a faster sign mechanism such as node's native createHmac: + */ +⋮---- +// Optional, uncomment the "trace" override to log a lot more info about what the WS client is doing +⋮---- +// trace: (...params) => console.log('trace', ...params), +⋮---- +// For private topics, include one or more accounts in an array. Otherwise only public topics will work +⋮---- +/** + * Overkill in almost every case, but if you need any optimisation available, + * you can inject a faster sign mechanism such as node's native createHmac: + */ +⋮---- +function setWsClientEventListeners( + websocketClient: WebsocketClient, + accountRef: string, +): Promise +⋮---- +// console.log('raw message received ', JSON.stringify(data, null, 2)); +⋮---- +// Simple promise to ensure we're subscribed before trying anything else +⋮---- +// Start trading - - -> [!TIP] -> Read this guide in tutorial format on the Siebly website: [OKX JavaScript REST API and WebSocket Tutorial](https://siebly.io/sdk/okx/javascript/tutorial) - - - -This tutorial uses [`okx-api`](https://www.npmjs.com/package/okx-api), Siebly's Node.js, JavaScript, and TypeScript SDK for OKX. It covers public and private REST API calls, live WebSocket streams, demo orders, WebSocket API commands, regional API routing, and proxies. - -The SDK handles OKX request signing, API passphrase authentication, regional hosts, demo trading, WebSocket channel routing, heartbeats, reconnects, resubscriptions, and WebSocket API response matching. Request and response types are included. - -**Key links** - -- OKX JavaScript SDK by Siebly: [`okx-api`](https://www.npmjs.com/package/okx-api) -- GitHub repository: [`tiagosiebler/okx-api`](https://github.com/tiagosiebler/okx-api) -- SDK endpoint map: [OKX JavaScript endpoint reference](./endpointFunctionList.md) -- SDK examples: [OKX SDK examples](https://siebly.io/examples/OKX) -- OKX Global API docs: [OKX API documentation](https://www.okx.com/docs-v5/en/) -- OKX EEA API docs: [OKX EEA API documentation](https://my.okx.com/docs-v5/en/) -- OKX US API docs: [OKX US API documentation](https://app.okx.com/docs-v5/en/) -- Trading-system terms: [Siebly glossary](https://siebly.io/reference/glossary) -- More JavaScript and TypeScript SDKs: [Siebly.io](https://siebly.io) - ---- - - - -## Why use the SDK - -An OKX integration has more than one connection path: - -- Private REST API calls require an API key, secret, passphrase, timestamp, and HMAC signature. -- Public, private, and business WebSocket channels use different endpoints. -- Demo trading uses separate API keys, REST API headers, and WebSocket hosts. -- Global, EEA, and US accounts use different API host groups. -- WebSocket connections need heartbeat, reconnect, and resubscribe handling. -- WebSocket API commands need unique request IDs and matching responses. - -The SDK handles those mechanics and exposes three main clients: - -| Workflow | SDK client | Use it for | -| ----------------- | -------------------- | ------------------------------------------------------------------------------------ | -| REST API | `RestClient` | Public data, account reads, trading, funding, transfers, and broad endpoint coverage | -| WebSocket streams | `WebsocketClient` | Public market data, private account state, and business channels | -| WebSocket API | `WebsocketAPIClient` | Awaitable order, amend, cancel, batch, and spread commands over WebSocket | - -Most applications use `RestClient` for initial state and reconciliation, then add `WebsocketClient` for live updates. Use `WebsocketAPIClient` when you want supported trading commands to use a persistent authenticated socket. - ---- - - - -## Installation and API keys - -Install the SDK: - -```bash -npm install okx-api -``` +================ +File: examples/Rest/app.okx.com.ts +================ +import { RestClient, WebsocketClient } from '../../src/index.js'; +⋮---- +// or +// import { RestClient } from 'okx-api'; +⋮---- +/** + * To use "app.okx.com", set market to "US" + * + * Note: your available functionality may differ, refer to the corresponding API docs for more details: + * https://app.okx.com/docs-v5/en/#overview-production-trading-services + */ +⋮---- +/** + * This is a simple script wrapped in a immediately invoked function expression, designed to make public API calls without credentials + */ +⋮---- +// Raw data will arrive on the 'update' event +⋮---- +// console.log( +// new Date(), +// 'ws update (raw data received)', +// JSON.stringify(data, null, 2), +// ); +// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); -Other npm-compatible package managers work too: +================ +File: examples/Rest/demo-trading.ts +================ +import { RestClient, WebsocketClient } from '../../src/index.js'; +⋮---- +// or +// import { RestClient} from 'okx-api'; +⋮---- +// read from environmental variables, your demo trading keys +⋮---- +// okx api credentials +⋮---- +// Raw data will arrive on the 'update' event +⋮---- +// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); +⋮---- +// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event +⋮---- +// console.log('ws response: ', JSON.stringify(data, null, 2)); +⋮---- +// Subscribe to demo account events: +⋮---- +/** Simple examples for private REST API calls with bybit's V5 REST APIs */ +⋮---- +// Trade USDT linear perps -```bash -pnpm install okx-api -yarn add okx-api -``` +================ +File: examples/Rest/my.okx.com.ts +================ +import { RestClient, WebsocketClient } from '../../src/index.js'; +⋮---- +// or +// import { RestClient } from 'okx-api'; +⋮---- +/** + * To use "my.okx.com", set market to "EEA" + * + * Note: your available functionality may differ, refer to the corresponding API docs for more details: + * https://my.okx.com/docs-v5/en/#overview-production-trading-services + */ +⋮---- +async function start() +⋮---- +// Raw data will arrive on the 'update' event +⋮---- +// console.log( +// new Date(), +// 'ws update (raw data received)', +// JSON.stringify(data, null, 2), +// ); +// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); -Public market data does not need credentials. Private REST API calls, private WebSocket subscriptions, and WebSocket API commands need all three values: +================ +File: examples/Rest/rest-private-trade-market.ts +================ +import { OrderRequest, RestClient } from '../../src/index.js'; +⋮---- +// or +// import { RestClient, OrderRequest } from 'okx-api'; +⋮---- +// read from environmental variables +⋮---- +// If running from CLI in unix, you can pass env vars as such: +// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/rest-private-trade-market.ts +⋮---- +// note the single quotes, preventing special characters such as $ from being incorrectly passed +⋮---- +// apiKey: 'apiKeyHere', +⋮---- +// apiSecret: 'apiSecretHere', +⋮---- +// apiPass: 'apiPassHere', +⋮---- +/** Get available balance for an asset */ +async function getAssetBalance( + client: RestClient, + coin: string, +): Promise +⋮---- +/** + * This is a simple REST API demo script wrapped in a immediately invoked function expression. The logic below will immediately execute if you run this script. + * + * It is designed to: + * - check for any available USDT balance + * - immediately use half the balance to buy bitcoin (in spot) + * - check the available BTC balance + * - immediately sell all available BTC back to USDT + */ -| SDK option | OKX credential | -| ----------- | ---------------------------------------------- | -| `apiKey` | API key | -| `apiSecret` | API secret | -| `apiPass` | Passphrase chosen when the API key was created | +================ +File: examples/Rest/rest-public.ts +================ +import { RestClient } from '../../src/index.js'; +⋮---- +// or +// import { RestClient } from 'okx-api'; +⋮---- +/** + * This is a simple script wrapped in a immediately invoked function expression, designed to make public API calls without credentials + */ -`apiPass` is the API-key passphrase, not the password used to sign in to OKX. +================ +File: examples/Websocket/app.okx.com.ts +================ +import { RestClient, WebsocketClient } from '../../src/index.js'; +⋮---- +// or +// import { RestClient } from 'okx-api'; +⋮---- +/** + * To use "app.okx.com", set market to "US" + * + * Note: your available functionality may differ, refer to the corresponding API docs for more details: + * https://app.okx.com/docs-v5/en/#overview-production-trading-services + */ +⋮---- +/** + * This is a simple script wrapped in a immediately invoked function expression, designed to make public API calls without credentials + */ +⋮---- +// Raw data will arrive on the 'update' event +⋮---- +// console.log( +// new Date(), +// 'ws update (raw data received)', +// JSON.stringify(data, null, 2), +// ); +// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); -Create and manage keys on the site associated with the account: +================ +File: examples/Websocket/ws-private-handle-auth-fail.ts +================ +// If you cloned the repo and are using typescript, you can import from src directly: +import { WebsocketClient } from '../../src/index.js'; +⋮---- +/** + * + * This simple example demonstrates one way to handle failed authentication, stopping the + * websocket client from running into a reconnect-loop when authentication fails (e.g. bad API keys). + * + * However, keep in mind it might be safer to make a test REST API call (e.g. fetch account balance) before + * trying to make a private WS connection to the account. + * + */ +⋮---- +// For private topics, include one or more accounts in an array. Otherwise only public topics will work +⋮---- +// Raw data will arrive on the 'update' event +⋮---- +// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); +⋮---- +// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event +⋮---- +// console.log('ws response: ', JSON.stringify(data, null, 2)); +⋮---- +// Optional, connect before subscribing: +⋮---- +// This is optional though. The wsclient will automatically open and subscribe if the connection doesn't exist yet. +⋮---- +// Subscribe one event at a time: -- [OKX Global API keys](https://www.okx.com/account/my-api) -- [OKX EEA API keys](https://my.okx.com/account/my-api) -- [OKX US API keys](https://app.okx.com/account/my-api) - -The private examples use these environment variables: - -```bash -OKX_API_KEY -OKX_API_SECRET -OKX_API_PASSPHRASE -``` +================ +File: examples/Websocket/ws-private.ts +================ +// If you cloned the repo and are using typescript, you can import from src directly: +import { DefaultLogger, WebsocketClient } from '../../src/index.js'; +⋮---- +// or use the module installed via `npm install okx-api`: +// import { WebsocketClient, DefaultLogger } from 'okx-api'; +⋮---- +// or if you're not using typescript (e.g. pure nodejs), change the "import" to "require": +// const { WebsocketClient, DefaultLogger } = require('okx-api'); +⋮---- +// Optional: Inject a custom logger. +// This example overrides the default logger to also log "trace" (super verbose) messages, which are disabled by default +⋮---- +// trace: (...params) => console.log('trace', ...params), +⋮---- +// For private events, all 3 of the following are required (per account): +⋮---- +// If running from CLI in unix, you can pass env vars as such: +// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts +⋮---- +// note the single quotes, preventing special characters such as $ from being incorrectly passed +⋮---- +// For Global users (www.okx.com), you don't need to set the market. +// It will use global by default. +// Not needed: market: 'GLOBAL', +⋮---- +// For EEA users (my.okx.com), set market to "EEA": +// market: 'EEA', +⋮---- +// For US users (app.okx.com), set market to "US": +// market: 'US', +⋮---- +// For private topics, include one or more accounts in an array. Otherwise only public topics will work +⋮---- +// { +// apiKey: 'yourApiKeyHere', +// apiSecret: 'yourApiSecretHere', +// apiPass: 'yourApiPassHere', +// }, +// { +// apiKey: 'anotherAccountKey', +// apiSecret: 'anotherAccountSecret', +// apiPass: 'anotherAccountPass', +// }, +⋮---- +// Raw data will arrive on the 'update' event +⋮---- +// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); +⋮---- +// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event +⋮---- +// console.log('ws response: ', JSON.stringify(data, null, 2)); +⋮---- +// Optional, connect before subscribing: +// wsClient.connectPrivate(); +⋮---- +// This is optional though. The wsclient will automatically open and subscribe if the connection doesn't exist yet. +⋮---- +/** + * # Subscribing to channels + * + * Subscribe to channels using the inner "args" part of the subscription request described in the OKX API docs. + * + * For example, if the docs state your request should look as such: + { + op: "subscribe", + args: [ + { + channel: "account" + } + ] + } + * + * You should call the wsClient.subscribe function using only the "args". + * + * Either of these examples is correct (one channel vs one or more channels in an array): + wsClient.subscribe({ + channel: 'account' + }); -Use a secret manager in deployed applications. Keep live and demo credentials separate, grant only the permissions the application needs, and use an IP whitelist when the outbound addresses are stable. Nothing in this tutorial requires withdrawal permission. + wsClient.subscribe([ + { + channel: "account" + } + ]) + */ +⋮---- +// Subscribe one event at a time: +⋮---- +// OR, combine multiple subscription events into one request using an array instead of an object: +⋮---- +/** + * Examples for each private channel listed in the API docs: + * https://www.okx.com/docs-v5/en/#websocket-api-private-channel + */ +⋮---- +// Account events for all symbols +⋮---- +// Account events for specific symbol only +⋮---- +// Withdrawal events for specific symbol only +⋮---- +// Position events on any instrument type +⋮---- +// Position events on specific instruments +⋮---- +// Balance & position channel +⋮---- +// Order channel +⋮---- +// Order channel with extra args +⋮---- +// Algo orders channel +⋮---- +// Advance algo orders channel +⋮---- +// Position risk warning channel +⋮---- +// Account greeks channel +⋮---- +// Spot grid algo orders channel +⋮---- +// Contract grid orders channel +⋮---- +// Moon grid orders channel +⋮---- +// Moon grid orders channel +⋮---- +// Grid positions channel +⋮---- +// Grid sub orders channel -Pass the environment variables directly when creating a private client: +================ +File: examples/Websocket/ws-public.ts +================ +import { DefaultLogger, WebsocketClient } from '../../src/index.js'; +⋮---- +// or use the module installed via `npm install okx-api`: +// import { WebsocketClient, DefaultLogger } from 'okx-api'; +⋮---- +// or if you're not using typescript (e.g. pure nodejs), change the "import" to "require": +// const { WebsocketClient, DefaultLogger } = require('okx-api'); +⋮---- +// Optional: Inject a custom logger. +// This example overrides the default logger to also log "trace" (super verbose) messages, which are disabled by default +⋮---- +// trace: (...params) => console.log('trace', ...params), +⋮---- +// For Global users (www.okx.com), you don't need to set the market. +// It will use global by default. +// Not needed: market: 'GLOBAL', +// For EEA users (my.okx.com), set market to "EEA": +// market: 'EEA', +// For US users (app.okx.com), set market to "US": +// market: 'US', +⋮---- +logger, // Optional: inject the custom logger here +⋮---- +// Raw data will arrive on the 'update' event +⋮---- +// console.log( +// new Date(), +// 'ws update (raw data received)', +// JSON.stringify(data, null, 2), +// ); +// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); +⋮---- +// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event +⋮---- +// Send one topic at a time +⋮---- +// Or an array of requests +⋮---- +/** + * + * Examples for each channel: https://www.okx.com/docs-v5/en/#websocket-api-public-channel + * + */ +⋮---- +// Instruments channel +⋮---- +// Tickers channel +⋮---- +// Open interest channel +⋮---- +// Candlesticks channel +⋮---- +// Trades channel +⋮---- +// Estimated delivery/exercise price channel +⋮---- +// Mark price channel +⋮---- +// Mark price candlesticks channel +⋮---- +// Price limit channel +⋮---- +// Order book channel +⋮---- +// OPTION summary channel +⋮---- +// Funding rate channel +⋮---- +// Index candlesticks channel +⋮---- +// Index tickers channel +⋮---- +// Status channel +⋮---- +// Liquidation orders channel -```typescript -import { RestClient } from 'okx-api'; +================ +File: src/types/rest/request/convert.ts +================ +export interface ConvertQuoteEstimateRequest { + baseCcy: string; + quoteCcy: string; + side: string; + rfqSz: string; + rfqSzCcy: string; + clTReqId?: string; + tag?: string; + /** 0: standard convert (default), 1: large order convert for VIP */ + convertMode?: '0' | '1'; +} +⋮---- +/** 0: standard convert (default), 1: large order convert for VIP */ +⋮---- +export interface ConvertTradeRequest { + quoteId: string; + baseCcy: string; + quoteCcy: string; + side: string; + sz: string; + szCcy: string; + clTReqId?: string; + tag?: string; + /** 0: standard convert (default), 1: large order convert for VIP */ + convertMode?: '0' | '1'; +} +⋮---- +/** 0: standard convert (default), 1: large order convert for VIP */ -const client = new RestClient({ - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, -}); -``` - -The TypeScript `!` tells the compiler that each environment variable is set. Do not log the credentials. Private signing also depends on an accurate system clock and a maintained Node.js release with the Web Crypto API. - ---- - - - -## OKX products and request vocabulary - -OKX uses an instrument type to identify a product family and an instrument ID to identify the exact market: - -| Product | Typical `instType` | `instId` example | Common `tdMode` | -| --------------- | ------------------ | --------------------------------------------------------- | ------------------------ | -| Spot | `SPOT` | `BTC-USDT` | `cash` | -| Spot margin | `MARGIN` | `BTC-USDT` | `cross` or `isolated` | -| Perpetual swap | `SWAP` | `BTC-USDT-SWAP` | `cross` or `isolated` | -| Dated futures | `FUTURES` | Query current instruments for an active expiry | `cross` or `isolated` | -| Options | `OPTION` | Query current instruments for an active expiry and strike | Depends on account setup | -| Event contracts | `EVENTS` | Query current instruments and regional availability | Product-specific | - -Do not hardcode dated futures or option instrument IDs in long-lived code. Use `getInstruments()` to find active contracts and read their expiry, tick size, lot size, and minimum size. - -The fields used most often are: - -- `instType`: the product family, such as `SPOT`, `SWAP`, or `OPTION`. -- `instId`: the exact instrument, such as `BTC-USDT` or `BTC-USDT-SWAP`. -- `instFamily`: a derivatives family used by some requests and channels. -- `uly`: the underlying used by some futures and options endpoints. -- `tdMode`: `cash`, `cross`, `isolated`, or another mode supported by that request. -- `posSide`: `net`, `long`, or `short`, depending on the account's position mode. -- `clOrdId`: your own identifier for an order. - -Use a unique `clOrdId` for each application-owned order. It makes retries and reconciliation easier. See [Custom Order ID](https://siebly.io/reference/glossary#custom-order-id) in the Siebly glossary. - -Account mode and position mode affect which order fields are valid. Read `getAccountConfiguration()` before building derivatives order logic. The tutorial does not change either setting. - -### REST API, streams, and the WebSocket API - -These are separate workflows: - -| Flow | SDK client | Best for | -| ----------------- | -------------------- | --------------------------------------------------------------------------------- | -| REST API | `RestClient` | Public reads, account reads, trading, broad endpoint coverage, and reconciliation | -| WebSocket streams | `WebsocketClient` | Live market, order, balance, and position updates | -| WebSocket API | `WebsocketAPIClient` | Awaitable order-management commands over an authenticated socket | - -A stream update and a WebSocket API acknowledgement are not interchangeable. An acknowledgement reports whether OKX accepted a command. Order and fill state still comes from the private streams or a REST API query. - ---- - - - -## Start building: first calls - -Run the public REST API example first. Then add the client that matches the workflow you need. - -### 1. First public REST API request - -`RestClient` works without credentials for public endpoints. - - - -```typescript -import { RestClient } from 'okx-api'; - -const client = new RestClient(); - -async function main() { - try { - const serverTime = await client.getSystemTime({}); - console.log('Server time:', serverTime[0]?.ts); - } catch (error) { - console.error('Failed to get server time:', error); - } - - try { - const instruments = await client.getInstruments({ - instType: 'SPOT', - instId: 'BTC-USDT', - }); - console.log('Instrument:', instruments[0]?.instId); - } catch (error) { - console.error('Failed to get instruments:', error); - } - - try { - const ticker = await client.getTicker({ instId: 'BTC-USDT' }); - console.log('Last price:', ticker[0]?.last); - } catch (error) { - console.error('Failed to get ticker:', error); - } - - try { - const orderBook = await client.getOrderBook({ - instId: 'BTC-USDT', - sz: '5', - }); - console.log('Best bid:', orderBook[0]?.bids[0]); - } catch (error) { - console.error('Failed to get order book:', error); - } - - try { - const candles = await client.getCandles({ - instId: 'BTC-USDT', - bar: '1m', - limit: '5', - }); - console.log('Latest candle:', candles[0]); - } catch (error) { - console.error('Failed to get candles:', error); - } +================ +File: src/types/rest/request/dual-investment.ts +================ +export interface GetDcdProductsRequest { + baseCcy: string; + quoteCcy: string; + optType: 'C' | 'P'; +} +⋮---- +export interface RequestDcdQuoteRequest { + productId: string; + notionalSz: string; + notionalCcy: string; +} +⋮---- +export interface SubmitDcdTradeRequest { + quoteId: string; +} +⋮---- +export interface RequestDcdRedeemQuoteRequest { + ordId: string; +} +⋮---- +export interface SubmitDcdRedeemRequest { + ordId: string; + quoteId: string; +} +⋮---- +export interface GetDcdOrderStatusRequest { + ordId: string; +} +⋮---- +export type DcdOrderState = + | 'initial' + | 'live' + | 'pending_settle' + | 'settled' + | 'pending_redeem' + | 'redeemed' + | 'rejected'; +⋮---- +export interface GetDcdOrderHistoryRequest { + ordId?: string; + productId?: string; + uly?: string; + state?: DcdOrderState; + beginId?: string; + endId?: string; + begin?: string; + end?: string; + limit?: string; } -main(); -``` - -Run it with a TypeScript runner or compile it with your project: - -```bash -npx tsx first-okx-api-call.ts -``` - -Successful SDK methods return the parsed OKX `data` value. Most OKX REST API endpoints return an array, so `getTicker()` resolves to the ticker array rather than the outer `{ code, msg, data }` envelope. Exchange errors and non-success HTTP responses reject the promise. - -### 2. First private REST API request - -Private calls use the same client with `apiKey`, `apiSecret`, and `apiPass`. - - +================ +File: src/types/rest/request/glp.ts +================ +export type GlpProgram = 'SPOT' | 'PERP' | 'FUT_NTO'; +⋮---- +export interface GetGlpHistoricalPerformanceRequest { + program: GlpProgram; + begin?: string; + end?: string; + limit?: string; +} -```typescript -import { RestClient } from 'okx-api'; +================ +File: src/types/rest/request/okusd.ts +================ +export interface SubscribeOkusdRequest { + amt: string; + clOrdId: string; +} +⋮---- +export interface RedeemOkusdRequest { + amt: string; + /** "1" = fast (real-time); "2" = standard (D+5/D+6) */ + redeemType: '1' | '2'; + clOrdId: string; +} +⋮---- +/** "1" = fast (real-time); "2" = standard (D+5/D+6) */ -const client = new RestClient({ - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, -}); +================ +File: src/types/rest/request/stable-rewards.ts +================ +export interface GetStableRewardsProductInfoRequest { + ccy: string; +} +⋮---- +export interface RequestStableRewardsQuoteRequest { + ccy: string; + settleCcy: string; + action: 'subscribe' | 'redeem'; + amt: string; +} +⋮---- +export interface SubmitStableRewardsTradeRequest { + quoteId: string; +} +⋮---- +export interface GetStableRewardsBalanceRequest { + ccy?: string; +} +⋮---- +export interface GetStableRewardsApyHistoryRequest { + ccy: string; + days?: string; +} +⋮---- +export interface GetStableRewardsSubscribeRedeemHistoryRequest { + ccy: string; + type?: 'subscribe' | 'redeem'; + status?: 'pending' | 'success' | 'failed'; + after?: string; + before?: string; + limit?: string; +} -async function main() { - try { - const configuration = await client.getAccountConfiguration(); - console.log({ - accountMode: configuration[0]?.acctLv, - positionMode: configuration[0]?.posMode, - }); - } catch (error) { - console.error('Failed to get account configuration:', error); - } - - try { - const balances = await client.getBalance(); - console.log({ - totalEquity: balances[0]?.totalEq, - currencies: balances[0]?.details.map((item) => item.ccy), - }); - } catch (error) { - console.error('Failed to get trading balances:', error); - } - - try { - const positions = await client.getPositions(); - console.log('Position count:', positions.length); - } catch (error) { - console.error('Failed to get positions:', error); - } - - try { - const openOrders = await client.getOrderList({ instType: 'SPOT' }); - console.log('Open order count:', openOrders.length); - } catch (error) { - console.error('Failed to get open orders:', error); - } - - try { - const fills = await client.getFills({ instType: 'SPOT', limit: '20' }); - console.log('Recent fill count:', fills.length); - } catch (error) { - console.error('Failed to get fills:', error); - } +================ +File: src/types/rest/response/private-dual-investment.ts +================ +export interface DcdCurrencyPair { + baseCcy: string; + quoteCcy: string; + optType: 'C' | 'P'; + uly: string; } - -main(); -``` - -Read-only API keys are sufficient for this example. `getBalance()` returns trading-account balances. Funding-account assets use `getBalances()`, which is a different endpoint covered later. - -### 3. First public WebSocket stream - -Pass the inner channel objects from the OKX `args` array to `subscribe()`. The SDK builds the outer subscribe message and selects the correct WebSocket connection. - - - -```typescript -import { WebsocketClient } from 'okx-api'; - -const ws = new WebsocketClient(); - -ws.on('open', ({ wsKey }) => { - console.log('Connected:', wsKey); -}); - -ws.on('response', (event) => { - console.log('WebSocket response:', event); -}); - -ws.on('update', (event) => { - console.log(event.arg.channel, event.data); -}); - -ws.on('reconnect', ({ wsKey }) => { - console.log('Reconnecting:', wsKey); -}); - -ws.on('reconnected', ({ wsKey }) => { - console.log('Reconnected:', wsKey); -}); - -ws.on('exception', (error) => { - console.error('WebSocket exception:', error); -}); - -ws.subscribe([ - { channel: 'tickers', instId: 'BTC-USDT' }, - { channel: 'books', instId: 'BTC-USDT' }, - { channel: 'trades', instId: 'BTC-USDT' }, - { channel: 'candle1m', instId: 'BTC-USDT' }, -]); -``` - -Ticker, book, and trade channels use the public WebSocket. Candles use the business WebSocket. One `WebsocketClient` routes both connections, tracks the subscriptions, and resubscribes after a reconnect. - -The `response` event carries subscription and control replies. Live channel data arrives on `update`. - -### 4. First private WebSocket stream - -Private channels need credentials in the client's `accounts` array. - - - -```typescript -import { WebsocketClient } from 'okx-api'; - -const ws = new WebsocketClient({ - accounts: [ - { - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, - }, - ], -}); - -ws.on('open', ({ wsKey }) => { - console.log('Connected:', wsKey); -}); - -ws.on('authenticated', ({ wsKey }) => { - console.log('Authenticated:', wsKey); -}); - -ws.on('response', (event) => { - console.log('WebSocket response:', event); -}); - -ws.on('update', (event) => { - console.log(event.arg.channel, event.data); -}); - -ws.on('reconnect', ({ wsKey }) => { - console.log('Reconnecting:', wsKey); -}); - -ws.on('reconnected', ({ wsKey }) => { - console.log('Reconnected:', wsKey); -}); - -ws.on('exception', (error) => { - console.error('WebSocket exception:', error); -}); - -ws.subscribe([ - { channel: 'account' }, - { channel: 'positions', instType: 'ANY' }, - { channel: 'orders', instType: 'ANY' }, -]); -``` - -The SDK connects and authenticates when the first private subscription needs it. Use `response` to check the [Subscription Acknowledgement](https://siebly.io/reference/glossary#subscription-acknowledgement), then process channel data from `update`. - -OKX can publish related state changes on several channels. Account, position, order, and fill handling should share one consistent account-state model. - -### 5. First REST API order in demo trading - -This example can only place a demo order. It hardcodes `demoTrading: true`, requires separate demo API keys, and exits unless `OKX_PLACE_DEMO_ORDER=true` is set. - -It reads the current instrument rules and places a post-only buy at the current best bid, then queries and cancels the order if it is still open. - - - -```typescript -import { RestClient } from 'okx-api'; - -if (process.env.OKX_PLACE_DEMO_ORDER !== 'true') { - throw new Error('Set OKX_PLACE_DEMO_ORDER=true to place the demo order.'); +⋮---- +export interface DcdProduct { + absYield: string; + annualizedYield: string; + baseCcy: string; + quoteCcy: string; + expTime: string; + interestAccrualTime: string; + listTime: string; + maxSize: string; + minSize: string; + notionalCcy: string; + optType: 'C' | 'P'; + productId: string; + quoteTime: string; + redeemEndTime: string; + redeemStartTime: string; + stepSz: string; + tradeEndTime: string; + strike: string; + uly: string; } - -const client = new RestClient({ - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, - demoTrading: true, -}); - -async function main() { - const instId = 'BTC-USDT'; - - let instrument; - try { - [instrument] = await client.getInstruments({ - instType: 'SPOT', - instId, - }); - } catch (error) { - console.error('Failed to get instrument rules:', error); - return; - } - - let ticker; - try { - [ticker] = await client.getTicker({ instId }); - } catch (error) { - console.error('Failed to get the ticker:', error); - return; - } - - if (!instrument || !ticker) { - console.error(`No demo market data returned for ${instId}.`); - return; - } - - if (!ticker.bidPx) { - console.error(`No best bid returned for ${instId}.`); - return; - } - - const clOrdId = `sieblyDemo${Date.now()}`; - - let placed; - try { - [placed] = await client.submitOrder({ - instId, - tdMode: 'cash', - side: 'buy', - ordType: 'post_only', - sz: instrument.minSz, - px: ticker.bidPx, - clOrdId, - }); - } catch (error) { - console.error('Failed to submit the demo order:', error); - return; - } - - if (!placed || placed.sCode !== '0') { - console.error(placed?.sMsg || 'OKX rejected the demo order.'); - return; - } - - console.log('Demo order accepted:', { - ordId: placed.ordId, - clOrdId: placed.clOrdId, - }); - - let order; - try { - [order] = await client.getOrderDetails({ instId, clOrdId }); - console.log('Current order state:', order?.state); - } catch (error) { - console.error('Failed to query the demo order:', error); - } - - if (!order || ['live', 'partially_filled'].includes(order.state)) { - try { - const [cancelled] = await client.cancelOrder({ instId, clOrdId }); - - if (!cancelled || cancelled.sCode !== '0') { - console.error(cancelled?.sMsg || 'OKX rejected the cancellation.'); - return; - } - - console.log('Demo order cancellation accepted:', cancelled.ordId); - } catch (error) { - console.error('Failed to cancel the demo order:', error); - } - } +⋮---- +export interface DcdQuote { + absYield: string; + annualizedYield: string; + interestAccrualTime: string; + notionalSz: string; + notionalCcy: string; + productId: string; + quoteId: string; + validUntil: string; + idxPx: string; } - -main(); -``` - -OKX order endpoints can return an HTTP success while an individual order result has failed. Check `sCode` and `sMsg` on each result item. This also applies to batch requests, where some items can succeed and others can fail. - -Use `demoTrading: true`. Do not use the old `market: 'demo'` form. - -### 6. First WebSocket API order command - -`WebsocketAPIClient` wraps supported WebSocket commands in promises. Current OKX WebSocket order requests prefer `instIdCode`, so the example reads it from `getInstruments()` before submitting the same demo-only post-only order. - - - -```typescript -import { RestClient, WebsocketAPIClient } from 'okx-api'; - -if (process.env.OKX_PLACE_DEMO_ORDER !== 'true') { - throw new Error('Set OKX_PLACE_DEMO_ORDER=true to place the demo order.'); +⋮---- +export type DcdTradeOrderState = + | 'initial' + | 'pending_book' + | 'live' + | 'rejected'; +⋮---- +export interface DcdTradeResult { + quoteId: string; + ordId: string; + state: DcdTradeOrderState; } - -const credentials = { - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, -}; -const rest = new RestClient({ - ...credentials, - demoTrading: true, -}); -const wsApi = new WebsocketAPIClient({ - accounts: [credentials], - demoTrading: true, - attachEventListeners: false, -}); -const ws = wsApi.getWSClient(); - -ws.on('open', ({ wsKey }) => console.log('Connected:', wsKey)); -ws.on('authenticated', ({ wsKey }) => console.log('Authenticated:', wsKey)); -ws.on('reconnect', ({ wsKey }) => console.log('Reconnecting:', wsKey)); -ws.on('reconnected', ({ wsKey }) => console.log('Reconnected:', wsKey)); -ws.on('exception', (error) => console.error('WebSocket exception:', error)); - -async function main() { - const instId = 'BTC-USDT'; - - let instrument; - try { - [instrument] = await rest.getInstruments({ - instType: 'SPOT', - instId, - }); - } catch (error) { - console.error('Failed to get instrument rules:', error); - ws.closeAll(); - return; - } - - let ticker; - try { - [ticker] = await rest.getTicker({ instId }); - } catch (error) { - console.error('Failed to get the ticker:', error); - ws.closeAll(); - return; - } - - if (!instrument || !ticker) { - console.error(`No demo market data returned for ${instId}.`); - ws.closeAll(); - return; - } - - if (!instrument.instIdCode) { - console.error(`No instIdCode returned for ${instId}.`); - ws.closeAll(); - return; - } - - if (!ticker.bidPx) { - console.error(`No best bid returned for ${instId}.`); - ws.closeAll(); - return; - } - - const clOrdId = `sieblyWsDemo${Date.now()}`; - - try { - await wsApi.connectWSAPI(); - } catch (error) { - console.error('Failed to connect the WebSocket API:', error); - ws.closeAll(); - return; - } - - let placed; - try { - placed = await wsApi.submitNewOrder({ - instIdCode: instrument.instIdCode, - tdMode: 'cash', - side: 'buy', - ordType: 'post_only', - sz: instrument.minSz, - px: ticker.bidPx, - clOrdId, - }); - } catch (error) { - console.error('Failed to submit the WebSocket API order:', error); - ws.closeAll(); - return; - } - - const placedItem = placed.data[0]; - - if (placed.code !== '0' || !placedItem || placedItem.sCode !== '0') { - console.error(placedItem?.sMsg || placed.msg || 'Order was rejected.'); - ws.closeAll(); - return; - } - - console.log('Demo WebSocket order accepted:', { - ordId: placedItem.ordId, - clOrdId: placedItem.clOrdId, - }); - - let cancelled; - try { - cancelled = await wsApi.cancelOrder({ clOrdId }); - } catch (error) { - console.error('Failed to cancel the WebSocket API order:', error); - ws.closeAll(); - return; - } - - const cancelledItem = cancelled.data[0]; - - if (cancelled.code !== '0' || !cancelledItem || cancelledItem.sCode !== '0') { - console.error( - cancelledItem?.sMsg || cancelled.msg || 'Cancellation was rejected.', - ); - ws.closeAll(); - return; - } - - console.log('Demo WebSocket cancellation accepted:', cancelledItem.ordId); - ws.closeAll(); +⋮---- +export interface DcdRedeemQuote { + ordId: string; + quoteId: string; + redeemCcy: string; + redeemSz: string; + termRate: string; + validUntil: string; +} +⋮---- +export type DcdRedeemConfirmState = + | 'pending_redeem_booking' + | 'pending_redeem' + | 'redeeming' + | 'redeemed'; +⋮---- +export interface DcdRedeemResult { + ordId: string; + state: DcdRedeemConfirmState; +} +⋮---- +export type DcdOrderStatusState = + | 'initial' + | 'live' + | 'pending_settle' + | 'settled' + | 'pending_redeem' + | 'redeemed' + | 'rejected'; +⋮---- +export interface DcdOrderStatus { + ordId: string; + state: DcdOrderStatusState; +} +⋮---- +export interface DcdOrderHistoryItem { + ordId: string; + quoteId: string; + state: DcdOrderStatusState; + productId: string; + baseCcy: string; + quoteCcy: string; + uly: string; + strike: string; + notionalSz: string; + notionalCcy: string; + absYield: string; + annualizedYield: string; + yieldSz: string; + yieldCcy: string; + settleSz: string; + settleCcy: string; + settlePx: string; + settleTime: string; + expTime: string; + redeemStartTime: string; + redeemEndTime: string; + cTime: string; + uTime: string; } -main(); -``` - -Check both the top-level `code` and each item's `sCode`. A successful acknowledgement means OKX accepted the command, not that the order filled. Treat it as [Pending Confirmation](https://siebly.io/reference/glossary#pending-confirmation) until the private order stream or REST API confirms the resulting state. See [Private Stream Confirmation](https://siebly.io/reference/glossary#private-stream-confirmation) for the distinction. - ---- - - - -## REST API - -`RestClient` covers OKX market data, public data, account, trade, funding, transfer, sub-account, convert, algo, grid, copy-trading, spread, block-trading, Earn, staking, and loan endpoints. - -Public methods work without credentials. Private methods use the credentials passed to the constructor, and the SDK adds the timestamp, signature, passphrase, and other required headers. - -### Public market data - -The same product fields appear across public endpoints: +================ +File: src/types/rest/response/private-flexible-loan.ts +================ +export interface CollateralAsset { + ccy: string; + amt: string; + notionalUsd: string; +} +⋮---- +export interface CollateralAssetsResponse { + assets: CollateralAsset[]; +} +⋮---- +export interface SupplementaryCollateral { + ccy: string; + amt: string; +} +⋮---- +export interface GetFlexibleLoanCollateralAssetsRequest { + ccy?: string; + /** When the account has multiple active flexible-loan positions. */ + ordId?: string; +} +⋮---- +/** When the account has multiple active flexible-loan positions. */ +⋮---- +export interface MaxLoanRequest { + borrowCcy: string; + supCollateral?: SupplementaryCollateral[]; + /** When multiple active loans exist. */ + ordId?: string; +} +⋮---- +/** When multiple active loans exist. */ +⋮---- +export interface MaxLoanResponse { + borrowCcy: string; + maxLoan: string; + notionalUsd: string; + remainingQuota: string; +} +⋮---- +export interface AdjustCollateralRequest { + type: 'add' | 'reduce'; + collateralCcy: string; + collateralAmt: string; + /** When multiple active loans exist. */ + ordId?: string; +} +⋮---- +/** When multiple active loans exist. */ +⋮---- +export interface LoanCurrencyData { + ccy: string; + amt: string; +} +⋮---- +export interface RiskWarningData { + instId: string; + liqPx: string; +} +⋮---- +export interface GetLoanInfoRequest { + /** When the account has multiple active flexible loans . */ + ordId?: string; +} +⋮---- +/** When the account has multiple active flexible loans . */ +⋮---- +export interface LoanInfo { + /** + * Active loan / position id when the account can hold multiple loan orders. + */ + ordId?: string; + loanNotionalUsd: string; + loanData: LoanCurrencyData[]; + /** Adjusted collateral value in USD. */ + collateralNotionalUsd: string; + collateralData: LoanCurrencyData[]; + riskWarningData: RiskWarningData; + curLTV: string; + marginCallLTV: string; + liqLTV: string; +} +⋮---- +/** + * Active loan / position id when the account can hold multiple loan orders. + */ +⋮---- +/** Adjusted collateral value in USD. */ +⋮---- +export interface LoanHistoryRequest { + type?: + | 'borrowed' + | 'repaid' + | 'collateral_locked' + | 'collateral_released' + | 'forced_repayment_buy' + | 'forced_repayment_sell' + | 'forced_liquidation' + | 'partial_liquidation'; + /** When multiple active loans exist. */ + ordId?: string; + after?: string; + before?: string; + limit?: string; +} +⋮---- +/** When multiple active loans exist. */ +⋮---- +export interface LoanHistoryItem { + refId: string; + type: string; + ccy: string; + amt: string; + ts: string; +} +⋮---- +export interface AccruedInterestRequest { + ccy?: string; + /** When multiple active loans exist. */ + ordId?: string; + after?: string; + before?: string; + limit?: string; +} +⋮---- +/** When multiple active loans exist. */ +⋮---- +export interface AccruedInterestItem { + refId: string; + ccy: string; + loan: string; + interest: string; + interestRate: string; + ts: string; +} -- Use `instType` for a product family. -- Use `instId` for one exact market. -- Use `instFamily` or `uly` where a derivatives endpoint asks for a family or underlying. -- Query instruments before using products with expiries, strikes, or region-specific availability. +================ +File: src/types/rest/response/private-glp.ts +================ +export interface GlpMakerTaker { + maker: string; + taker: string; +} +⋮---- +export interface GlpVolumeBuckets { + typeA: GlpMakerTaker | null; + typeBTotal: GlpMakerTaker | null; + tradfiX2: GlpMakerTaker | null; + total: GlpMakerTaker; +} +⋮---- +export interface GlpShareBuckets { + typeA: GlpMakerTaker | null; + typeBAdj: GlpMakerTaker | null; + total: GlpMakerTaker; +} +⋮---- +export interface GlpDailyMetrics { + volume: GlpVolumeBuckets; + share: GlpShareBuckets; +} +⋮---- +export interface GlpMtdMetrics extends GlpDailyMetrics { + mtdStatus: string; + qualifyingShare: GlpMakerTaker; +} +⋮---- +export interface GlpProgramPerformance { + program: string; + marketMakerBusinessId: string; + enrollmentStatus: string; + marketMakerLevelId: string; + enrolledTierDisplay: string; + qualifyingPool: string; + qualifyingRows: string[]; + daily: GlpDailyMetrics; + mtd: GlpMtdMetrics; +} +⋮---- +export interface GlpTodayPerformance { + dataReady: boolean; + dataDate: string; + account: { + masterAccountId: string; + combinedAccountIds: string[]; + }; + programs: GlpProgramPerformance[]; +} +⋮---- +export interface GlpHistoricalPerformanceItem { + date: string; + volume: GlpVolumeBuckets; + share: GlpShareBuckets; +} -This example reads both Spot and perpetual-swap data: +================ +File: src/types/rest/response/private-okusd.ts +================ +export interface OkusdLimitBucket { + personalDailyLimit: string; + personalUsedAmt: string; + platformDailyLimit: string; + platformUsedAmt: string; + feeRate?: string; +} +⋮---- +export interface OkusdSubLimit extends OkusdLimitBucket { + maxSubAmt: string; +} +⋮---- +export interface OkusdLimits { + subLimit: OkusdSubLimit; + fastRedeemLimit: OkusdLimitBucket; + stdRedeemLimit: OkusdLimitBucket; + ts: string; +} +⋮---- +export interface OkusdSubscribeResult { + ordId: string; + clOrdId: string; + ccy: string; + amt: string; + okusdAmt: string; + state: string; + ts: string; +} +⋮---- +export interface OkusdRedeemResult { + ordId: string; + clOrdId: string; + ccy: string; + amt: string; + fee: string; + usdtAmt: string; + redeemType: string; + state: string; + estSettlementTime: string; + ts: string; +} - - -```typescript -import { RestClient } from 'okx-api'; - -const client = new RestClient(); - -async function main() { - const spotInstId = 'BTC-USDT'; - const swapInstId = 'BTC-USDT-SWAP'; - - try { - const spotInstruments = await client.getInstruments({ - instType: 'SPOT', - instId: spotInstId, - }); - console.log('Spot instrument:', spotInstruments[0]?.instId); - } catch (error) { - console.error('Failed to get Spot instruments:', error); - } - - try { - const spotTickers = await client.getTickers({ instType: 'SPOT' }); - console.log('Spot ticker count:', spotTickers.length); - } catch (error) { - console.error('Failed to get Spot tickers:', error); - } - - try { - const orderBook = await client.getOrderBook({ - instId: spotInstId, - sz: '5', - }); - console.log('Best bid:', orderBook[0]?.bids[0]); - } catch (error) { - console.error('Failed to get the order book:', error); - } - - try { - const candles = await client.getCandles({ - instId: spotInstId, - bar: '1m', - limit: '5', - }); - console.log('Latest candle:', candles[0]); - } catch (error) { - console.error('Failed to get candles:', error); - } - - try { - const trades = await client.getTrades({ instId: spotInstId, limit: 5 }); - console.log('Latest trade:', trades[0]); - } catch (error) { - console.error('Failed to get trades:', error); - } - - try { - const swapInstruments = await client.getInstruments({ - instType: 'SWAP', - instId: swapInstId, - }); - console.log('Swap instrument:', swapInstruments[0]?.instId); - } catch (error) { - console.error('Failed to get swap instruments:', error); - } - - try { - const openInterest = await client.getOpenInterest({ - instType: 'SWAP', - instId: swapInstId, - }); - console.log('Open interest rows:', openInterest.length); - } catch (error) { - console.error('Failed to get open interest:', error); - } - - try { - const fundingRate = await client.getFundingRate({ instId: swapInstId }); - console.log('Funding rate:', fundingRate[0]?.fundingRate); - } catch (error) { - console.error('Failed to get the funding rate:', error); - } - - try { - const markPrice = await client.getMarkPrice({ - instType: 'SWAP', - instId: swapInstId, - }); - console.log('Mark price:', markPrice[0]?.markPx); - } catch (error) { - console.error('Failed to get the mark price:', error); - } - - try { - const indexTicker = await client.getIndexTickers({ instId: spotInstId }); - console.log('Index price:', indexTicker[0]?.idxPx); - } catch (error) { - console.error('Failed to get the index ticker:', error); - } +================ +File: src/types/rest/response/private-stable-rewards.ts +================ +export interface StableRewardsProductInfoDetail { + ccy: string; + settleCcy: string; + subFeeRate: string; + redemptFeeRate: string; + minSubAmt: string; + minRedeemAmt: string; + remainingSubQuota: string; + remainingRedemptQuota: string; + canRedeem: boolean; +} +⋮---- +export interface StableRewardsProductInfo { + details: StableRewardsProductInfoDetail[]; + ts: string; +} +⋮---- +export interface StableRewardsQuote { + quoteId: string; + quoteAmt: string; + quoteCcy: string; + exchRate: string; + feeRate: string; + quoteTime: string; + ttlMs: string; +} +⋮---- +export interface StableRewardsTradeResult { + quoteId: string; + ordId: string; +} +⋮---- +export type StableRewardsBalanceState = 'earning' | 'pending'; +⋮---- +export interface StableRewardsBalanceDetail { + ccy: string; + amt: string; + totalEarnAccrual: string; + state: StableRewardsBalanceState; +} +⋮---- +export interface StableRewardsBalance { + details: StableRewardsBalanceDetail[]; + ts: string; +} +⋮---- +export interface StableRewardsApyHistoryItem { + rate: string; + ts: string; +} +⋮---- +export type StableRewardsSubscribeRedeemType = 'subscribe' | 'redeem'; +⋮---- +export type StableRewardsSubscribeRedeemStatus = + | 'pending' + | 'success' + | 'failed'; +⋮---- +export interface StableRewardsSubscribeRedeemHistoryItem { + type: StableRewardsSubscribeRedeemType; + status: StableRewardsSubscribeRedeemStatus; + ccy: string; + settleCcy: string; + ccyAmt: string; + settleCcyAmt: string; + fee: string; + quoteId: string; + ordId: string; + ts: string; } -main(); -``` - -Candles are returned newest first. Each candle is an array containing timestamp, open, high, low, close, volume fields, and a confirmation flag. Destructure those positions or map them into named fields before passing them deeper into an application. - -Use `getHistoricCandles()` for older market candles. Index and mark-price candles have separate methods because their response and pricing source differ from traded-market candles. - -### Private account state - -Start private workflows by reading account configuration and current state: - - - -```typescript -import { RestClient } from 'okx-api'; +================ +File: src/websocket-client.ts +================ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +⋮---- +import { APICredentials } from './types/shared.js'; +import { + WsAPIOperationResponseMap, + WSAPIRequestFlags, + WSAPIRequestOKX, + WsAPITopicRequestParamMap, + WsAPIWsKeyTopicMap, + WsAuthRequest, + WSOperation, + WsRequestOperationOKX, +} from './types/websockets/ws-api.js'; +import { MessageEventLike, WsDataEvent } from './types/websockets/ws-events.js'; +import { WSClientConfigurableOptions } from './types/websockets/ws-general.js'; +import { + WsAuthRequestArg, + WsChannelSubUnSubRequestArg, +} from './types/websockets/ws-request.js'; +import { + BaseWebsocketClient, + EmittableEvent, + MidflightWsRequestEvent, + WSClientEventMap, +} from './util/BaseWSClient.js'; +import { DefaultLogger } from './util/logger.js'; +import { + isConnCountEvent, + isWSAPIResponse, + isWsDataEvent, + isWsErrorEvent, + isWsLoginEvent, + isWsSubscribeEvent, + isWsUnsubscribeEvent, + neverGuard, +} from './util/typeGuards.js'; +import { + SignAlgorithm, + SignEncodeMethod, + signMessage, +} from './util/webCryptoAPI.js'; +import { + getDemoWsKey, + getPromiseRefForWSAPIRequest, + getWsKeyForMarket, + getWsKeyForTopicChannel, + getWsUrlForWsKey, + isWsPong, + PRIVATE_WS_KEYS, + PUBLIC_WS_KEYS, + requiresWSAPITag, + validateWSAPITag, + WS_EVENT_CODE_ENUM, + WS_KEY_MAP, + WS_LOGGER_CATEGORY, + WsKey, + WsTopicRequest, +} from './util/websocket-util.js'; +import { WSConnectedResult } from './util/WsStore.types.js'; +⋮---- +// Type safety for on and emit handlers: https://stackoverflow.com/a/61609010/880837 +export declare interface WebsocketClient { + on>( + event: U, + listener: WSClientEventMap[U], + ): this; -const client = new RestClient({ - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, -}); - -async function main() { - try { - const configuration = await client.getAccountConfiguration(); - console.log({ - accountMode: configuration[0]?.acctLv, - positionMode: configuration[0]?.posMode, - }); - } catch (error) { - console.error('Failed to get account configuration:', error); - } - - try { - const tradingBalances = await client.getBalance(); - console.log('Trading equity:', tradingBalances[0]?.totalEq); - } catch (error) { - console.error('Failed to get trading balances:', error); - } - - try { - const fundingBalances = await client.getBalances(); - console.log('Funding currency count:', fundingBalances.length); - } catch (error) { - console.error('Failed to get funding balances:', error); - } - - try { - const positions = await client.getPositions(); - console.log('Position count:', positions.length); - } catch (error) { - console.error('Failed to get positions:', error); - } - - try { - const openOrders = await client.getOrderList({ instType: 'SPOT' }); - console.log('Open order count:', openOrders.length); - } catch (error) { - console.error('Failed to get open orders:', error); - } - - try { - const orderHistory = await client.getOrderHistory({ - instType: 'SPOT', - limit: '20', - }); - console.log('Recent order count:', orderHistory.length); - } catch (error) { - console.error('Failed to get order history:', error); - } - - try { - const fills = await client.getFills({ instType: 'SPOT', limit: '20' }); - console.log('Recent fill count:', fills.length); - } catch (error) { - console.error('Failed to get fills:', error); - } - - try { - const feeRates = await client.getFeeRates({ - instType: 'SPOT', - instId: 'BTC-USDT', - }); - console.log('Fee rate rows:', feeRates.length); - } catch (error) { - console.error('Failed to get fee rates:', error); - } -} - -main(); -``` - -`getBalance()` reads the trading account. `getBalances()` reads assets in the funding account. They are different OKX account areas, so do not combine the results without retaining their source. - -Pending orders, recent order history, fills, positions, and balances are useful together when rebuilding [Account State](https://siebly.io/reference/glossary#accountstate). - -### Order management - -The complete demo REST API example above shows a safe place, query, and cancel flow. The same `RestClient` also exposes amend and batch methods: - -| Operation | SDK method | Result to inspect | -| ------------------- | ------------------------------------ | ------------------------------------------------------------ | -| Place one order | `submitOrder()` | Item `sCode`, `sMsg`, `ordId`, and `clOrdId` | -| Place a batch | `submitMultipleOrders()` | Every item's `sCode` and `sMsg` | -| Query one order | `getOrderDetails()` | Current `state`, filled size, average price, and identifiers | -| Amend one order | `amendOrder()` | Item `sCode`, `sMsg`, and `reqId` | -| Amend a batch | `amendMultipleOrders()` | Every item's result | -| Cancel one order | `cancelOrder()` | Item `sCode` and `sMsg` | -| Cancel a batch | `cancelMultipleOrders()` | Every item's result | -| Read pending orders | `getOrderList()` | Orders still working | -| Read recent history | `getOrderHistory()` and `getFills()` | Completed order and execution evidence | - -Identify application-owned orders with `clOrdId`. After placement, OKX also returns `ordId`; persist both. A typical amend uses: - -```typescript -import type { RestClient } from 'okx-api'; - -async function amendOrder( - client: RestClient, - instId: string, - clOrdId: string, - newPx: string, -) { - try { - const [amended] = await client.amendOrder({ - instId, - clOrdId, - newPx, - reqId: `amend${Date.now()}`, - }); - - if (!amended || amended.sCode !== '0') { - console.error(amended?.sMsg || 'OKX rejected the amendment.'); - return; - } - - return amended; - } catch (error) { - console.error('Failed to amend the order:', error); - } -} -``` - -`newPx` must follow the current instrument tick size and price limits. `reqId` identifies the amend request, while `clOrdId` continues to identify the order. - -For retries after a timeout, query by `clOrdId` before submitting another order. A missing response does not prove that OKX rejected the first request. - -### Spot, margin, and derivatives orders - -Order fields depend on the product and account configuration: - -| Workflow | Important fields | -| -------------- | ------------------------------------------------------------------------------------------- | -| Spot | `instId`, `tdMode: 'cash'`, `side`, `ordType`, and `sz` | -| Spot margin | Spot `instId` with `tdMode: 'cross'` or `isolated`, plus borrowing behavior where needed | -| Perpetual swap | Swap `instId`, margin `tdMode`, and position-side fields that match the account | -| Dated futures | A current futures `instId` from `getInstruments()`, margin mode, and position-side fields | -| Options | A current option `instId`, account-compatible trade mode, size, and a supported price field | - -In net position mode, derivatives requests normally use or imply `posSide: 'net'`. In long/short mode, opening and closing requests use `posSide: 'long'` or `short`. Do not copy a derivatives order request across accounts without reading `posMode`. - -Use `reduceOnly` only where the product, mode, and side support it. For margin and derivatives, check available size, leverage, margin mode, and current positions before sending an order. - -### More REST API groups - -`RestClient` also covers: - -- Algo orders, attached take-profit and stop-loss orders, trailing orders, and recurring buys. -- Grid and signal bots. -- Copy trading. -- Spread trading, block trading, RFQs, and market-maker protection. -- Funding-account transfers, deposits, withdrawals, and sub-accounts. -- Convert and easy-convert workflows. -- Earn, savings, staking, dual investment, and loan products. -- Event contracts where the account region supports them. - -Use the [OKX SDK endpoint map](./endpointFunctionList.md) to find the method for a specific endpoint, then check the matching regional OKX documentation for request rules and availability. - ---- - - - -## WebSocket streams - -`WebsocketClient` manages public, private, and business connections. It handles heartbeats, reconnects, and resubscriptions, while emitting the same lifecycle events for each connection. - -### Events and type guards - -| Event | Meaning | -| --------------- | ------------------------------------------------------ | -| `open` | A connection opened for the first time | -| `authenticated` | An authenticated connection completed login | -| `response` | Login, subscribe, unsubscribe, error, or control reply | -| `update` | Data from a subscribed channel | -| `reconnect` | The SDK is reconnecting a dropped connection | -| `reconnected` | The connection is open again | -| `exception` | A connection or listener error needs attention | -| `close` | A connection closed | - -The package exports type guards for handlers that receive unknown messages: - -```typescript -import { - isWsDataEvent, - isWsErrorEvent, - isWsSubscribeEvent, - WebsocketClient, -} from 'okx-api'; - -const ws = new WebsocketClient(); - -ws.on('response', (event) => { - if (isWsErrorEvent(event)) { - console.error('OKX WebSocket error:', event); - return; - } - - if (isWsSubscribeEvent(event)) { - console.log('Subscription acknowledged:', event); - } -}); - -ws.on('update', (event) => { - if (isWsDataEvent(event)) { - console.log(event.arg.channel, event.data); - } -}); -``` - -`isWsDataEvent()` checks for channel data, `isWsSubscribeEvent()` checks for a subscribe reply, and `isWsErrorEvent()` checks for an exchange error event. - -### Automatic channel routing - -The channel determines which OKX connection the SDK uses: - -| Connection | Example channels | Authentication | -| ---------- | -------------------------------------------------------------- | ---------------------- | -| Public | `tickers`, `books`, `trades`, `instruments`, `funding-rate` | Usually none | -| Private | `account`, `positions`, `orders`, `balance_and_position` | Required | -| Business | Candles, algo orders, grid channels, deposits, and withdrawals | Depends on the channel | - -Normal subscriptions do not need a manually selected `WS_KEY_MAP` value. Pass the channel arguments to `subscribe()` and let the SDK route them. A [WsKey](https://siebly.io/reference/glossary#ws-key) is still useful in logs because lifecycle events include the connection's `wsKey`. - -Some high-depth public books require authentication even though their data is public. Add credentials when using a channel whose OKX documentation requires an authenticated public connection. - -### Subscribe and shut down - -Keep the subscribed topics together, then close the WebSocket connections when the process shuts down: - - - -```typescript -import { type WsChannelSubUnSubRequestArg, WebsocketClient } from 'okx-api'; - -const ws = new WebsocketClient(); - -const topics = [ - { channel: 'tickers', instId: 'BTC-USDT' }, - { channel: 'books', instId: 'BTC-USDT' }, - { channel: 'candle1m', instId: 'BTC-USDT' }, -] satisfies WsChannelSubUnSubRequestArg[]; - -ws.on('update', (event) => { - console.log(event.arg.channel, event.data); -}); - -ws.on('exception', (error) => { - console.error('WebSocket exception:', error); -}); - -ws.subscribe(topics); - -function shutdown() { - ws.closeAll(); + emit>( + event: U, + ...args: Parameters[U]> + ): boolean; } +⋮---- +on>( + event: U, + listener: WSClientEventMap[U], + ): this; +⋮---- +emit>( + event: U, + ...args: Parameters[U]> + ): boolean; +⋮---- +export class WebsocketClient extends BaseWebsocketClient< +⋮---- +constructor(options?: WSClientConfigurableOptions, logger?: DefaultLogger) +⋮---- +/** + * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library + */ +public connectAll(): Promise[] +⋮---- +public connectPublic( + businessEndpoint?: boolean, +): Promise +⋮---- +public connectPrivate( + businessEndpoint?: boolean, +): Promise +⋮---- +/** + * Ensures the WS API connection is active and ready. + * + * You do not need to call this, but if you call this before making any WS API requests, + * it can accelerate the first request (by preparing the connection in advance). + */ +public connectWSAPI(): Promise +⋮---- +/** This call automatically ensures the connection is active AND authenticated before resolving */ +⋮---- +/** + * Subscribe to topics & track/persist them. They will be automatically resubscribed to if the connection drops/reconnects. + * @param wsEvents topic or list of topics + * @param isPrivateTopic optional - the library will try to detect private topics, you can use this to mark a topic as private (if the topic isn't recognised yet) + */ +public subscribe( + wsEvents: WsChannelSubUnSubRequestArg[] | WsChannelSubUnSubRequestArg, + isPrivateTopic?: boolean, +): Promise[] +⋮---- +// Format and batch topic requests by WsKey (resolved dynamically) +⋮---- +// Arrange into per-wsKey sorted lists +⋮---- +/** + * Unsubscribe from topics & remove them from memory. They won't be re-subscribed to if the connection reconnects. + * @param wsTopics topic or list of topics + * @param isPrivateTopic optional - the library will try to detect private topics, you can use this to mark a topic as private (if the topic isn't recognised yet) + */ +public unsubscribe( + wsEvents: WsChannelSubUnSubRequestArg[] | WsChannelSubUnSubRequestArg, + isPrivateTopic?: boolean, +) +⋮---- +// Format and batch topic requests by WsKey (resolved dynamically) +⋮---- +// Arrange into per-wsKey sorted lists +⋮---- +/** + * + * + * Internal methods required to integrate with the BaseWSClient + * + * + */ +⋮---- +public getMarketWsKey(type: 'private' | 'business'): WsKey +⋮---- +// returns private or business ws key for the active api market +// defaults to global +// automatically resolves to demo trading wsKeys under the hood (WSClient) +⋮---- +protected sendPingEvent(wsKey: WsKey): void +⋮---- +protected sendPongEvent(wsKey: WsKey): void +⋮---- +protected isWsPing(data: any): boolean +⋮---- +protected isWsPong(data: any): boolean +⋮---- +protected isPrivateTopicRequest( + _request: WsTopicRequest, + wsKey: WsKey, +): boolean +⋮---- +protected getPrivateWSKeys(): WsKey[] +⋮---- +protected isAuthOnConnectWsKey(wsKey: WsKey): boolean +⋮---- +protected async getWsUrl(wsKey: WsKey): Promise +⋮---- +protected getMaxTopicsPerSubscribeEvent(): number | null +⋮---- +/** + * @returns one or more correctly structured request events for performing a operations over WS. This can vary per exchange spec. + */ +protected async getWsRequestEvents( + operation: WSOperation, + requests: WsTopicRequest[], +): Promise>[]> +⋮---- +// Previously used to track topics in a request. Keeping this for subscribe/unsubscribe requests, no need for incremental values +⋮---- +/** + { + "op":"subscribe", + "args":[ + { + "channel": "tickers", + "instId": "BTC-USDT" + }, + { + "channel": "tickers", + "instId": "BTC-USDT" + } + ] + } + */ +⋮---- +// const request = { +// topic: 'tickers', +// payload: { instId: 'BTC-USDT' }, +// }; +// becomes: +// const request = { +// channel: 'ticker', +// instId: 'BTC-USDT', +// }; +⋮---- +private async signMessage( + paramsStr: string, + secret: string, + method: SignEncodeMethod, + algorithm: SignAlgorithm, +): Promise +⋮---- +protected async getWsAuthRequestEvent( + wsKey: WsKey, + skipIsPublicWsKeyCheck: boolean, +): Promise | null> +⋮---- +// Filter out failed accounts +⋮---- +private async getWsAuthSignature( + wsKey: WsKey, + credentials: APICredentials, +): Promise< +⋮---- +// const signatureExpiresAt = timestamp + 5; +⋮---- +/** + * Abstraction called to sort ws events into emittable event types (response to a request, data update, etc) + */ +protected resolveEmittableEvents( + wsKey: WsKey, + event: MessageEventLike, +): EmittableEvent[] +⋮---- +/** + * WS API response handling + */ +⋮---- +// const eg1 = { +// id: '2', +// op: 'order', +// code: '1', +// msg: '', +// data: [ +// { +// tag: '159881cb7207BCDE', +// ts: '1753783406701', +// ordId: '', +// clOrdId: '', +// sCode: '51008', +// sMsg: 'Order failed. Insufficient USDT balance in account.', +// }, +// ], +// inTime: '1753783406701275', +// outTime: '1753783406702251', +// wsKey: 'prodPrivate', +// }; +⋮---- +// check getPromiseRefForWSAPIRequest +⋮---- +// WS API Success +⋮---- +// messageType: typeof msg, +// messageString: JSON.stringify(msg), +⋮---- +// Successfully authenticated +⋮---- +// this.logger.trace(`Ws subscribe reply:`, { ...msg, wsKey }); +⋮---- +// Queue immediate reconnection workflow +⋮---- +// Emit notice to client for visibility +⋮---- +// messageType: typeof msg, +// messageString: JSON.stringify(msg), +⋮---- +// fallback emit anyway +⋮---- +/** + * OKX supports order placement via WebSockets. This is the WS API: + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order + * + * For convenient promise-wrapped usage of the WS API, instance the WebsocketAPIClient class exported by this SDK. + * + * For demo trading, set demoTrading:true in the WS Client config. + * + * @returns a promise that resolves/rejects when a matching response arrives + */ +async sendWSAPIRequest< + TWSKey extends keyof WsAPIWsKeyTopicMap, + TWSOperation extends WsAPIWsKeyTopicMap[TWSKey], + TWSParams extends WsAPITopicRequestParamMap[TWSOperation], + TWSAPIResponse extends + WsAPIOperationResponseMap[TWSOperation] = WsAPIOperationResponseMap[TWSOperation], + >( + rawWsKey: WsKey, + operation: TWSOperation, + params: TWSParams & { signRequest?: boolean }, + requestFlags?: WSAPIRequestFlags, +): Promise +⋮---- +// If demo trading, enforce demo wskey for WS API calls +⋮---- +// Ensure "args" is always wrapped as array +⋮---- +// Store deferred promise, resolved within the "resolveEmittableEvents" method while parsing incoming events +⋮---- +// Enriched WS API response includes wsKey & the request that was connected to the response +type DeferredWSAPIResponse = TWSAPIResponse & { + request: WSAPIRequestOKX & { wsKey: WsKey }; + }; +⋮---- +// Enrich returned promise with request context for easier debugging +⋮---- +// throw e; +⋮---- +// Send event +⋮---- +// Return deferred promise, so caller can await this call -process.once('SIGINT', shutdown); -``` - -There is no need to unsubscribe before `closeAll()`. Use `unsubscribe()` only when the application should stop receiving a topic while its other WebSocket connections remain active. - -### Private streams and recovery - -The SDK reconnects and resubscribes after a connection gap. That restores transport and subscription state, but it cannot recover updates that OKX sent while the connection was unavailable. - -Backfill private state through REST API before order logic relies on the stream again: - - - -```typescript -import { RestClient, WebsocketClient } from 'okx-api'; - -const credentials = { - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, -}; -const rest = new RestClient(credentials); -const ws = new WebsocketClient({ accounts: [credentials] }); - -async function refreshAccountState() { - const instrumentTypes = [ - 'SPOT', - 'MARGIN', - 'SWAP', - 'FUTURES', - 'OPTION', - ] as const; - - let balanceRows = 0; - let positionRows = 0; - let openOrderRows = 0; - let recentFillRows = 0; - - try { - const balances = await rest.getBalance(); - balanceRows = balances.length; - } catch (error) { - console.error('Failed to refresh balances:', error); - } - - try { - const positions = await rest.getPositions(); - positionRows = positions.length; - } catch (error) { - console.error('Failed to refresh positions:', error); - } - - for (const instType of instrumentTypes) { - try { - const openOrders = await rest.getOrderList({ instType }); - openOrderRows += openOrders.length; - } catch (error) { - console.error(`Failed to refresh ${instType} orders:`, error); - } - } - - try { - const fills = await rest.getFills({ limit: '100' }); - recentFillRows = fills.length; - } catch (error) { - console.error('Failed to refresh fills:', error); - } - - console.log('Account state refreshed:', { - balanceRows, - positionRows, - openOrderRows, - recentFillRows, - }); -} - -ws.on('reconnect', ({ wsKey }) => { - console.log('Pausing stream-dependent work:', wsKey); -}); - -ws.on('reconnected', ({ wsKey }) => { - console.log('Reconnected, refreshing private state:', wsKey); - refreshAccountState(); -}); - -ws.on('update', (event) => { - console.log(event.arg.channel, event.data); -}); - -ws.on('exception', (error) => { - console.error('WebSocket exception:', error); -}); - -ws.subscribe([ - { channel: 'account' }, - { channel: 'positions', instType: 'ANY' }, - { channel: 'orders', instType: 'ANY' }, -]); -``` - -A production application should replace the `console.log()` summary with one atomic state update and resume stream-dependent work only after the refresh succeeds. This is [REST Hydration](https://siebly.io/reference/glossary#rest-hydration) applied after a connection gap. - -For more detail on deciding which state needs repair, see [Scoped Recovery](https://siebly.io/reference/glossary#scoped-recovery), [Exchange State](https://siebly.io/reference/exchange-state), and [Runtime Workflows](https://siebly.io/reference/runtime-workflows). - ---- - - - -## WebSocket API - -The OKX WebSocket API sends order-management commands over an authenticated socket. `WebsocketAPIClient` handles connection setup, authentication, request IDs, response matching, and promise resolution. - -The main methods are: - -| SDK method | Operation | -| -------------------------- | -------------------------------------- | -| `submitNewOrder()` | Place one order | -| `submitMultipleOrders()` | Place a batch | -| `amendOrder()` | Amend one order | -| `amendMultipleOrders()` | Amend a batch | -| `cancelOrder()` | Cancel one order | -| `cancelMultipleOrders()` | Cancel a batch | -| `massCancelOrders()` | Cancel orders for an instrument family | -| `submitSpreadOrder()` | Place one spread order | -| `amendSpreadOrder()` | Amend one spread order | -| `cancelSpreadOrder()` | Cancel one spread order | -| `massCancelSpreadOrders()` | Cancel spread orders | - -Standard order commands use the private WebSocket. Spread commands use the business WebSocket. The wrapper selects the connection for each method. - -`connectWSAPI()` is optional. Calling it during startup prepares and authenticates the required connection before the first command. The first command can also open the connection automatically. - -### Check acknowledgements at both levels - -Every response has a top-level `code`, `msg`, and `data` array. Each item in `data` has its own `sCode` and `sMsg`. - -Use both checks: - -```typescript -type OkxCommandItem = { - sCode: string; - sMsg: string; - ordId?: string; - clOrdId?: string; -}; - -function assertOkxCommandAccepted(response: { - code: string; - msg: string; - data: OkxCommandItem[]; -}) { - if (response.code !== '0') { - throw new Error(response.msg || `OKX command failed: ${response.code}`); - } - - const failedItems = response.data.filter((item) => item.sCode !== '0'); - - if (failedItems.length > 0) { - throw new Error( - failedItems - .map((item) => `${item.clOrdId || item.ordId}: ${item.sMsg}`) - .join('; '), - ); - } -} -``` - -Batch commands can contain a mix of successful and failed items. Do not treat a top-level success as proof that every order was accepted. - -For current WebSocket order placement, prefer an `instIdCode` obtained from `getInstruments()`. Identify amend and cancel commands with `ordId` or `clOrdId` as required by the current OKX operation. - -An accepted WebSocket API command is still not final order state. Watch the private `orders` channel, then use REST API when an update is missing or the connection has a gap. - -`WebsocketClient.sendWSAPIRequest()` is available for lower-level operation calls. Use `WebsocketAPIClient` for the typed convenience methods unless the wrapper does not yet expose the operation you need. - -See the repository examples for both approaches: - -- [Promise-based WebSocket API client](../examples/Websocket/WS-API/ws-api-client.ts) -- [Lower-level WebSocket API requests](../examples/Websocket/WS-API/ws-api-trade-raw.ts) - ---- - - - -## Demo trading - -OKX demo trading uses simulated accounts and separate demo API keys. It is the right place to test authentication, request fields, permissions, order acknowledgements, private streams, and reconciliation before a live order. - -Set the same option on whichever client the workflow uses: - -```typescript -import { RestClient, WebsocketAPIClient, WebsocketClient } from 'okx-api'; - -const credentials = { - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, -}; - -const rest = new RestClient({ - ...credentials, - demoTrading: true, -}); - -const streams = new WebsocketClient({ - accounts: [credentials], - demoTrading: true, -}); +================ +File: .gitignore +================ +!.gitkeep +.DS_STORE +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json +pids +*.pid +*.seed +*.pid.lock +node_modules/ +.npm +.eslintcache +.node_repl_history +*.tgz +.yarn-integrity +.env +.env.test +.cache +lib +dist +bundleReport.html +.history/ +.idea +privaterepotracker +restClientRegex.ts +testfile.ts +localtest.sh +coverage/ -const wsApi = new WebsocketAPIClient({ - accounts: [credentials], - demoTrading: true, -}); -``` +repomix.sh -For a complete copy-pastable order flow with credential checks and an explicit opt-in, use the [demo REST API example](#5-first-rest-api-order-in-demo-trading) or [demo WebSocket API example](#6-first-websocket-api-order-command) above. +================ +File: .npmrc +================ +min-release-age=30 +save-exact=true -With `demoTrading: true`, `RestClient` adds the required simulated-trading header. The WebSocket clients select the demo public, private, and business hosts. Do not use `market: 'demo'`. +================ +File: .nvmrc +================ +v24.18.0 -Demo trading does not support every funding or account action. Keep demo and live credentials in separate secret-store entries, and do not treat demo liquidity or fills as representative of live trading. +================ +File: docs/OKX_SDK_QUICKSTART_GUIDE.md +================ + -Regional routing and demo trading can be combined. Set both `market` and `demoTrading: true` on each client. See [Demo Trading](https://siebly.io/reference/glossary#demo-trading) for the terminology used across Siebly guides. +# OKX API JavaScript Tutorial for Node.js and TypeScript ---- + - +> [!TIP] +> Read this guide in tutorial format on the Siebly website: [OKX JavaScript REST API and WebSocket Tutorial](https://siebly.io/sdk/okx/javascript/tutorial) -## Regional API routing + -Use the API group associated with the domain where the OKX account was registered. The SDK applies that choice to REST API, public WebSocket, private WebSocket, business WebSocket, and WebSocket API connections. +This tutorial uses [`okx-api`](https://www.npmjs.com/package/okx-api), Siebly's Node.js, JavaScript, and TypeScript SDK for OKX. It covers public and private REST API calls, live WebSocket streams, demo orders, WebSocket API commands, regional API routing, and proxies. -| Account API group | SDK `market` | REST API host | WebSocket host family | -| ----------------------------- | ---------------------------------- | ----------------- | --------------------- | -| Global compatibility default | Omit it, or use `prod` or `GLOBAL` | `www.okx.com` | `ws.okx.com` | -| Global OpenAPI host | `OPENAPI_GLOBAL` | `openapi.okx.com` | `ws.okx.com` | -| EEA account from `my.okx.com` | `EEA` | `eea.okx.com` | `wseea.okx.com` | -| Account from `app.okx.com` | `US` | `us.okx.com` | `wsus.okx.com` | +The SDK handles OKX request signing, API passphrase authentication, regional hosts, demo trading, WebSocket channel routing, heartbeats, reconnects, resubscriptions, and WebSocket API response matching. Request and response types are included. -`OPENAPI_GLOBAL` changes the REST API host but uses the same WebSocket hosts as `GLOBAL`. +**Key links** -Pass the same `market` to every client used by one account: +- OKX JavaScript SDK by Siebly: [`okx-api`](https://www.npmjs.com/package/okx-api) +- GitHub repository: [`sieblyio/okx-api`](https://github.com/sieblyio/okx-api) +- SDK endpoint map: [OKX JavaScript endpoint reference](./endpointFunctionList.md) +- SDK examples: [OKX SDK examples](https://siebly.io/examples/OKX) +- OKX Global API docs: [OKX API documentation](https://www.okx.com/docs-v5/en/) +- OKX EEA API docs: [OKX EEA API documentation](https://my.okx.com/docs-v5/en/) +- OKX US API docs: [OKX US API documentation](https://app.okx.com/docs-v5/en/) +- Trading-system terms: [Siebly glossary](https://siebly.io/reference/glossary) +- More JavaScript and TypeScript SDKs: [Siebly.io](https://siebly.io) - +--- -```typescript -import { RestClient, WebsocketAPIClient, WebsocketClient } from 'okx-api'; + -const market = 'EEA' as const; -const credentials = { - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, -}; - -const rest = new RestClient({ - ...credentials, - market, -}); +## Why use the SDK -const streams = new WebsocketClient({ - accounts: [credentials], - market, -}); +An OKX integration has more than one connection path: -const wsApi = new WebsocketAPIClient({ - accounts: [credentials], - market, -}); -const wsApiConnection = wsApi.getWSClient(); +- Private REST API calls require an API key, secret, passphrase, timestamp, and HMAC signature. +- Public, private, and business WebSocket channels use different endpoints. +- Demo trading uses separate API keys, REST API headers, and WebSocket hosts. +- Global, EEA, and US accounts use different API host groups. +- WebSocket connections need heartbeat, reconnect, and resubscribe handling. +- WebSocket API commands need unique request IDs and matching responses. -async function main() { - try { - const time = await rest.getSystemTime({}); - console.log('REST API connected:', time[0]?.ts); - } catch (error) { - console.error('REST API connection failed:', error); - } +The SDK handles those mechanics and exposes three main clients: - streams.subscribe({ - channel: 'account', - }); +| Workflow | SDK client | Use it for | +| ----------------- | -------------------- | ------------------------------------------------------------------------------------ | +| REST API | `RestClient` | Public data, account reads, trading, funding, transfers, and broad endpoint coverage | +| WebSocket streams | `WebsocketClient` | Public market data, private account state, and business channels | +| WebSocket API | `WebsocketAPIClient` | Awaitable order, amend, cancel, batch, and spread commands over WebSocket | - try { - await wsApi.connectWSAPI(); - console.log('WebSocket API connected'); - } catch (error) { - console.error('WebSocket API connection failed:', error); - shutdown(); - } -} +Most applications use `RestClient` for initial state and reconciliation, then add `WebsocketClient` for live updates. Use `WebsocketAPIClient` when you want supported trading commands to use a persistent authenticated socket. -function shutdown() { - streams.closeAll(); - wsApiConnection.closeAll(); -} +--- -process.once('SIGINT', shutdown); + -main(); -``` +## Installation and API keys -Change `market` to the API group for the account. Product and endpoint availability can differ by region, so use the corresponding [Global](https://www.okx.com/docs-v5/en/), [EEA](https://my.okx.com/docs-v5/en/), or [US](https://app.okx.com/docs-v5/en/) OKX documentation. +Install the SDK: -`baseUrl` and `wsUrl` are custom overrides. Use `market` for the supported regional groups so REST API and every WebSocket connection remain aligned. +```bash +npm install okx-api +``` -A proxy does not change an account's API group. Regional routing selects the OKX hosts; a proxy only changes the network path used to reach them. +Other npm-compatible package managers work too: ---- +```bash +pnpm install okx-api +yarn add okx-api +``` - +Public market data does not need credentials. Private REST API calls, private WebSocket subscriptions, and WebSocket API commands need all three values: -## Proxies for REST API and WebSocket +| SDK option | OKX credential | +| ----------- | ---------------------------------------------- | +| `apiKey` | API key | +| `apiSecret` | API secret | +| `apiPass` | Passphrase chosen when the API key was created | -Proxies are useful when a deployment needs a stable egress IP, must pass through an approved corporate network, or uses controlled network failover. They do not replace OKX regional routing or account eligibility checks. +`apiPass` is the API-key passphrase, not the password used to sign in to OKX. -The broader [Using proxy with Siebly SDKs](https://siebly.io/blog/using-proxy-with-siebly-sdks) article covers the shared constructor pattern. The examples below use the current `okx-api` options directly. +Create and manage keys on the site associated with the account: -### HTTP or HTTPS proxy +- [OKX Global API keys](https://www.okx.com/account/my-api) +- [OKX EEA API keys](https://my.okx.com/account/my-api) +- [OKX US API keys](https://app.okx.com/account/my-api) -Install the agent: +The private examples use these environment variables: ```bash -npm install okx-api https-proxy-agent +OKX_API_KEY +OKX_API_SECRET +OKX_API_PASSPHRASE ``` -Set `OKX_PROXY_URL` to the full proxy URL, including credentials when required. - -This public check sends both REST API and WebSocket traffic through the same proxy: +Use a secret manager in deployed applications. Keep live and demo credentials separate, grant only the permissions the application needs, and use an IP whitelist when the outbound addresses are stable. Nothing in this tutorial requires withdrawal permission. - +Pass the environment variables directly when creating a private client: ```typescript -import { HttpsProxyAgent } from 'https-proxy-agent'; -import { RestClient, WebsocketClient } from 'okx-api'; +import { RestClient } from 'okx-api'; -const proxyUrl = process.env.OKX_PROXY_URL; +const client = new RestClient({ + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, +}); +``` -if (!proxyUrl) { - throw new Error('Set OKX_PROXY_URL before running this example.'); -} +The TypeScript `!` tells the compiler that each environment variable is set. Do not log the credentials. Private signing also depends on an accurate system clock and a maintained Node.js release with the Web Crypto API. -function errorMessage(error: unknown): string { - return error instanceof Error ? error.message : String(error); -} +--- -const proxyAgent = new HttpsProxyAgent(proxyUrl); -const market = 'OPENAPI_GLOBAL' as const; + -const rest = new RestClient( - { market }, - { - httpsAgent: proxyAgent, - proxy: false, - }, -); +## OKX products and request vocabulary -const ws = new WebsocketClient({ - market, - wsOptions: { - agent: proxyAgent, - }, -}); +OKX uses an instrument type to identify a product family and an instrument ID to identify the exact market: -ws.on('open', ({ wsKey }) => { - console.log('WebSocket connected through proxy:', wsKey); -}); +| Product | Typical `instType` | `instId` example | Common `tdMode` | +| --------------- | ------------------ | --------------------------------------------------------- | ------------------------ | +| Spot | `SPOT` | `BTC-USDT` | `cash` | +| Spot margin | `MARGIN` | `BTC-USDT` | `cross` or `isolated` | +| Perpetual swap | `SWAP` | `BTC-USDT-SWAP` | `cross` or `isolated` | +| Dated futures | `FUTURES` | Query current instruments for an active expiry | `cross` or `isolated` | +| Options | `OPTION` | Query current instruments for an active expiry and strike | Depends on account setup | +| Event contracts | `EVENTS` | Query current instruments and regional availability | Product-specific | -ws.on('update', (event) => { - console.log(event.arg.channel, event.data); -}); +Do not hardcode dated futures or option instrument IDs in long-lived code. Use `getInstruments()` to find active contracts and read their expiry, tick size, lot size, and minimum size. -ws.on('exception', (error) => { - console.error('WebSocket proxy error:', errorMessage(error)); -}); +The fields used most often are: -async function main() { - try { - const time = await rest.getSystemTime({}); - console.log('REST API connected through proxy:', time[0]?.ts); - } catch (error) { - console.error('REST API proxy request failed:', errorMessage(error)); - } +- `instType`: the product family, such as `SPOT`, `SWAP`, or `OPTION`. +- `instId`: the exact instrument, such as `BTC-USDT` or `BTC-USDT-SWAP`. +- `instFamily`: a derivatives family used by some requests and channels. +- `uly`: the underlying used by some futures and options endpoints. +- `tdMode`: `cash`, `cross`, `isolated`, or another mode supported by that request. +- `posSide`: `net`, `long`, or `short`, depending on the account's position mode. +- `clOrdId`: your own identifier for an order. - ws.subscribe({ - channel: 'tickers', - instId: 'BTC-USDT', - }); -} +Use a unique `clOrdId` for each application-owned order. It makes retries and reconciliation easier. See [Custom Order ID](https://siebly.io/reference/glossary#custom-order-id) in the Siebly glossary. -process.once('SIGINT', () => { - ws.closeAll(); -}); +Account mode and position mode affect which order fields are valid. Read `getAccountConfiguration()` before building derivatives order logic. The tutorial does not change either setting. -main(); -``` +### REST API, streams, and the WebSocket API -REST API networking options belong in the second `RestClient` argument: +These are separate workflows: -- `httpsAgent` carries HTTPS requests through the proxy agent. -- `proxy: false` prevents Axios from applying another proxy configuration on top of that agent. +| Flow | SDK client | Best for | +| ----------------- | -------------------- | --------------------------------------------------------------------------------- | +| REST API | `RestClient` | Public reads, account reads, trading, broad endpoint coverage, and reconciliation | +| WebSocket streams | `WebsocketClient` | Live market, order, balance, and position updates | +| WebSocket API | `WebsocketAPIClient` | Awaitable order-management commands over an authenticated socket | -WebSocket networking options belong in `wsOptions.agent`. The same setting works for public streams, private streams, business streams, and `WebsocketAPIClient`. +A stream update and a WebSocket API acknowledgement are not interchangeable. An acknowledgement reports whether OKX accepted a command. Order and fill state still comes from the private streams or a REST API query. -OKX authenticates private WebSockets over the socket. Unlike exchanges that fetch a listen key or WebSocket token through REST API first, OKX does not need a second REST API proxy setting inside its WebSocket client. +--- -### Private streams and WebSocket API through a proxy + -Use the same agent with credentials: +## Start building: first calls - +Run the public REST API example first. Then add the client that matches the workflow you need. -```typescript -import { HttpsProxyAgent } from 'https-proxy-agent'; -import { WebsocketAPIClient, WebsocketClient } from 'okx-api'; +### 1. First public REST API request -const proxyUrl = process.env.OKX_PROXY_URL; +`RestClient` works without credentials for public endpoints. -if (!proxyUrl) { - throw new Error('Set OKX_PROXY_URL before running this example.'); -} + -function errorMessage(error: unknown): string { - return error instanceof Error ? error.message : String(error); -} +```typescript +import { RestClient } from 'okx-api'; -const credentials = { - apiKey: process.env.OKX_API_KEY!, - apiSecret: process.env.OKX_API_SECRET!, - apiPass: process.env.OKX_API_PASSPHRASE!, -}; -const proxyAgent = new HttpsProxyAgent(proxyUrl); -const market = 'OPENAPI_GLOBAL' as const; +const client = new RestClient(); -const streams = new WebsocketClient({ - accounts: [credentials], - market, - wsOptions: { - agent: proxyAgent, - }, -}); +async function main() { + try { + const serverTime = await client.getSystemTime({}); + console.log('Server time:', serverTime[0]?.ts); + } catch (error) { + console.error('Failed to get server time:', error); + } -const wsApi = new WebsocketAPIClient({ - accounts: [credentials], - market, - attachEventListeners: false, - wsOptions: { - agent: proxyAgent, - }, -}); -const wsApiConnection = wsApi.getWSClient(); + try { + const instruments = await client.getInstruments({ + instType: 'SPOT', + instId: 'BTC-USDT', + }); + console.log('Instrument:', instruments[0]?.instId); + } catch (error) { + console.error('Failed to get instruments:', error); + } -streams.on('authenticated', ({ wsKey }) => { - console.log('Private stream authenticated:', wsKey); -}); -streams.on('exception', (error) => { - console.error('Private stream error:', errorMessage(error)); -}); -wsApiConnection.on('authenticated', ({ wsKey }) => { - console.log('WebSocket API authenticated:', wsKey); -}); -wsApiConnection.on('exception', (error) => { - console.error('WebSocket API error:', errorMessage(error)); -}); + try { + const ticker = await client.getTicker({ instId: 'BTC-USDT' }); + console.log('Last price:', ticker[0]?.last); + } catch (error) { + console.error('Failed to get ticker:', error); + } -async function main() { - streams.subscribe([ - { channel: 'account' }, - { channel: 'orders', instType: 'ANY' }, - ]); + try { + const orderBook = await client.getOrderBook({ + instId: 'BTC-USDT', + sz: '5', + }); + console.log('Best bid:', orderBook[0]?.bids[0]); + } catch (error) { + console.error('Failed to get order book:', error); + } try { - await wsApi.connectWSAPI(); - console.log('Private connections are ready'); + const candles = await client.getCandles({ + instId: 'BTC-USDT', + bar: '1m', + limit: '5', + }); + console.log('Latest candle:', candles[0]); } catch (error) { - console.error('WebSocket API connection failed:', errorMessage(error)); - streams.closeAll(); - wsApiConnection.closeAll(); + console.error('Failed to get candles:', error); } } -process.once('SIGINT', () => { - streams.closeAll(); - wsApiConnection.closeAll(); -}); - main(); ``` -This validates private authentication without placing an order. Add `demoTrading: true` to both clients when testing with demo keys. - -### SOCKS5 proxy - -Install the SOCKS agent: +Run it with a TypeScript runner or compile it with your project: ```bash -npm install okx-api socks-proxy-agent +npx tsx first-okx-api-call.ts ``` -Use `SocksProxyAgent` in the same REST API and WebSocket positions: +Successful SDK methods return the parsed OKX `data` value. Most OKX REST API endpoints return an array, so `getTicker()` resolves to the ticker array rather than the outer `{ code, msg, data }` envelope. Exchange errors and non-success HTTP responses reject the promise. - +### 2. First private REST API request -```typescript -import { RestClient, WebsocketClient } from 'okx-api'; -import { SocksProxyAgent } from 'socks-proxy-agent'; +Private calls use the same client with `apiKey`, `apiSecret`, and `apiPass`. -const proxyUrl = process.env.OKX_SOCKS_PROXY_URL; + -if (!proxyUrl) { - throw new Error('Set OKX_SOCKS_PROXY_URL before running this example.'); -} +```typescript +import { RestClient } from 'okx-api'; -function errorMessage(error: unknown): string { - return error instanceof Error ? error.message : String(error); -} +const client = new RestClient({ + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, +}); -const proxyAgent = new SocksProxyAgent(proxyUrl); +async function main() { + try { + const configuration = await client.getAccountConfiguration(); + console.log({ + accountMode: configuration[0]?.acctLv, + positionMode: configuration[0]?.posMode, + }); + } catch (error) { + console.error('Failed to get account configuration:', error); + } -const rest = new RestClient( - {}, - { - httpsAgent: proxyAgent, - proxy: false, - }, -); + try { + const balances = await client.getBalance(); + console.log({ + totalEquity: balances[0]?.totalEq, + currencies: balances[0]?.details.map((item) => item.ccy), + }); + } catch (error) { + console.error('Failed to get trading balances:', error); + } -const ws = new WebsocketClient({ - wsOptions: { - agent: proxyAgent, - }, -}); + try { + const positions = await client.getPositions(); + console.log('Position count:', positions.length); + } catch (error) { + console.error('Failed to get positions:', error); + } -async function main() { try { - const time = await rest.getSystemTime({}); - console.log('REST API connected through SOCKS5:', time[0]?.ts); + const openOrders = await client.getOrderList({ instType: 'SPOT' }); + console.log('Open order count:', openOrders.length); } catch (error) { - console.error('SOCKS5 REST API request failed:', errorMessage(error)); + console.error('Failed to get open orders:', error); } - ws.subscribe({ - channel: 'tickers', - instId: 'BTC-USDT', - }); + try { + const fills = await client.getFills({ instType: 'SPOT', limit: '20' }); + console.log('Recent fill count:', fills.length); + } catch (error) { + console.error('Failed to get fills:', error); + } } -process.once('SIGINT', () => { - ws.closeAll(); -}); - main(); ``` -### Proxy checks - -- Keep proxy URLs and credentials in environment variables or a secret manager. -- URL-encode usernames and passwords when constructing a proxy URL from separate values. -- Make sure the proxy egress IP matches the API key's OKX IP whitelist. -- Test a public REST API call and public WebSocket subscription before private authentication. -- Measure request, connection, and reconnect latency through the proxy. -- Treat repeated HTTP 407 responses, TLS errors, and WebSocket reconnect loops as network failures. -- Keep the host clock synchronized. Extra network latency does not change how OKX signatures are calculated. -- Do not add a generic `recvWindow` setting. `okx-api` does not expose one. -- The SDK does not rotate proxy endpoints. Handle endpoint selection outside the client when rotation is required. +Read-only API keys are sufficient for this example. `getBalance()` returns trading-account balances. Funding-account assets use `getBalances()`, which is a different endpoint covered later. ---- +### 3. First public WebSocket stream - +Pass the inner channel objects from the OKX `args` array to `subscribe()`. The SDK builds the outer subscribe message and selects the correct WebSocket connection. -## Production notes + -Before an OKX integration trades unattended: +```typescript +import { WebsocketClient } from 'okx-api'; -1. Roll out in stages: public REST API, private read-only REST API, public streams, private streams, demo writes, then small controlled live tests. -2. Use a unique `clOrdId` on every application-owned order. -3. Check REST API item-level `sCode` values and WebSocket API top-level plus item-level codes. -4. Treat command acceptance as pending until a private stream or REST API query confirms the resulting order state. -5. Reconcile balances, positions, pending orders, recent history, and fills after a private stream gap. -6. Keep the system clock synchronized. OKX rejects stale signed requests. -7. Respect IP, user, instrument, and connection rate limits from the relevant OKX endpoint documentation. -8. Keep `market`, account mode, position mode, `tdMode`, `instType`, and `instId` in structured logs. -9. Keep live, demo, and regional credentials separate. -10. Keep credentials out of frontend code, exceptions, and logs. -11. Monitor proxy availability, latency, and egress IP when a proxy is enabled. -12. Unsubscribe or call `closeAll()` during a controlled shutdown. +const ws = new WebsocketClient(); -The SDK restores WebSocket connections and cached subscriptions. Your application must still recover state, reconcile orders, and decide when writes can resume after a gap. +ws.on('open', ({ wsKey }) => { + console.log('Connected:', wsKey); +}); ---- +ws.on('response', (event) => { + console.log('WebSocket response:', event); +}); - +ws.on('update', (event) => { + console.log(event.arg.channel, event.data); +}); -## FAQ +ws.on('reconnect', ({ wsKey }) => { + console.log('Reconnecting:', wsKey); +}); -### Do public OKX API calls need keys? +ws.on('reconnected', ({ wsKey }) => { + console.log('Reconnected:', wsKey); +}); -Most public REST API endpoints and public WebSocket channels do not. Private account methods, private channels, WebSocket API commands, and a small number of high-depth public channels require credentials. +ws.on('exception', (error) => { + console.error('WebSocket exception:', error); +}); -### What is `apiPass`? +ws.subscribe([ + { channel: 'tickers', instId: 'BTC-USDT' }, + { channel: 'books', instId: 'BTC-USDT' }, + { channel: 'trades', instId: 'BTC-USDT' }, + { channel: 'candle1m', instId: 'BTC-USDT' }, +]); +``` -It is the passphrase chosen when the OKX API key was created. It is not the account login password. +Ticker, book, and trade channels use the public WebSocket. Candles use the business WebSocket. One `WebsocketClient` routes both connections, tracks the subscriptions, and resubscribes after a reconnect. -### Which SDK client should I use? +The `response` event carries subscription and control replies. Live channel data arrives on `update`. -Use `RestClient` for request/response calls and broad endpoint coverage, `WebsocketClient` for live channel updates, and `WebsocketAPIClient` for supported promise-based commands over WebSocket. Many applications use all three. +### 4. First private WebSocket stream -### Why do REST API methods return arrays? +Private channels need credentials in the client's `accounts` array. -The SDK returns the parsed OKX `data` value after a successful call. OKX commonly puts result rows in a `data` array, including endpoints that normally return one row. + -### What is the difference between `SPOT`, `MARGIN`, `SWAP`, `FUTURES`, and `OPTION`? +```typescript +import { WebsocketClient } from 'okx-api'; -They are OKX instrument types. Spot and Margin use cash-market instrument IDs, Swap identifies perpetual contracts, Futures identifies dated contracts, and Option identifies option contracts. Query `getInstruments()` for current product details. +const ws = new WebsocketClient({ + accounts: [ + { + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, + }, + ], +}); -### What is the difference between `instType`, `instId`, and `instFamily`? +ws.on('open', ({ wsKey }) => { + console.log('Connected:', wsKey); +}); -`instType` is a product family, `instId` is one exact instrument, and `instFamily` groups related derivatives. The method's TypeScript request type shows which one it needs. +ws.on('authenticated', ({ wsKey }) => { + console.log('Authenticated:', wsKey); +}); -### Why did an order fail under the current account mode? +ws.on('response', (event) => { + console.log('WebSocket response:', event); +}); -Valid `tdMode`, `posSide`, leverage, and margin fields depend on account mode and position mode. Read `getAccountConfiguration()`, then build requests for that configuration instead of copying fields from another account. +ws.on('update', (event) => { + console.log(event.arg.channel, event.data); +}); -### Is OKX demo trading the same as testnet? +ws.on('reconnect', ({ wsKey }) => { + console.log('Reconnecting:', wsKey); +}); -No. The SDK uses OKX demo trading with separate demo API keys and `demoTrading: true`. Do not use testnet flags from another exchange SDK. +ws.on('reconnected', ({ wsKey }) => { + console.log('Reconnected:', wsKey); +}); -### Why should I check both `code` and `sCode`? +ws.on('exception', (error) => { + console.error('WebSocket exception:', error); +}); -WebSocket API responses have a top-level command result and item-level results. REST API order methods return the parsed items, whose `sCode` values can report individual failures. Batch requests can have mixed outcomes. +ws.subscribe([ + { channel: 'account' }, + { channel: 'positions', instType: 'ANY' }, + { channel: 'orders', instType: 'ANY' }, +]); +``` -### Why did a candle subscription open a business WebSocket? +The SDK connects and authenticates when the first private subscription needs it. Use `response` to check the [Subscription Acknowledgement](https://siebly.io/reference/glossary#subscription-acknowledgement), then process channel data from `update`. -OKX routes candle channels through its business WebSocket. `WebsocketClient` detects the channel and selects that connection automatically. +OKX can publish related state changes on several channels. Account, position, order, and fill handling should share one consistent account-state model. -### Which regional `market` value should I use? +### 5. First REST API order in demo trading -Use the group associated with the account's registration domain: the Global default or `OPENAPI_GLOBAL`, `EEA` for `my.okx.com`, and `US` for `app.okx.com`. +This example can only place a demo order. It hardcodes `demoTrading: true`, requires separate demo API keys, and exits unless `OKX_PLACE_DEMO_ORDER=true` is set. -### Can regional routing and demo trading be combined? +It reads the current instrument rules and places a post-only buy at the current best bid, then queries and cancels the order if it is still open. -Yes. Pass both the regional `market` and `demoTrading: true` to every client in the workflow, using demo keys for that account region. + -### How do I proxy REST API calls? +```typescript +import { RestClient } from 'okx-api'; -Pass an Axios-compatible proxy agent as `httpsAgent` in the second `RestClient` argument. When using an agent, set `proxy: false`. +if (process.env.OKX_PLACE_DEMO_ORDER !== 'true') { + throw new Error('Set OKX_PLACE_DEMO_ORDER=true to place the demo order.'); +} -### How do I proxy WebSocket streams and WebSocket API commands? +const client = new RestClient({ + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, + demoTrading: true, +}); -Pass the agent as `wsOptions.agent` to `WebsocketClient` or `WebsocketAPIClient`. +async function main() { + const instId = 'BTC-USDT'; -### Does a proxy change request signing? + let instrument; + try { + [instrument] = await client.getInstruments({ + instType: 'SPOT', + instId, + }); + } catch (error) { + console.error('Failed to get instrument rules:', error); + return; + } -No. The SDK signs private requests locally before sending them. A proxy changes the network route, so latency and egress IP still need monitoring. + let ticker; + try { + [ticker] = await client.getTicker({ instId }); + } catch (error) { + console.error('Failed to get the ticker:', error); + return; + } -### Can I use `okx-api` from plain JavaScript? + if (!instrument || !ticker) { + console.error(`No demo market data returned for ${instId}.`); + return; + } -Yes. The package supports ESM imports and CommonJS `require()`. Remove TypeScript annotations when using JavaScript: + if (!ticker.bidPx) { + console.error(`No best bid returned for ${instId}.`); + return; + } -```javascript -const { RestClient } = require('okx-api'); + const clOrdId = `sieblyDemo${Date.now()}`; -const client = new RestClient(); -client.getTicker({ instId: 'BTC-USDT' }).then(console.log); -``` + let placed; + try { + [placed] = await client.submitOrder({ + instId, + tdMode: 'cash', + side: 'buy', + ordType: 'post_only', + sz: instrument.minSz, + px: ticker.bidPx, + clOrdId, + }); + } catch (error) { + console.error('Failed to submit the demo order:', error); + return; + } ---- + if (!placed || placed.sCode !== '0') { + console.error(placed?.sMsg || 'OKX rejected the demo order.'); + return; + } - + console.log('Demo order accepted:', { + ordId: placed.ordId, + clOrdId: placed.clOrdId, + }); -## Next steps + let order; + try { + [order] = await client.getOrderDetails({ instId, clOrdId }); + console.log('Current order state:', order?.state); + } catch (error) { + console.error('Failed to query the demo order:', error); + } -- [OKX JavaScript SDK by Siebly](https://siebly.io/sdk/okx/javascript) -- [`okx-api` on npm](https://www.npmjs.com/package/okx-api) -- [OKX SDK source on GitHub](https://github.com/tiagosiebler/okx-api) -- [OKX SDK examples on Siebly](https://siebly.io/examples/OKX) -- [OKX SDK endpoint map](./endpointFunctionList.md) -- [OKX Global API documentation](https://www.okx.com/docs-v5/en/) -- [OKX EEA API documentation](https://my.okx.com/docs-v5/en/) -- [OKX US API documentation](https://app.okx.com/docs-v5/en/) -- [Siebly trading-system glossary](https://siebly.io/reference/glossary) -- [Siebly Exchange State reference](https://siebly.io/reference/exchange-state) -- [Siebly Runtime Workflows reference](https://siebly.io/reference/runtime-workflows) + if (!order || ['live', 'partially_filled'].includes(order.state)) { + try { + const [cancelled] = await client.cancelOrder({ instId, clOrdId }); -================ -File: examples/Auth/fasterHmacSign.ts -================ -import { createHmac } from 'crypto'; -⋮---- -import { - DefaultLogger, - RestClient, - WebsocketClient, -} from '../../src/index.js'; -⋮---- -// or -// import { createHmac } from 'crypto'; -// import { DefaultLogger, RestClient, WebsocketClient } from 'okx-api'; -⋮---- -/** - * Injecting a custom signMessage function. - * - * As of version 3.0.0 of the okx-api Node.js/TypeScript/JavaScript - * SDK for OKX, the SDK uses the Web Crypto API for signing requests. - * While it is compatible with Node and Browser environments, it is - * slightly slower than using Node's native crypto module (only - * available in backend Node environments). - * - * For latency sensitive users, you can inject the previous node crypto sign - * method (or your own even faster implementation), if this change affects you. - * - * This example demonstrates how to inject a custom sign function, to achieve - * the same peformance as seen before the Web Crypto API was introduced. - * - * For context on standard usage, the "signMessage" function is used: - * - During every single API call - * - After opening a new private WebSocket connection - */ -⋮---- -// If running from CLI in unix, you can pass env vars as such: -// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/rest-private-trade.ts -⋮---- -// note the single quotes, preventing special characters such as $ from being incorrectly passed -⋮---- -// apiKey: 'apiKeyHere', -⋮---- -// apiSecret: 'apiSecretHere', -⋮---- -// apiPass: 'apiPassHere', -/** - * Overkill in almost every case, but if you need any optimisation available, - * you can inject a faster sign mechanism such as node's native createHmac: - */ -⋮---- -// Optional, uncomment the "trace" override to log a lot more info about what the WS client is doing -⋮---- -// trace: (...params) => console.log('trace', ...params), -⋮---- -// For private topics, include one or more accounts in an array. Otherwise only public topics will work -⋮---- -/** - * Overkill in almost every case, but if you need any optimisation available, - * you can inject a faster sign mechanism such as node's native createHmac: - */ -⋮---- -function setWsClientEventListeners( - websocketClient: WebsocketClient, - accountRef: string, -): Promise -⋮---- -// console.log('raw message received ', JSON.stringify(data, null, 2)); -⋮---- -// Simple promise to ensure we're subscribed before trying anything else -⋮---- -// Start trading + if (!cancelled || cancelled.sCode !== '0') { + console.error(cancelled?.sMsg || 'OKX rejected the cancellation.'); + return; + } -================ -File: examples/Rest/app.okx.com.ts -================ -import { RestClient, WebsocketClient } from '../../src/index.js'; -⋮---- -// or -// import { RestClient } from 'okx-api'; -⋮---- -/** - * To use "app.okx.com", set market to "US" - * - * Note: your available functionality may differ, refer to the corresponding API docs for more details: - * https://app.okx.com/docs-v5/en/#overview-production-trading-services - */ -⋮---- -/** - * This is a simple script wrapped in a immediately invoked function expression, designed to make public API calls without credentials - */ -⋮---- -// Raw data will arrive on the 'update' event -⋮---- -// console.log( -// new Date(), -// 'ws update (raw data received)', -// JSON.stringify(data, null, 2), -// ); -// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); + console.log('Demo order cancellation accepted:', cancelled.ordId); + } catch (error) { + console.error('Failed to cancel the demo order:', error); + } + } +} -================ -File: examples/Rest/demo-trading.ts -================ -import { RestClient, WebsocketClient } from '../../src/index.js'; -⋮---- -// or -// import { RestClient} from 'okx-api'; -⋮---- -// read from environmental variables, your demo trading keys -⋮---- -// okx api credentials -⋮---- -// Raw data will arrive on the 'update' event -⋮---- -// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); -⋮---- -// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event -⋮---- -// console.log('ws response: ', JSON.stringify(data, null, 2)); -⋮---- -// Subscribe to demo account events: -⋮---- -/** Simple examples for private REST API calls with bybit's V5 REST APIs */ -⋮---- -// Trade USDT linear perps +main(); +``` -================ -File: examples/Rest/my.okx.com.ts -================ -import { RestClient, WebsocketClient } from '../../src/index.js'; -⋮---- -// or -// import { RestClient } from 'okx-api'; -⋮---- -/** - * To use "my.okx.com", set market to "EEA" - * - * Note: your available functionality may differ, refer to the corresponding API docs for more details: - * https://my.okx.com/docs-v5/en/#overview-production-trading-services - */ -⋮---- -async function start() -⋮---- -// Raw data will arrive on the 'update' event -⋮---- -// console.log( -// new Date(), -// 'ws update (raw data received)', -// JSON.stringify(data, null, 2), -// ); -// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); +OKX order endpoints can return an HTTP success while an individual order result has failed. Check `sCode` and `sMsg` on each result item. This also applies to batch requests, where some items can succeed and others can fail. -================ -File: examples/Rest/rest-private-trade-market.ts -================ -import { OrderRequest, RestClient } from '../../src/index.js'; -⋮---- -// or -// import { RestClient, OrderRequest } from 'okx-api'; -⋮---- -// read from environmental variables -⋮---- -// If running from CLI in unix, you can pass env vars as such: -// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/rest-private-trade-market.ts -⋮---- -// note the single quotes, preventing special characters such as $ from being incorrectly passed -⋮---- -// apiKey: 'apiKeyHere', -⋮---- -// apiSecret: 'apiSecretHere', -⋮---- -// apiPass: 'apiPassHere', -⋮---- -/** Get available balance for an asset */ -async function getAssetBalance( - client: RestClient, - coin: string, -): Promise -⋮---- -/** - * This is a simple REST API demo script wrapped in a immediately invoked function expression. The logic below will immediately execute if you run this script. - * - * It is designed to: - * - check for any available USDT balance - * - immediately use half the balance to buy bitcoin (in spot) - * - check the available BTC balance - * - immediately sell all available BTC back to USDT - */ +Use `demoTrading: true`. Do not use the old `market: 'demo'` form. -================ -File: examples/Rest/rest-public.ts -================ -import { RestClient } from '../../src/index.js'; -⋮---- -// or -// import { RestClient } from 'okx-api'; -⋮---- -/** - * This is a simple script wrapped in a immediately invoked function expression, designed to make public API calls without credentials - */ +### 6. First WebSocket API order command -================ -File: examples/Websocket/app.okx.com.ts -================ -import { RestClient, WebsocketClient } from '../../src/index.js'; -⋮---- -// or -// import { RestClient } from 'okx-api'; -⋮---- -/** - * To use "app.okx.com", set market to "US" - * - * Note: your available functionality may differ, refer to the corresponding API docs for more details: - * https://app.okx.com/docs-v5/en/#overview-production-trading-services - */ -⋮---- -/** - * This is a simple script wrapped in a immediately invoked function expression, designed to make public API calls without credentials - */ -⋮---- -// Raw data will arrive on the 'update' event -⋮---- -// console.log( -// new Date(), -// 'ws update (raw data received)', -// JSON.stringify(data, null, 2), -// ); -// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); +`WebsocketAPIClient` wraps supported WebSocket commands in promises. Current OKX WebSocket order requests prefer `instIdCode`, so the example reads it from `getInstruments()` before submitting the same demo-only post-only order. -================ -File: examples/Websocket/ws-private-handle-auth-fail.ts -================ -// If you cloned the repo and are using typescript, you can import from src directly: -import { WebsocketClient } from '../../src/index.js'; -⋮---- -/** - * - * This simple example demonstrates one way to handle failed authentication, stopping the - * websocket client from running into a reconnect-loop when authentication fails (e.g. bad API keys). - * - * However, keep in mind it might be safer to make a test REST API call (e.g. fetch account balance) before - * trying to make a private WS connection to the account. - * - */ -⋮---- -// For private topics, include one or more accounts in an array. Otherwise only public topics will work -⋮---- -// Raw data will arrive on the 'update' event -⋮---- -// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); -⋮---- -// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event -⋮---- -// console.log('ws response: ', JSON.stringify(data, null, 2)); -⋮---- -// Optional, connect before subscribing: -⋮---- -// This is optional though. The wsclient will automatically open and subscribe if the connection doesn't exist yet. -⋮---- -// Subscribe one event at a time: + -================ -File: examples/Websocket/ws-private.ts -================ -// If you cloned the repo and are using typescript, you can import from src directly: -import { DefaultLogger, WebsocketClient } from '../../src/index.js'; -⋮---- -// or use the module installed via `npm install okx-api`: -// import { WebsocketClient, DefaultLogger } from 'okx-api'; -⋮---- -// or if you're not using typescript (e.g. pure nodejs), change the "import" to "require": -// const { WebsocketClient, DefaultLogger } = require('okx-api'); -⋮---- -// Optional: Inject a custom logger. -// This example overrides the default logger to also log "trace" (super verbose) messages, which are disabled by default -⋮---- -// trace: (...params) => console.log('trace', ...params), -⋮---- -// For private events, all 3 of the following are required (per account): -⋮---- -// If running from CLI in unix, you can pass env vars as such: -// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts -⋮---- -// note the single quotes, preventing special characters such as $ from being incorrectly passed -⋮---- -// For Global users (www.okx.com), you don't need to set the market. -// It will use global by default. -// Not needed: market: 'GLOBAL', -⋮---- -// For EEA users (my.okx.com), set market to "EEA": -// market: 'EEA', -⋮---- -// For US users (app.okx.com), set market to "US": -// market: 'US', -⋮---- -// For private topics, include one or more accounts in an array. Otherwise only public topics will work -⋮---- -// { -// apiKey: 'yourApiKeyHere', -// apiSecret: 'yourApiSecretHere', -// apiPass: 'yourApiPassHere', -// }, -// { -// apiKey: 'anotherAccountKey', -// apiSecret: 'anotherAccountSecret', -// apiPass: 'anotherAccountPass', -// }, -⋮---- -// Raw data will arrive on the 'update' event -⋮---- -// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); -⋮---- -// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event -⋮---- -// console.log('ws response: ', JSON.stringify(data, null, 2)); -⋮---- -// Optional, connect before subscribing: -// wsClient.connectPrivate(); -⋮---- -// This is optional though. The wsclient will automatically open and subscribe if the connection doesn't exist yet. -⋮---- -/** - * # Subscribing to channels - * - * Subscribe to channels using the inner "args" part of the subscription request described in the OKX API docs. - * - * For example, if the docs state your request should look as such: - { - op: "subscribe", - args: [ - { - channel: "account" - } - ] - } - * - * You should call the wsClient.subscribe function using only the "args". - * - * Either of these examples is correct (one channel vs one or more channels in an array): - wsClient.subscribe({ - channel: 'account' - }); +```typescript +import { RestClient, WebsocketAPIClient } from 'okx-api'; - wsClient.subscribe([ - { - channel: "account" - } - ]) - */ -⋮---- -// Subscribe one event at a time: -⋮---- -// OR, combine multiple subscription events into one request using an array instead of an object: -⋮---- -/** - * Examples for each private channel listed in the API docs: - * https://www.okx.com/docs-v5/en/#websocket-api-private-channel - */ -⋮---- -// Account events for all symbols -⋮---- -// Account events for specific symbol only -⋮---- -// Withdrawal events for specific symbol only -⋮---- -// Position events on any instrument type -⋮---- -// Position events on specific instruments -⋮---- -// Balance & position channel -⋮---- -// Order channel -⋮---- -// Order channel with extra args -⋮---- -// Algo orders channel -⋮---- -// Advance algo orders channel -⋮---- -// Position risk warning channel -⋮---- -// Account greeks channel -⋮---- -// Spot grid algo orders channel -⋮---- -// Contract grid orders channel -⋮---- -// Moon grid orders channel -⋮---- -// Moon grid orders channel -⋮---- -// Grid positions channel -⋮---- -// Grid sub orders channel +if (process.env.OKX_PLACE_DEMO_ORDER !== 'true') { + throw new Error('Set OKX_PLACE_DEMO_ORDER=true to place the demo order.'); +} -================ -File: examples/Websocket/ws-public.ts -================ -import { DefaultLogger, WebsocketClient } from '../../src/index.js'; -⋮---- -// or use the module installed via `npm install okx-api`: -// import { WebsocketClient, DefaultLogger } from 'okx-api'; -⋮---- -// or if you're not using typescript (e.g. pure nodejs), change the "import" to "require": -// const { WebsocketClient, DefaultLogger } = require('okx-api'); -⋮---- -// Optional: Inject a custom logger. -// This example overrides the default logger to also log "trace" (super verbose) messages, which are disabled by default -⋮---- -// trace: (...params) => console.log('trace', ...params), -⋮---- -// For Global users (www.okx.com), you don't need to set the market. -// It will use global by default. -// Not needed: market: 'GLOBAL', -// For EEA users (my.okx.com), set market to "EEA": -// market: 'EEA', -// For US users (app.okx.com), set market to "US": -// market: 'US', -⋮---- -logger, // Optional: inject the custom logger here -⋮---- -// Raw data will arrive on the 'update' event -⋮---- -// console.log( -// new Date(), -// 'ws update (raw data received)', -// JSON.stringify(data, null, 2), -// ); -// console.log('ws update (raw data received)', JSON.stringify(data, null, 2)); -⋮---- -// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event -⋮---- -// Send one topic at a time -⋮---- -// Or an array of requests -⋮---- -/** - * - * Examples for each channel: https://www.okx.com/docs-v5/en/#websocket-api-public-channel - * - */ -⋮---- -// Instruments channel -⋮---- -// Tickers channel -⋮---- -// Open interest channel -⋮---- -// Candlesticks channel -⋮---- -// Trades channel -⋮---- -// Estimated delivery/exercise price channel -⋮---- -// Mark price channel -⋮---- -// Mark price candlesticks channel -⋮---- -// Price limit channel -⋮---- -// Order book channel -⋮---- -// OPTION summary channel -⋮---- -// Funding rate channel -⋮---- -// Index candlesticks channel -⋮---- -// Index tickers channel -⋮---- -// Status channel -⋮---- -// Liquidation orders channel +const credentials = { + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, +}; +const rest = new RestClient({ + ...credentials, + demoTrading: true, +}); +const wsApi = new WebsocketAPIClient({ + accounts: [credentials], + demoTrading: true, + attachEventListeners: false, +}); +const ws = wsApi.getWSClient(); -================ -File: src/types/rest/request/block-trading.ts -================ -import { OrderSide, RFQLeg } from '../shared.js'; -export interface AccountAllocationLeg { - sz: string; - instId: string; - tdMode?: string; - ccy?: string; - posSide?: string; -} -⋮---- -export interface AccountAllocation { - acct: string; - legs: AccountAllocationLeg[]; -} -⋮---- -export interface CreateBlockRFQRequest { - counterparties: string[]; - anonymous?: boolean; - clRfqId?: string; - tag?: string; - allowPartialExecution?: boolean; - legs: RFQLeg[]; - acctAlloc?: AccountAllocation[]; -} -⋮---- -export interface CancelBlockRFQRequest { - rfqId?: string; - clRfqId?: string; -} -⋮---- -export interface CancelMultipleBlockRFQRequest { - rfqIds?: string[]; - clRfqIds?: string[]; -} -⋮---- -export interface ExecuteBlockQuoteRequest { - rfqId: string; - quoteId: string; -} -⋮---- -export interface CreateBlockQuoteLeg { - px: string; - sz: string; - instId: string; - side: OrderSide; - tgtCcy?: 'base_ccy' | 'quote_ccy'; -} -⋮---- -export interface CreateBlockQuoteRequest { - rfqId: string; - clQuoteId?: string; - quoteSide: OrderSide; - anonymous?: boolean; - expiresIn?: string; - legs: CreateBlockQuoteLeg[]; -} -⋮---- -export interface CancelBlockQuoteRequest { - quoteId?: string; - clQuoteId?: string; -} -⋮---- -export interface CancelMultipleBlockQuoteRequest { - quoteIds?: string[]; - clQuoteIds?: string[]; -} -⋮---- -export interface GetBlockRFQSParams { - rfqId?: string; - clRfqId?: string; - state?: string; - beginId?: string; - endId?: string; - limit?: string; -} -⋮---- -export interface GetBlockQuoteParams { - rfqId?: string; - clRfqId?: string; - quoteId?: string; - clQuoteId?: string; - state?: string; - beginId?: string; - endId?: string; - limit?: string; -} -⋮---- -export interface MakerInstrumentData { - uly?: string; - instId?: string; - maxBlockSz?: string; - makerPxBand?: string; -} -⋮---- -export interface SetQuoteProductsRequest { - instType: string; - includeAll?: boolean; - data: MakerInstrumentData[]; -} -⋮---- -export interface SetMmpConfigRequest { - timeInterval: string; - frozenInterval: string; - countLimit: string; -} +ws.on('open', ({ wsKey }) => console.log('Connected:', wsKey)); +ws.on('authenticated', ({ wsKey }) => console.log('Authenticated:', wsKey)); +ws.on('reconnect', ({ wsKey }) => console.log('Reconnecting:', wsKey)); +ws.on('reconnected', ({ wsKey }) => console.log('Reconnected:', wsKey)); +ws.on('exception', (error) => console.error('WebSocket exception:', error)); -================ -File: src/types/rest/request/convert.ts -================ -export interface ConvertQuoteEstimateRequest { - baseCcy: string; - quoteCcy: string; - side: string; - rfqSz: string; - rfqSzCcy: string; - clTReqId?: string; - tag?: string; - /** 0: standard convert (default), 1: large order convert for VIP */ - convertMode?: '0' | '1'; -} -⋮---- -/** 0: standard convert (default), 1: large order convert for VIP */ -⋮---- -export interface ConvertTradeRequest { - quoteId: string; - baseCcy: string; - quoteCcy: string; - side: string; - sz: string; - szCcy: string; - clTReqId?: string; - tag?: string; - /** 0: standard convert (default), 1: large order convert for VIP */ - convertMode?: '0' | '1'; -} -⋮---- -/** 0: standard convert (default), 1: large order convert for VIP */ +async function main() { + const instId = 'BTC-USDT'; -================ -File: src/types/rest/request/dual-investment.ts -================ -export interface GetDcdProductsRequest { - baseCcy: string; - quoteCcy: string; - optType: 'C' | 'P'; -} -⋮---- -export interface RequestDcdQuoteRequest { - productId: string; - notionalSz: string; - notionalCcy: string; -} -⋮---- -export interface SubmitDcdTradeRequest { - quoteId: string; -} -⋮---- -export interface RequestDcdRedeemQuoteRequest { - ordId: string; -} -⋮---- -export interface SubmitDcdRedeemRequest { - ordId: string; - quoteId: string; -} -⋮---- -export interface GetDcdOrderStatusRequest { - ordId: string; -} -⋮---- -export type DcdOrderState = - | 'initial' - | 'live' - | 'pending_settle' - | 'settled' - | 'pending_redeem' - | 'redeemed' - | 'rejected'; -⋮---- -export interface GetDcdOrderHistoryRequest { - ordId?: string; - productId?: string; - uly?: string; - state?: DcdOrderState; - beginId?: string; - endId?: string; - begin?: string; - end?: string; - limit?: string; -} + let instrument; + try { + [instrument] = await rest.getInstruments({ + instType: 'SPOT', + instId, + }); + } catch (error) { + console.error('Failed to get instrument rules:', error); + ws.closeAll(); + return; + } -================ -File: src/types/rest/request/glp.ts -================ -export type GlpProgram = 'SPOT' | 'PERP' | 'FUT_NTO'; -⋮---- -export interface GetGlpHistoricalPerformanceRequest { - program: GlpProgram; - begin?: string; - end?: string; - limit?: string; -} + let ticker; + try { + [ticker] = await rest.getTicker({ instId }); + } catch (error) { + console.error('Failed to get the ticker:', error); + ws.closeAll(); + return; + } -================ -File: src/types/rest/request/okusd.ts -================ -export interface SubscribeOkusdRequest { - amt: string; - clOrdId: string; -} -⋮---- -export interface RedeemOkusdRequest { - amt: string; - /** "1" = fast (real-time); "2" = standard (D+5/D+6) */ - redeemType: '1' | '2'; - clOrdId: string; -} -⋮---- -/** "1" = fast (real-time); "2" = standard (D+5/D+6) */ + if (!instrument || !ticker) { + console.error(`No demo market data returned for ${instId}.`); + ws.closeAll(); + return; + } -================ -File: src/types/rest/request/stable-rewards.ts -================ -export interface GetStableRewardsProductInfoRequest { - ccy: string; -} -⋮---- -export interface RequestStableRewardsQuoteRequest { - ccy: string; - settleCcy: string; - action: 'subscribe' | 'redeem'; - amt: string; -} -⋮---- -export interface SubmitStableRewardsTradeRequest { - quoteId: string; -} -⋮---- -export interface GetStableRewardsBalanceRequest { - ccy?: string; -} -⋮---- -export interface GetStableRewardsApyHistoryRequest { - ccy: string; - days?: string; -} -⋮---- -export interface GetStableRewardsSubscribeRedeemHistoryRequest { - ccy: string; - type?: 'subscribe' | 'redeem'; - status?: 'pending' | 'success' | 'failed'; - after?: string; - before?: string; - limit?: string; -} + if (!instrument.instIdCode) { + console.error(`No instIdCode returned for ${instId}.`); + ws.closeAll(); + return; + } -================ -File: src/types/rest/response/private-block-trading.ts -================ -import { RFQLeg, RFQQuoteLegExtended } from '../shared.js'; -⋮---- -export interface BlockCounterParty { - traderName: string; - traderCode: string; - type: never; // Currently not live -} -⋮---- -type: never; // Currently not live -⋮---- -export interface AccountAllocationLegResult { - instId: string; - sz: string; - tdMode: string; - ccy: string; - posSide: string; -} -export interface AccountAllocationResult { - acct: string; - sCode: string; - sMsg: string; - legs: AccountAllocationLegResult[]; -} -⋮---- -export interface CreateRFQResult { - cTime: string; - uTime: string; - traderCode: string; - rfqId: string; - clRfqId: string; - state: string; - validUntil: string; - counterparties: string[]; - legs: Required[]; - groupId?: string; - acctAlloc?: AccountAllocationResult[]; -} -⋮---- -export interface CancelBlockRFQResult { - rfqId: string; - clRfqId: string; - sCode: string; - sMsg: string; + if (!ticker.bidPx) { + console.error(`No best bid returned for ${instId}.`); + ws.closeAll(); + return; + } + + const clOrdId = `sieblyWsDemo${Date.now()}`; + + try { + await wsApi.connectWSAPI(); + } catch (error) { + console.error('Failed to connect the WebSocket API:', error); + ws.closeAll(); + return; + } + + let placed; + try { + placed = await wsApi.submitNewOrder({ + instIdCode: instrument.instIdCode, + tdMode: 'cash', + side: 'buy', + ordType: 'post_only', + sz: instrument.minSz, + px: ticker.bidPx, + clOrdId, + }); + } catch (error) { + console.error('Failed to submit the WebSocket API order:', error); + ws.closeAll(); + return; + } + + const placedItem = placed.data[0]; + + if (placed.code !== '0' || !placedItem || placedItem.sCode !== '0') { + console.error(placedItem?.sMsg || placed.msg || 'Order was rejected.'); + ws.closeAll(); + return; + } + + console.log('Demo WebSocket order accepted:', { + ordId: placedItem.ordId, + clOrdId: placedItem.clOrdId, + }); + + let cancelled; + try { + cancelled = await wsApi.cancelOrder({ clOrdId }); + } catch (error) { + console.error('Failed to cancel the WebSocket API order:', error); + ws.closeAll(); + return; + } + + const cancelledItem = cancelled.data[0]; + + if (cancelled.code !== '0' || !cancelledItem || cancelledItem.sCode !== '0') { + console.error( + cancelledItem?.sMsg || cancelled.msg || 'Cancellation was rejected.', + ); + ws.closeAll(); + return; + } + + console.log('Demo WebSocket cancellation accepted:', cancelledItem.ordId); + ws.closeAll(); } -⋮---- -export interface AccountAllocationLegExecutionResult { - instId: string; - sz: string; - fee: string; - feeCcy: string; - tradeId: string; -} -⋮---- -export interface AccountAllocationExecutionResult { - acct: string; - blockTdId: string; - sCode: string; - sMsg: string; - legs: AccountAllocationLegExecutionResult[]; -} -export interface ExecuteBlockQuoteResult { - blockTdId: string; - rfqId: string; - clRfqId: string; - quoteId: string; - clQuoteId: string; - tTraderCode: string; - mTraderCode: string; - cTime: string; - tag?: string; - legs: RFQQuoteLegExtended[]; - acctAlloc?: AccountAllocationExecutionResult[]; -} -⋮---- -export interface CreatedBlockQuoteLeg { - px: string; - sz: string; - instId: string; - side: string; - tgtCcy: string; + +main(); +``` + +Check both the top-level `code` and each item's `sCode`. A successful acknowledgement means OKX accepted the command, not that the order filled. Treat it as [Pending Confirmation](https://siebly.io/reference/glossary#pending-confirmation) until the private order stream or REST API confirms the resulting state. See [Private Stream Confirmation](https://siebly.io/reference/glossary#private-stream-confirmation) for the distinction. + +--- + + + +## REST API + +`RestClient` covers OKX market data, public data, account, trade, funding, transfer, sub-account, convert, algo, grid, copy-trading, spread, block-trading, Earn, staking, and loan endpoints. + +Public methods work without credentials. Private methods use the credentials passed to the constructor, and the SDK adds the timestamp, signature, passphrase, and other required headers. + +### Public market data + +The same product fields appear across public endpoints: + +- Use `instType` for a product family. +- Use `instId` for one exact market. +- Use `instFamily` or `uly` where a derivatives endpoint asks for a family or underlying. +- Query instruments before using products with expiries, strikes, or region-specific availability. + +This example reads both Spot and perpetual-swap data: + + + +```typescript +import { RestClient } from 'okx-api'; + +const client = new RestClient(); + +async function main() { + const spotInstId = 'BTC-USDT'; + const swapInstId = 'BTC-USDT-SWAP'; + + try { + const spotInstruments = await client.getInstruments({ + instType: 'SPOT', + instId: spotInstId, + }); + console.log('Spot instrument:', spotInstruments[0]?.instId); + } catch (error) { + console.error('Failed to get Spot instruments:', error); + } + + try { + const spotTickers = await client.getTickers({ instType: 'SPOT' }); + console.log('Spot ticker count:', spotTickers.length); + } catch (error) { + console.error('Failed to get Spot tickers:', error); + } + + try { + const orderBook = await client.getOrderBook({ + instId: spotInstId, + sz: '5', + }); + console.log('Best bid:', orderBook[0]?.bids[0]); + } catch (error) { + console.error('Failed to get the order book:', error); + } + + try { + const candles = await client.getCandles({ + instId: spotInstId, + bar: '1m', + limit: '5', + }); + console.log('Latest candle:', candles[0]); + } catch (error) { + console.error('Failed to get candles:', error); + } + + try { + const trades = await client.getTrades({ instId: spotInstId, limit: 5 }); + console.log('Latest trade:', trades[0]); + } catch (error) { + console.error('Failed to get trades:', error); + } + + try { + const swapInstruments = await client.getInstruments({ + instType: 'SWAP', + instId: swapInstId, + }); + console.log('Swap instrument:', swapInstruments[0]?.instId); + } catch (error) { + console.error('Failed to get swap instruments:', error); + } + + try { + const openInterest = await client.getOpenInterest({ + instType: 'SWAP', + instId: swapInstId, + }); + console.log('Open interest rows:', openInterest.length); + } catch (error) { + console.error('Failed to get open interest:', error); + } + + try { + const fundingRate = await client.getFundingRate({ instId: swapInstId }); + console.log('Funding rate:', fundingRate[0]?.fundingRate); + } catch (error) { + console.error('Failed to get the funding rate:', error); + } + + try { + const markPrice = await client.getMarkPrice({ + instType: 'SWAP', + instId: swapInstId, + }); + console.log('Mark price:', markPrice[0]?.markPx); + } catch (error) { + console.error('Failed to get the mark price:', error); + } + + try { + const indexTicker = await client.getIndexTickers({ instId: spotInstId }); + console.log('Index price:', indexTicker[0]?.idxPx); + } catch (error) { + console.error('Failed to get the index ticker:', error); + } } -⋮---- -export interface CreateBlockQuoteResult { - cTime: string; - uTime: string; - quoteId: string; - clQuoteId: string; - rfqId: string; - quoteSide: string; - state: string; - validUntil: string; - legs: CreatedBlockQuoteLeg[]; -} -⋮---- -export interface CancelBlockQuoteResult { - rfqId: string; - clQuoteId: string; - sCode: string; - sMsg: string; -} -⋮---- -export interface BlockRFQResult { - rfqId: string; - clRfqId: string; - traderCode: string; - validUntil: string; - state: string; - counterparties: string[]; - legs: Required[]; - cTime: string; - uTime: string; - allowPartialExecution?: boolean; - groupId?: string; - acctAlloc?: AccountAllocationResult[]; -} -⋮---- -export interface BlockQuoteLeg { - px: string; - sz: string; - instId: string; - side: string; - tgtCcy: string; -} -⋮---- -export interface GetBlockQuoteResult { - validUntil: string; - uTime: string; - cTime: string; - legs: BlockQuoteLeg[]; - quoteId: string; - rfqId: string; - quoteSide: string; - state: string; - clQuoteId: string; - clRfqId: string; - traderCode: string; -} -⋮---- -export interface BlockMakerInstrumentData { - uly?: string; - instId?: string; - maxBlockSz?: string; - makerPxBand?: string; -} -⋮---- -export interface AccountAllocationTradeLegResult { - instId: string; - sz: string; - tradeId: string; - fee: string; - feeCcy: string; -} -export interface AccountAllocationTradeResult { - blockTdId: string; - errorCode: string; - acct: string; - legs: AccountAllocationTradeLegResult[]; -} -⋮---- -export interface BlockTradeLeg { - instId: string; - side: string; - sz: string; - px: string; - tradeId: string; - fee: string; - feeCcy: string; - tradeQuoteCcy?: string; -} -⋮---- -export interface BlockTradeResult { - rfqId: string; - clRfqId: string; - quoteId: string; - clQuoteId: string; - blockTdId: string; - tag: string; - isSuccessful: boolean; - errorCode: string; - cTime: string; - tTraderCode: string; - mTraderCode: string; - legs: BlockTradeLeg[]; - groupId?: string; - acctAlloc?: AccountAllocationTradeResult[]; -} -⋮---- -export interface BlockMakerInstrumentSettings { - instType: string; - includeALL: boolean; - data: BlockMakerInstrumentData[]; -} -⋮---- -export interface SetMmpConfigResult { - timeInterval: string; - frozenInterval: string; - countLimit: string; -} -⋮---- -export interface BlockMMPConfig { - frozenInterval: string; - mmpFrozen: boolean; - mmpFrozenUntil: string; - countLimit: string; - timeInterval: string; -} -⋮---- -export interface PublicBlockTradeLeg { - instId: string; - tradeId: string; - px: string; - sz: string; - side: 'buy' | 'sell'; -} -⋮---- -export interface PublicBlockTrade { - blockTdId: string; - groupId?: string; - legs: PublicBlockTradeLeg[]; - strategy?: string; - cTime: string; + +main(); +``` + +Candles are returned newest first. Each candle is an array containing timestamp, open, high, low, close, volume fields, and a confirmation flag. Destructure those positions or map them into named fields before passing them deeper into an application. + +Use `getHistoricCandles()` for older market candles. Index and mark-price candles have separate methods because their response and pricing source differ from traded-market candles. + +### Private account state + +Start private workflows by reading account configuration and current state: + + + +```typescript +import { RestClient } from 'okx-api'; + +const client = new RestClient({ + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, +}); + +async function main() { + try { + const configuration = await client.getAccountConfiguration(); + console.log({ + accountMode: configuration[0]?.acctLv, + positionMode: configuration[0]?.posMode, + }); + } catch (error) { + console.error('Failed to get account configuration:', error); + } + + try { + const tradingBalances = await client.getBalance(); + console.log('Trading equity:', tradingBalances[0]?.totalEq); + } catch (error) { + console.error('Failed to get trading balances:', error); + } + + try { + const fundingBalances = await client.getBalances(); + console.log('Funding currency count:', fundingBalances.length); + } catch (error) { + console.error('Failed to get funding balances:', error); + } + + try { + const positions = await client.getPositions(); + console.log('Position count:', positions.length); + } catch (error) { + console.error('Failed to get positions:', error); + } + + try { + const openOrders = await client.getOrderList({ instType: 'SPOT' }); + console.log('Open order count:', openOrders.length); + } catch (error) { + console.error('Failed to get open orders:', error); + } + + try { + const orderHistory = await client.getOrderHistory({ + instType: 'SPOT', + limit: '20', + }); + console.log('Recent order count:', orderHistory.length); + } catch (error) { + console.error('Failed to get order history:', error); + } + + try { + const fills = await client.getFills({ instType: 'SPOT', limit: '20' }); + console.log('Recent fill count:', fills.length); + } catch (error) { + console.error('Failed to get fills:', error); + } + + try { + const feeRates = await client.getFeeRates({ + instType: 'SPOT', + instId: 'BTC-USDT', + }); + console.log('Fee rate rows:', feeRates.length); + } catch (error) { + console.error('Failed to get fee rates:', error); + } } -================ -File: src/types/rest/response/private-dual-investment.ts -================ -export interface DcdCurrencyPair { - baseCcy: string; - quoteCcy: string; - optType: 'C' | 'P'; - uly: string; -} -⋮---- -export interface DcdProduct { - absYield: string; - annualizedYield: string; - baseCcy: string; - quoteCcy: string; - expTime: string; - interestAccrualTime: string; - listTime: string; - maxSize: string; - minSize: string; - notionalCcy: string; - optType: 'C' | 'P'; - productId: string; - quoteTime: string; - redeemEndTime: string; - redeemStartTime: string; - stepSz: string; - tradeEndTime: string; - strike: string; - uly: string; -} -⋮---- -export interface DcdQuote { - absYield: string; - annualizedYield: string; - interestAccrualTime: string; - notionalSz: string; - notionalCcy: string; - productId: string; - quoteId: string; - validUntil: string; - idxPx: string; -} -⋮---- -export type DcdTradeOrderState = - | 'initial' - | 'pending_book' - | 'live' - | 'rejected'; -⋮---- -export interface DcdTradeResult { - quoteId: string; - ordId: string; - state: DcdTradeOrderState; -} -⋮---- -export interface DcdRedeemQuote { - ordId: string; - quoteId: string; - redeemCcy: string; - redeemSz: string; - termRate: string; - validUntil: string; -} -⋮---- -export type DcdRedeemConfirmState = - | 'pending_redeem_booking' - | 'pending_redeem' - | 'redeeming' - | 'redeemed'; -⋮---- -export interface DcdRedeemResult { - ordId: string; - state: DcdRedeemConfirmState; -} -⋮---- -export type DcdOrderStatusState = - | 'initial' - | 'live' - | 'pending_settle' - | 'settled' - | 'pending_redeem' - | 'redeemed' - | 'rejected'; -⋮---- -export interface DcdOrderStatus { - ordId: string; - state: DcdOrderStatusState; -} -⋮---- -export interface DcdOrderHistoryItem { - ordId: string; - quoteId: string; - state: DcdOrderStatusState; - productId: string; - baseCcy: string; - quoteCcy: string; - uly: string; - strike: string; - notionalSz: string; - notionalCcy: string; - absYield: string; - annualizedYield: string; - yieldSz: string; - yieldCcy: string; - settleSz: string; - settleCcy: string; - settlePx: string; - settleTime: string; - expTime: string; - redeemStartTime: string; - redeemEndTime: string; - cTime: string; - uTime: string; -} +main(); +``` -================ -File: src/types/rest/response/private-flexible-loan.ts -================ -export interface CollateralAsset { - ccy: string; - amt: string; - notionalUsd: string; -} -⋮---- -export interface CollateralAssetsResponse { - assets: CollateralAsset[]; -} -⋮---- -export interface SupplementaryCollateral { - ccy: string; - amt: string; -} -⋮---- -export interface GetFlexibleLoanCollateralAssetsRequest { - ccy?: string; - /** When the account has multiple active flexible-loan positions. */ - ordId?: string; -} -⋮---- -/** When the account has multiple active flexible-loan positions. */ -⋮---- -export interface MaxLoanRequest { - borrowCcy: string; - supCollateral?: SupplementaryCollateral[]; - /** When multiple active loans exist. */ - ordId?: string; -} -⋮---- -/** When multiple active loans exist. */ -⋮---- -export interface MaxLoanResponse { - borrowCcy: string; - maxLoan: string; - notionalUsd: string; - remainingQuota: string; -} -⋮---- -export interface AdjustCollateralRequest { - type: 'add' | 'reduce'; - collateralCcy: string; - collateralAmt: string; - /** When multiple active loans exist. */ - ordId?: string; -} -⋮---- -/** When multiple active loans exist. */ -⋮---- -export interface LoanCurrencyData { - ccy: string; - amt: string; -} -⋮---- -export interface RiskWarningData { - instId: string; - liqPx: string; -} -⋮---- -export interface GetLoanInfoRequest { - /** When the account has multiple active flexible loans . */ - ordId?: string; -} -⋮---- -/** When the account has multiple active flexible loans . */ -⋮---- -export interface LoanInfo { - /** - * Active loan / position id when the account can hold multiple loan orders. - */ - ordId?: string; - loanNotionalUsd: string; - loanData: LoanCurrencyData[]; - /** Adjusted collateral value in USD. */ - collateralNotionalUsd: string; - collateralData: LoanCurrencyData[]; - riskWarningData: RiskWarningData; - curLTV: string; - marginCallLTV: string; - liqLTV: string; -} -⋮---- -/** - * Active loan / position id when the account can hold multiple loan orders. - */ -⋮---- -/** Adjusted collateral value in USD. */ -⋮---- -export interface LoanHistoryRequest { - type?: - | 'borrowed' - | 'repaid' - | 'collateral_locked' - | 'collateral_released' - | 'forced_repayment_buy' - | 'forced_repayment_sell' - | 'forced_liquidation' - | 'partial_liquidation'; - /** When multiple active loans exist. */ - ordId?: string; - after?: string; - before?: string; - limit?: string; -} -⋮---- -/** When multiple active loans exist. */ -⋮---- -export interface LoanHistoryItem { - refId: string; - type: string; - ccy: string; - amt: string; - ts: string; -} -⋮---- -export interface AccruedInterestRequest { - ccy?: string; - /** When multiple active loans exist. */ - ordId?: string; - after?: string; - before?: string; - limit?: string; -} -⋮---- -/** When multiple active loans exist. */ -⋮---- -export interface AccruedInterestItem { - refId: string; - ccy: string; - loan: string; - interest: string; - interestRate: string; - ts: string; -} +`getBalance()` reads the trading account. `getBalances()` reads assets in the funding account. They are different OKX account areas, so do not combine the results without retaining their source. -================ -File: src/types/rest/response/private-glp.ts -================ -export interface GlpMakerTaker { - maker: string; - taker: string; -} -⋮---- -export interface GlpVolumeBuckets { - typeA: GlpMakerTaker | null; - typeBTotal: GlpMakerTaker | null; - tradfiX2: GlpMakerTaker | null; - total: GlpMakerTaker; -} -⋮---- -export interface GlpShareBuckets { - typeA: GlpMakerTaker | null; - typeBAdj: GlpMakerTaker | null; - total: GlpMakerTaker; -} -⋮---- -export interface GlpDailyMetrics { - volume: GlpVolumeBuckets; - share: GlpShareBuckets; -} -⋮---- -export interface GlpMtdMetrics extends GlpDailyMetrics { - mtdStatus: string; - qualifyingShare: GlpMakerTaker; -} -⋮---- -export interface GlpProgramPerformance { - program: string; - marketMakerBusinessId: string; - enrollmentStatus: string; - marketMakerLevelId: string; - enrolledTierDisplay: string; - qualifyingPool: string; - qualifyingRows: string[]; - daily: GlpDailyMetrics; - mtd: GlpMtdMetrics; -} -⋮---- -export interface GlpTodayPerformance { - dataReady: boolean; - dataDate: string; - account: { - masterAccountId: string; - combinedAccountIds: string[]; - }; - programs: GlpProgramPerformance[]; -} -⋮---- -export interface GlpHistoricalPerformanceItem { - date: string; - volume: GlpVolumeBuckets; - share: GlpShareBuckets; -} +Pending orders, recent order history, fills, positions, and balances are useful together when rebuilding [Account State](https://siebly.io/reference/glossary#accountstate). -================ -File: src/types/rest/response/private-okusd.ts -================ -export interface OkusdLimitBucket { - personalDailyLimit: string; - personalUsedAmt: string; - platformDailyLimit: string; - platformUsedAmt: string; - feeRate?: string; -} -⋮---- -export interface OkusdSubLimit extends OkusdLimitBucket { - maxSubAmt: string; -} -⋮---- -export interface OkusdLimits { - subLimit: OkusdSubLimit; - fastRedeemLimit: OkusdLimitBucket; - stdRedeemLimit: OkusdLimitBucket; - ts: string; -} -⋮---- -export interface OkusdSubscribeResult { - ordId: string; - clOrdId: string; - ccy: string; - amt: string; - okusdAmt: string; - state: string; - ts: string; -} -⋮---- -export interface OkusdRedeemResult { - ordId: string; - clOrdId: string; - ccy: string; - amt: string; - fee: string; - usdtAmt: string; - redeemType: string; - state: string; - estSettlementTime: string; - ts: string; -} +### Order management -================ -File: src/types/rest/response/private-stable-rewards.ts -================ -export interface StableRewardsProductInfoDetail { - ccy: string; - settleCcy: string; - subFeeRate: string; - redemptFeeRate: string; - minSubAmt: string; - minRedeemAmt: string; - remainingSubQuota: string; - remainingRedemptQuota: string; - canRedeem: boolean; -} -⋮---- -export interface StableRewardsProductInfo { - details: StableRewardsProductInfoDetail[]; - ts: string; -} -⋮---- -export interface StableRewardsQuote { - quoteId: string; - quoteAmt: string; - quoteCcy: string; - exchRate: string; - feeRate: string; - quoteTime: string; - ttlMs: string; -} -⋮---- -export interface StableRewardsTradeResult { - quoteId: string; - ordId: string; -} -⋮---- -export type StableRewardsBalanceState = 'earning' | 'pending'; -⋮---- -export interface StableRewardsBalanceDetail { - ccy: string; - amt: string; - totalEarnAccrual: string; - state: StableRewardsBalanceState; -} -⋮---- -export interface StableRewardsBalance { - details: StableRewardsBalanceDetail[]; - ts: string; -} -⋮---- -export interface StableRewardsApyHistoryItem { - rate: string; - ts: string; -} -⋮---- -export type StableRewardsSubscribeRedeemType = 'subscribe' | 'redeem'; -⋮---- -export type StableRewardsSubscribeRedeemStatus = - | 'pending' - | 'success' - | 'failed'; -⋮---- -export interface StableRewardsSubscribeRedeemHistoryItem { - type: StableRewardsSubscribeRedeemType; - status: StableRewardsSubscribeRedeemStatus; - ccy: string; - settleCcy: string; - ccyAmt: string; - settleCcyAmt: string; - fee: string; - quoteId: string; - ordId: string; - ts: string; +The complete demo REST API example above shows a safe place, query, and cancel flow. The same `RestClient` also exposes amend and batch methods: + +| Operation | SDK method | Result to inspect | +| ------------------- | ------------------------------------ | ------------------------------------------------------------ | +| Place one order | `submitOrder()` | Item `sCode`, `sMsg`, `ordId`, and `clOrdId` | +| Place a batch | `submitMultipleOrders()` | Every item's `sCode` and `sMsg` | +| Query one order | `getOrderDetails()` | Current `state`, filled size, average price, and identifiers | +| Amend one order | `amendOrder()` | Item `sCode`, `sMsg`, and `reqId` | +| Amend a batch | `amendMultipleOrders()` | Every item's result | +| Cancel one order | `cancelOrder()` | Item `sCode` and `sMsg` | +| Cancel a batch | `cancelMultipleOrders()` | Every item's result | +| Read pending orders | `getOrderList()` | Orders still working | +| Read recent history | `getOrderHistory()` and `getFills()` | Completed order and execution evidence | + +Identify application-owned orders with `clOrdId`. After placement, OKX also returns `ordId`; persist both. A typical amend uses: + +```typescript +import type { RestClient } from 'okx-api'; + +async function amendOrder( + client: RestClient, + instId: string, + clOrdId: string, + newPx: string, +) { + try { + const [amended] = await client.amendOrder({ + instId, + clOrdId, + newPx, + reqId: `amend${Date.now()}`, + }); + + if (!amended || amended.sCode !== '0') { + console.error(amended?.sMsg || 'OKX rejected the amendment.'); + return; + } + + return amended; + } catch (error) { + console.error('Failed to amend the order:', error); + } } +``` -================ -File: src/websocket-client-legacy.ts -================ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ -import { EventEmitter } from 'events'; -import WebSocket from 'isomorphic-ws'; -⋮---- -import { APICredentials } from './types/shared.js'; -import { - WsAuthRequest, - WsSubRequest, - WsUnsubRequest, -} from './types/websockets/ws-api.js'; -import { WsDataEvent } from './types/websockets/ws-events.js'; -import { - WebsocketClientOptions, - WSClientConfigurableOptions, -} from './types/websockets/ws-general.js'; -import { - WsAuthRequestArg, - WsChannelSubUnSubRequestArg, -} from './types/websockets/ws-request.js'; -import { WSClientEventMap } from './util/BaseWSClient.js'; -import { DefaultLogger } from './util/logger.js'; +`newPx` must follow the current instrument tick size and price limits. `reqId` identifies the amend request, while `clOrdId` continues to identify the order. + +For retries after a timeout, query by `clOrdId` before submitting another order. A missing response does not prove that OKX rejected the first request. + +### Spot, margin, and derivatives orders + +Order fields depend on the product and account configuration: + +| Workflow | Important fields | +| -------------- | ------------------------------------------------------------------------------------------- | +| Spot | `instId`, `tdMode: 'cash'`, `side`, `ordType`, and `sz` | +| Spot margin | Spot `instId` with `tdMode: 'cross'` or `isolated`, plus borrowing behavior where needed | +| Perpetual swap | Swap `instId`, margin `tdMode`, and position-side fields that match the account | +| Dated futures | A current futures `instId` from `getInstruments()`, margin mode, and position-side fields | +| Options | A current option `instId`, account-compatible trade mode, size, and a supported price field | + +In net position mode, derivatives requests normally use or imply `posSide: 'net'`. In long/short mode, opening and closing requests use `posSide: 'long'` or `short`. Do not copy a derivatives order request across accounts without reading `posMode`. + +Use `reduceOnly` only where the product, mode, and side support it. For margin and derivatives, check available size, leverage, margin mode, and current positions before sending an order. + +### More REST API groups + +`RestClient` also covers: + +- Algo orders, attached take-profit and stop-loss orders, trailing orders, and recurring buys. +- Grid and signal bots. +- Copy trading. +- Spread trading, block trading, RFQs, and market-maker protection. +- Funding-account transfers, deposits, withdrawals, and sub-accounts. +- Convert and easy-convert workflows. +- Earn, savings, staking, dual investment, and loan products. +- Event contracts where the account region supports them. + +Use the [OKX SDK endpoint map](./endpointFunctionList.md) to find the method for a specific endpoint, then check the matching regional OKX documentation for request rules and availability. + +--- + + + +## WebSocket streams + +`WebsocketClient` manages public, private, and business connections. It handles heartbeats, reconnects, and resubscriptions, while emitting the same lifecycle events for each connection. + +### Events and type guards + +| Event | Meaning | +| --------------- | ------------------------------------------------------ | +| `open` | A connection opened for the first time | +| `authenticated` | An authenticated connection completed login | +| `response` | Login, subscribe, unsubscribe, error, or control reply | +| `update` | Data from a subscribed channel | +| `reconnect` | The SDK is reconnecting a dropped connection | +| `reconnected` | The connection is open again | +| `exception` | A connection or listener error needs attention | +| `close` | A connection closed | + +The package exports type guards for handlers that receive unknown messages: + +```typescript import { - isConnCountEvent, isWsDataEvent, isWsErrorEvent, - isWsLoginEvent, isWsSubscribeEvent, - isWsUnsubscribeEvent, -} from './util/typeGuards.js'; -import { signMessage } from './util/webCryptoAPI.js'; -import { - getMaxTopicsPerSubscribeEventForMarket, - getWsKeyForMarket, - getWsKeyForTopicChannel, - getWsUrlForWsKey, - isWsPong, - PRIVATE_WS_KEYS, - PUBLIC_WS_KEYS, - safeTerminateWs, - WS_EVENT_CODE_ENUM, - WS_KEY_MAP, - WS_LOGGER_CATEGORY, - WsKey, -} from './util/websocket-util.js'; -import WsStore from './util/WsStore.js'; -import { WsConnectionStateEnum } from './util/WsStore.types.js'; -⋮---- -// Type safety for on and emit handlers: https://stackoverflow.com/a/61609010/880837 -export declare interface WebsocketClientLegacy { - on>( - event: U, - listener: WSClientEventMap[U], - ): this; + WebsocketClient, +} from 'okx-api'; - emit>( - event: U, - ...args: Parameters[U]> - ): boolean; -} -⋮---- -on>( - event: U, - listener: WSClientEventMap[U], - ): this; -⋮---- -emit>( - event: U, - ...args: Parameters[U]> - ): boolean; -⋮---- -/** - * @deprecated This is the old WebsocketClient that was part of the SDK prior to the V3 release. This legacy WebsocketClient is temporarily included but will be removed with the next major release. - */ -export class WebsocketClientLegacy extends EventEmitter -⋮---- -constructor(options: WSClientConfigurableOptions, logger?: DefaultLogger) -⋮---- -// Automatically send an authentication op/request after a connection opens, for private connections. -⋮---- -// Individual requests do not require a signature, so this is disabled. -⋮---- -/** - * Subscribe to topics & track/persist them. They will be automatically resubscribed to if the connection drops/reconnects. - * @param wsEvents topic or list of topics - * @param isPrivateTopic optional - the library will try to detect private topics, you can use this to mark a topic as private (if the topic isn't recognised yet) - */ -public subscribe( - wsEvents: WsChannelSubUnSubRequestArg[] | WsChannelSubUnSubRequestArg, - isPrivateTopic?: boolean, -) -⋮---- -// Persist topic for reconnects -⋮---- -// if connected, send subscription request -⋮---- -// start connection process if it hasn't yet begun. Topics are automatically subscribed to on-connect -⋮---- -/** - * Unsubscribe from topics & remove them from memory. They won't be re-subscribed to if the connection reconnects. - * @param wsTopics topic or list of topics - * @param isPrivateTopic optional - the library will try to detect private topics, you can use this to mark a topic as private (if the topic isn't recognised yet) - */ -public unsubscribe( - wsTopics: WsChannelSubUnSubRequestArg[] | WsChannelSubUnSubRequestArg, - isPrivateTopic?: boolean, -) -⋮---- -// Remove topic from persistence for reconnects -⋮---- -// unsubscribe request only necessary if active connection exists -⋮---- -/** Get the WsStore that tracks websocket & topic state */ -public getWsStore(): WsStore -⋮---- -public close(wsKey: WsKey, force?: boolean) -⋮---- -public closeAll(force?: boolean) -⋮---- -/** - * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library - */ -public connectAll(): Promise[] -⋮---- -public connectPublic( - businessEndpoint?: boolean, -): Promise -⋮---- -public connectPrivate( - businessEndpoint?: boolean, -): Promise -⋮---- -private async connect(wsKey: WsKey): Promise -⋮---- -private parseWsError(context: string, error: any, wsKey: WsKey) -⋮---- -/** - * Return params required to make authorized request - */ -private async getWsAuthRequest( - wsKey: WsKey, -): Promise | undefined> -⋮---- -// Filter out failed accounts -⋮---- -private async getWsAuthSignature( - wsKey: WsKey, - credentials: APICredentials, -): Promise< -⋮---- -// const signatureExpiresAt = timestamp + 5; -⋮---- -private async sendAuthRequest(wsKey: WsKey): Promise -⋮---- -private reconnectWithDelay(wsKey: WsKey, connectionDelayMs: number) -⋮---- -private ping(wsKey: WsKey) -⋮---- -/** - * Closes a connection, if it's even open. If open, this will trigger a reconnect asynchronously. - * If closed, trigger a reconnect immediately. - */ -private executeReconnectableClose(wsKey: WsKey, reason: string) -⋮---- -private clearTimers(wsKey: WsKey) -⋮---- -// Send a ping at intervals -private clearPingTimer(wsKey: WsKey) -⋮---- -// Expect a pong within a time limit -private clearPongTimer(wsKey: WsKey) -⋮---- -private clearReconnectTimer(wsKey: WsKey) -⋮---- -/** - * @private Use the `subscribe(topics)` method to subscribe to topics. Send WS message to subscribe to topics. - */ -private requestSubscribeTopics( - wsKey: WsKey, - topics: WsChannelSubUnSubRequestArg[], -) -⋮---- -/** - * @private Use the `unsubscribe(topics)` method to unsubscribe from topics. Send WS message to unsubscribe from topics. - */ -private requestUnsubscribeTopics( - wsKey: WsKey, - topics: WsChannelSubUnSubRequestArg[], -) -⋮---- -public tryWsSend(wsKey: WsKey, wsMessage: string): void -⋮---- -private connectToWsUrl(url: string, wsKey: WsKey): WebSocket -⋮---- -private async onWsOpen( - event: WebSocket.Event, - wsKey: WsKey, - url: string, - ws: WebSocket, -) -⋮---- -// Private websockets require an auth packet to be sent after opening the connection -⋮---- -// Any requested private topics will be subscribed to once authentication succeeds (in onWsMessage handler) -⋮---- -// Private topics will be subscribed to once authentication is confirmed as successful -⋮---- -// Public topics can be subscribed to immediately -⋮---- -// Since public channels have their own ws key, these topics must be public ones already -⋮---- -private onWsMessage(event: any, wsKey: WsKey, _ws: WebSocket) -⋮---- -// any message can clear the pong timer - wouldn't get a message if the ws dropped -⋮---- -// Successfully authenticated -⋮---- -// Since private topics have a dedicated WsKey, these are automatically all private topics (no filtering required before the subscribe call) -⋮---- -// this.logger.trace(`Ws subscribe reply:`, { ...msg, wsKey }); -⋮---- -private onWsClose(event: any, wsKey: WsKey) +const ws = new WebsocketClient(); -================ -File: .nvmrc -================ -v24.18.0 +ws.on('response', (event) => { + if (isWsErrorEvent(event)) { + console.error('OKX WebSocket error:', event); + return; + } -================ -File: examples/Rest/rest-private-trade.ts -================ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { RestClient } from '../../src/index.js'; -import { OrderRequest } from '../../src/types/rest/request/trade.js'; -⋮---- -// or -// import { SpotClient } from 'okx-api'; -⋮---- -// read from environmental variables -⋮---- -// If running from CLI in unix, you can pass env vars as such: -// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/rest-private-trade.ts -⋮---- -// note the single quotes, preventing special characters such as $ from being incorrectly passed -⋮---- -// apiKey: 'apiKeyHere', -⋮---- -// apiSecret: 'apiSecretHere', -⋮---- -// apiPass: 'apiPassHere', -⋮---- -// const wsClient = new WebsocketClient({ -// apiKey: API_KEY, -// apiSecret: API_SECRET, -// apiPass: API_PASS, -// }); -⋮---- -function logWSEvent(type: string, data: any) -⋮---- -// simple sleep function -function promiseSleep(milliseconds: number) -⋮---- -// WARNING: for sensitive math you should be using a library such as decimal.js! -function roundDown(value: any, decimals: number) -⋮---- -/** This is a simple script wrapped in a immediately invoked function expression, designed to check for any available BTC balance and immediately sell the full amount for USDT */ -⋮---- -// // Add event listeners to log websocket events on account -// wsClient.on('update', (data) => logWSEvent('update', data)); -// wsClient.on('open', (data) => logWSEvent('open', data)); -// wsClient.on('response', (data) => logWSEvent('response', data)); -// wsClient.on('reconnect', (data) => logWSEvent('reconnect', data)); -// wsClient.on('reconnected', (data) => logWSEvent('reconnected', data)); -// wsClient.on('authenticated', (data) => logWSEvent('authenticated', data)); -// wsClient.on('exception', (data) => logWSEvent('exception', data)); -⋮---- -// // Subscribe to private account topics -// wsClient.subscribeTopic('SPBL', 'account'); -// wsClient.subscribeTopic('SPBL', 'orders'); -⋮---- -// wait briefly for ws to be ready (could also use the response or authenticated events, to make sure topics are subscribed to before starting) -⋮---- -// const balances = allBalances.filter((bal) => Number(bal.available) != 0); -⋮---- -// console.log('balance: ', JSON.stringify(balances, null, 2)); -⋮---- -// example to find minimum allowed size for a symbol and place an order with it -/* const symbol = 'BTC-USDT-SWAP'; + if (isWsSubscribeEvent(event)) { + console.log('Subscription acknowledged:', event); + } +}); - const symbolsResult = await client.getInstruments({ - instType: 'SWAP', - }); - const btcRules = symbolsResult.find((rule) => rule.instId === symbol); - console.log('btc trading rules: ', btcRules); - if (!btcRules) { - return console.log('no rules found for trading ' + symbol); - } +ws.on('update', (event) => { + if (isWsDataEvent(event)) { + console.log(event.arg.channel, event.data); + } +}); +``` - const minSize = Number(btcRules.minSz); +`isWsDataEvent()` checks for channel data, `isWsSubscribeEvent()` checks for a subscribe reply, and `isWsErrorEvent()` checks for an exchange error event. - const order = { - instId: symbol, - tdMode: 'cross', - ordType: 'market', - side: 'sell', - sz: String(minSize), - } as const; +### Automatic channel routing - console.log('submitting order: ', order); +The channel determines which OKX connection the SDK uses: - const sellResult = await client.submitOrder(order); +| Connection | Example channels | Authentication | +| ---------- | -------------------------------------------------------------- | ---------------------- | +| Public | `tickers`, `books`, `trades`, `instruments`, `funding-rate` | Usually none | +| Private | `account`, `positions`, `orders`, `balance_and_position` | Required | +| Business | Candles, algo orders, grid channels, deposits, and withdrawals | Depends on the channel | - console.log('sell result: ', sellResult); */ +Normal subscriptions do not need a manually selected `WS_KEY_MAP` value. Pass the channel arguments to `subscribe()` and let the SDK route them. A [WsKey](https://siebly.io/reference/glossary#ws-key) is still useful in logs because lifecycle events include the connection's `wsKey`. -================ -File: examples/Websocket/WS-API/ws-api-client.ts -================ -import { DefaultLogger, WebsocketAPIClient } from '../../../src/index.js'; -⋮---- -// or use the module installed via `npm install okx-api`: -// import { WebsocketClient, DefaultLogger } from 'okx-api'; -⋮---- -// or if you're not using typescript (e.g. pure nodejs), change the "import" to "require": -// const { WebsocketClient, DefaultLogger } = require('okx-api'); -⋮---- -// function attachEventHandlers( -// wsClient: TWSClient, -// ): void { -// wsClient.on('update', (data) => { -// console.log('raw message received ', JSON.stringify(data)); -// }); -// wsClient.on('open', (data) => { -// console.log('ws connected', data.wsKey); -// }); -// wsClient.on('reconnect', ({ wsKey }) => { -// console.log('ws automatically reconnecting.... ', wsKey); -// }); -// wsClient.on('reconnected', (data) => { -// console.log('ws has reconnected ', data?.wsKey); -// }); -// wsClient.on('authenticated', (data) => { -// console.log('ws has authenticated ', data?.wsKey); -// }); -// } -⋮---- -// For private events, all 3 of the following are required (per account): -⋮---- -// If running from CLI in unix, you can pass env vars as such: -// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts -⋮---- -// For Global users (www.okx.com), you don't need to set the market. -// It will use global by default. -// Not needed: market: 'GLOBAL', -⋮---- -// For EEA users (my.okx.com), set market to "EEA": -// market: 'EEA', -⋮---- -// For US users (app.okx.com), set market to "US": -// market: 'US', -⋮---- -// For private topics, include one or more accounts in an array. Otherwise only public topics will work -⋮---- -// Optional, see above "attachEventListeners". Attach basic event handlers, so nothing is left unhandled -// attachEventHandlers(wsClient.getWSClient()); -⋮---- -// Optional: prepare the WebSocket API connection in advance. -// This happens automatically but you can do this early before making any API calls, to prevent delays from a cold start. -// await wsClient.connectWSAPI(); -⋮---- -/** - * OKX's WebSocket API be used like a REST API, through this SDK's WebsocketAPIClient. The WebsocketAPIClient is a utility class wrapped around WebsocketClient's sendWSAPIRequest() capabilities. - * - * Each request sent via the WebsocketAPIClient will automatically: - * - route via the active WS API connection - * - return a Promise, which automatically resolves/rejects when a matching response is received - */ -⋮---- -/** - * Place Order - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order - */ -⋮---- -/** - const res = { - id: '2', - op: 'order', - code: '1', - msg: '', - data: [ - { - tag: '159881cb7207BCDE', - ts: '1753714603721', - ordId: '', - clOrdId: '', - sCode: '51008', - sMsg: 'Order failed. Insufficient USDT balance in account.' - } - ], - inTime: '1753714603720755', - outTime: '1753714603721942', - wsKey: 'prodPrivate', - isWSAPIResponse: false - } +Some high-depth public books require authentication even though their data is public. Add credentials when using a channel whose OKX documentation requires an authenticated public connection. - const res = { - id: '2', - op: 'order', - code: '1', - msg: '', - data: [ - { - tag: '159881cb7207BCDE', - ts: '1753714567149', - ordId: '', - clOrdId: '', - sCode: '51010', - sMsg: "You can't complete this request under your current account mode." - } - ], - inTime: '1753714567149196', - outTime: '1753714567149913', - wsKey: 'prodPrivate', - isWSAPIResponse: false - } - */ -⋮---- -/** - * Submit multiple orders in a batch - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-multiple-orders - */ +### Subscribe and shut down -================ -File: examples/Websocket/WS-API/ws-api-trade-raw.ts -================ -// If you cloned the repo and are using typescript, you can import from src directly: -import { - DefaultLogger, - WebsocketClient, - WS_KEY_MAP, -} from '../../../src/index.js'; -⋮---- -// or use the module installed via `npm install okx-api`: -// import { WebsocketClient, DefaultLogger } from 'okx-api'; -⋮---- -// or if you're not using typescript (e.g. pure nodejs), change the "import" to "require": -// const { WebsocketClient, DefaultLogger } = require('okx-api'); -⋮---- -// For private events, all 3 of the following are required (per account): -⋮---- -// If running from CLI in unix, you can pass env vars as such: -// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts -⋮---- -// For private topics, include one or more accounts in an array. Otherwise only public topics will work -⋮---- -// console.log('WS raw message received ', JSON.stringify(data, null, 2)); -⋮---- -// prodPrivate is for the www.okx.com /ws/v5/private channel -⋮---- -// prodBusiness is for the www.okx.com /ws/v5/business channel -// const OKX_GLOBAL_BUSINESS_CHANNEL = WS_KEY_MAP.prodBusiness; -⋮---- -/** - * OKX's WebSocket API can be used via the sendWSAPIRequest() method. - * - * The correct WS Key depends on where you registered (www.okx.com vs app.okx.com vs my.okx.com), and whether you are using book trading (uses private connection) or spread trading (uses business connection) functionality. - * - * Note: for a better user experience, it is recommended to use the WebsocketAPIClient. - */ -⋮---- -/** - * Place Order - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order - */ -⋮---- -/** - const res = { - id: '2', - op: 'order', - code: '1', - msg: '', - data: [ - { - tag: '159881cb7207BCDE', - ts: '1753714603721', - ordId: '', - clOrdId: '', - sCode: '51008', - sMsg: 'Order failed. Insufficient USDT balance in account.' - } - ], - inTime: '1753714603720755', - outTime: '1753714603721942', - wsKey: 'prodPrivate', - isWSAPIResponse: false - } +Keep the subscribed topics together, then close the WebSocket connections when the process shuts down: - const res = { - id: '2', - op: 'order', - code: '1', - msg: '', - data: [ - { - tag: '159881cb7207BCDE', - ts: '1753714567149', - ordId: '', - clOrdId: '', - sCode: '51010', - sMsg: "You can't complete this request under your current account mode." - } - ], - inTime: '1753714567149196', - outTime: '1753714567149913', - wsKey: 'prodPrivate', - isWSAPIResponse: false - } + - */ -⋮---- -/** - * Cancel Order - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-cancel-order - */ -⋮---- -/** - const res = { - id: '2', - op: 'cancel-order', - code: '1', - msg: '', - data: [ - { - ts: '1753714393003', - ordId: '2510789768709120', - clOrdId: '', - sCode: '51400', - sMsg: 'Order cancellation failed as the order has been filled, canceled or does not exist.' - } - ], - inTime: '1753714393003190', - outTime: '1753714393004074', - wsKey: 'prodPrivate', - isWSAPIResponse: false - } - */ +```typescript +import { type WsChannelSubUnSubRequestArg, WebsocketClient } from 'okx-api'; -================ -File: src/types/rest/request/affiliate.ts -================ -export type AffiliatePeriodType = - | 'last_7d' - | 'last_30d' - | 'this_month' - | 'last_month' - | 'total' - | 'today' - | 'this_week' - | 'custom'; -⋮---- -export type AffiliateCommissionCategory = 'SPOT' | 'DERIVATIVE' | 'BSC'; -⋮---- -export type AffiliateKycStatus = 'unverified' | 'verified'; -⋮---- -export type AffiliateLinkType = 'standard' | 'co_inviter'; -⋮---- -export type AffiliateLinkStatus = 'normal' | 'abnormal'; -⋮---- -export type AffiliateInviteeListOrderBy = - | 'cTime' - | 'depAmt' - | 'vol' - | 'fee' - | 'rebate'; -⋮---- -export type AffiliateSubAffiliateListOrderBy = - | 'cTime' - | 'depAmt' - | 'vol' - | 'fee' - | 'rebate'; -⋮---- -export type AffiliateOrderDir = 'asc' | 'desc'; -⋮---- -export interface GetAffiliatePerformanceSummaryRequest { - periodType?: AffiliatePeriodType; - /** Required when periodType=custom, together with end. Inclusive. */ - begin?: string; - /** Required when periodType=custom, together with begin. Inclusive. */ - end?: string; -} -⋮---- -/** Required when periodType=custom, together with end. Inclusive. */ -⋮---- -/** Required when periodType=custom, together with begin. Inclusive. */ -⋮---- -export interface GetInviteeDetailRequest { - uid: string; - /** - * Stats window for `volPeriod`: last_7d, last_30d, this_month, last_month, total, today, this_week. - * When omitted, volPeriod is not returned. - */ - periodType?: Exclude; -} -⋮---- -/** - * Stats window for `volPeriod`: last_7d, last_30d, this_month, last_month, total, today, this_week. - * When omitted, volPeriod is not returned. - */ -⋮---- -export interface GetAffiliateInviteeListRequest { - page?: string; - limit?: string; - periodType?: AffiliatePeriodType; - /** Required when periodType=custom, together with end. Inclusive. */ - begin?: string; - /** Required when periodType=custom, together with begin. Inclusive. */ - end?: string; - keyword?: string; - commissionCategory?: AffiliateCommissionCategory; - orderBy?: AffiliateInviteeListOrderBy; - orderDir?: AffiliateOrderDir; - kycStatus?: AffiliateKycStatus; - subAffiliateUid?: string; - /** External user UIDs for exact match. Single or up to 100 comma-separated. */ - uid?: string; - /** Filter lower bound on joinTime (Unix ms). Required with joinTimeEnd; max 90d span, not older than 180d. */ - joinTimeBegin?: string; - /** Filter upper bound on joinTime (Unix ms). Required with joinTimeBegin. */ - joinTimeEnd?: string; -} -⋮---- -/** Required when periodType=custom, together with end. Inclusive. */ -⋮---- -/** Required when periodType=custom, together with begin. Inclusive. */ -⋮---- -/** External user UIDs for exact match. Single or up to 100 comma-separated. */ -⋮---- -/** Filter lower bound on joinTime (Unix ms). Required with joinTimeEnd; max 90d span, not older than 180d. */ -⋮---- -/** Filter upper bound on joinTime (Unix ms). Required with joinTimeBegin. */ -⋮---- -export interface GetAffiliateLinkListRequest { - page?: string; - limit?: string; - linkType?: AffiliateLinkType; - linkStatus?: AffiliateLinkStatus; -} -⋮---- -export interface GetAffiliateCoInviterLinkListRequest { - page?: string; - limit?: string; - linkStatus?: AffiliateLinkStatus; +const ws = new WebsocketClient(); + +const topics = [ + { channel: 'tickers', instId: 'BTC-USDT' }, + { channel: 'books', instId: 'BTC-USDT' }, + { channel: 'candle1m', instId: 'BTC-USDT' }, +] satisfies WsChannelSubUnSubRequestArg[]; + +ws.on('update', (event) => { + console.log(event.arg.channel, event.data); +}); + +ws.on('exception', (error) => { + console.error('WebSocket exception:', error); +}); + +ws.subscribe(topics); + +function shutdown() { + ws.closeAll(); } -⋮---- -export interface GetAffiliateSubAffiliateListRequest { - page?: string; - limit?: string; - keyword?: string; - commissionCategory?: AffiliateCommissionCategory; - orderBy?: AffiliateSubAffiliateListOrderBy; - orderDir?: AffiliateOrderDir; + +process.once('SIGINT', shutdown); +``` + +There is no need to unsubscribe before `closeAll()`. Use `unsubscribe()` only when the application should stop receiving a topic while its other WebSocket connections remain active. + +### Private streams and recovery + +The SDK reconnects and resubscribes after a connection gap. That restores transport and subscription state, but it cannot recover updates that OKX sent while the connection was unavailable. + +Backfill private state through REST API before order logic relies on the stream again: + + + +```typescript +import { RestClient, WebsocketClient } from 'okx-api'; + +const credentials = { + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, +}; +const rest = new RestClient(credentials); +const ws = new WebsocketClient({ accounts: [credentials] }); + +async function refreshAccountState() { + const instrumentTypes = [ + 'SPOT', + 'MARGIN', + 'SWAP', + 'FUTURES', + 'OPTION', + ] as const; + + let balanceRows = 0; + let positionRows = 0; + let openOrderRows = 0; + let recentFillRows = 0; + + try { + const balances = await rest.getBalance(); + balanceRows = balances.length; + } catch (error) { + console.error('Failed to refresh balances:', error); + } + + try { + const positions = await rest.getPositions(); + positionRows = positions.length; + } catch (error) { + console.error('Failed to refresh positions:', error); + } + + for (const instType of instrumentTypes) { + try { + const openOrders = await rest.getOrderList({ instType }); + openOrderRows += openOrders.length; + } catch (error) { + console.error(`Failed to refresh ${instType} orders:`, error); + } + } + + try { + const fills = await rest.getFills({ limit: '100' }); + recentFillRows = fills.length; + } catch (error) { + console.error('Failed to refresh fills:', error); + } + + console.log('Account state refreshed:', { + balanceRows, + positionRows, + openOrderRows, + recentFillRows, + }); } -================ -File: src/types/rest/response/private-affiliate.ts -================ -import type { AffiliateCommissionCategory } from '../request/affiliate.js'; -⋮---- -export interface AffiliatePerformanceSummaryDetail { - commissionCategory: AffiliateCommissionCategory; - firstTraderCnt: string; - traderCnt: string; - vol: string; - commission: string; +ws.on('reconnect', ({ wsKey }) => { + console.log('Pausing stream-dependent work:', wsKey); +}); + +ws.on('reconnected', ({ wsKey }) => { + console.log('Reconnected, refreshing private state:', wsKey); + refreshAccountState(); +}); + +ws.on('update', (event) => { + console.log(event.arg.channel, event.data); +}); + +ws.on('exception', (error) => { + console.error('WebSocket exception:', error); +}); + +ws.subscribe([ + { channel: 'account' }, + { channel: 'positions', instType: 'ANY' }, + { channel: 'orders', instType: 'ANY' }, +]); +``` + +A production application should replace the `console.log()` summary with one atomic state update and resume stream-dependent work only after the refresh succeeds. This is [REST Hydration](https://siebly.io/reference/glossary#rest-hydration) applied after a connection gap. + +For more detail on deciding which state needs repair, see [Scoped Recovery](https://siebly.io/reference/glossary#scoped-recovery), [Exchange State](https://siebly.io/reference/exchange-state), and [Runtime Workflows](https://siebly.io/reference/runtime-workflows). + +--- + + + +## WebSocket API + +The OKX WebSocket API sends order-management commands over an authenticated socket. `WebsocketAPIClient` handles connection setup, authentication, request IDs, response matching, and promise resolution. + +The main methods are: + +| SDK method | Operation | +| -------------------------- | -------------------------------------- | +| `submitNewOrder()` | Place one order | +| `submitMultipleOrders()` | Place a batch | +| `amendOrder()` | Amend one order | +| `amendMultipleOrders()` | Amend a batch | +| `cancelOrder()` | Cancel one order | +| `cancelMultipleOrders()` | Cancel a batch | +| `massCancelOrders()` | Cancel orders for an instrument family | +| `submitSpreadOrder()` | Place one spread order | +| `amendSpreadOrder()` | Amend one spread order | +| `cancelSpreadOrder()` | Cancel one spread order | +| `massCancelSpreadOrders()` | Cancel spread orders | + +Standard order commands use the private WebSocket. Spread commands use the business WebSocket. The wrapper selects the connection for each method. + +`connectWSAPI()` is optional. Calling it during startup prepares and authenticates the required connection before the first command. The first command can also open the connection automatically. + +### Check acknowledgements at both levels + +Every response has a top-level `code`, `msg`, and `data` array. Each item in `data` has its own `sCode` and `sMsg`. + +Use both checks: + +```typescript +type OkxCommandItem = { + sCode: string; + sMsg: string; + ordId?: string; + clOrdId?: string; +}; + +function assertOkxCommandAccepted(response: { + code: string; + msg: string; + data: OkxCommandItem[]; +}) { + if (response.code !== '0') { + throw new Error(response.msg || `OKX command failed: ${response.code}`); + } + + const failedItems = response.data.filter((item) => item.sCode !== '0'); + + if (failedItems.length > 0) { + throw new Error( + failedItems + .map((item) => `${item.clOrdId || item.ordId}: ${item.sMsg}`) + .join('; '), + ); + } } -⋮---- -export interface AffiliatePerformanceSummary { - uTime: string; - inviteeCnt: string; - depAmt: string; - details: AffiliatePerformanceSummaryDetail[]; +``` + +Batch commands can contain a mix of successful and failed items. Do not treat a top-level success as proof that every order was accepted. + +For current WebSocket order placement, prefer an `instIdCode` obtained from `getInstruments()`. Identify amend and cancel commands with `ordId` or `clOrdId` as required by the current OKX operation. + +An accepted WebSocket API command is still not final order state. Watch the private `orders` channel, then use REST API when an update is missing or the connection has a gap. + +`WebsocketClient.sendWSAPIRequest()` is available for lower-level operation calls. Use `WebsocketAPIClient` for the typed convenience methods unless the wrapper does not yet expose the operation you need. + +See the repository examples for both approaches: + +- [Promise-based WebSocket API client](../examples/Websocket/WS-API/ws-api-client.ts) +- [Lower-level WebSocket API requests](../examples/Websocket/WS-API/ws-api-trade-raw.ts) + +--- + + + +## Demo trading + +OKX demo trading uses simulated accounts and separate demo API keys. It is the right place to test authentication, request fields, permissions, order acknowledgements, private streams, and reconciliation before a live order. + +Set the same option on whichever client the workflow uses: + +```typescript +import { RestClient, WebsocketAPIClient, WebsocketClient } from 'okx-api'; + +const credentials = { + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, +}; + +const rest = new RestClient({ + ...credentials, + demoTrading: true, +}); + +const streams = new WebsocketClient({ + accounts: [credentials], + demoTrading: true, +}); + +const wsApi = new WebsocketAPIClient({ + accounts: [credentials], + demoTrading: true, +}); +``` + +For a complete copy-pastable order flow with credential checks and an explicit opt-in, use the [demo REST API example](#5-first-rest-api-order-in-demo-trading) or [demo WebSocket API example](#6-first-websocket-api-order-command) above. + +With `demoTrading: true`, `RestClient` adds the required simulated-trading header. The WebSocket clients select the demo public, private, and business hosts. Do not use `market: 'demo'`. + +Demo trading does not support every funding or account action. Keep demo and live credentials in separate secret-store entries, and do not treat demo liquidity or fills as representative of live trading. + +Regional routing and demo trading can be combined. Set both `market` and `demoTrading: true` on each client. See [Demo Trading](https://siebly.io/reference/glossary#demo-trading) for the terminology used across Siebly guides. + +--- + + + +## Regional API routing + +Use the API group associated with the domain where the OKX account was registered. The SDK applies that choice to REST API, public WebSocket, private WebSocket, business WebSocket, and WebSocket API connections. + +| Account API group | SDK `market` | REST API host | WebSocket host family | +| ----------------------------- | ---------------------------------- | ----------------- | --------------------- | +| Global compatibility default | Omit it, or use `prod` or `GLOBAL` | `www.okx.com` | `ws.okx.com` | +| Global OpenAPI host | `OPENAPI_GLOBAL` | `openapi.okx.com` | `ws.okx.com` | +| EEA account from `my.okx.com` | `EEA` | `eea.okx.com` | `wseea.okx.com` | +| Account from `app.okx.com` | `US` | `us.okx.com` | `wsus.okx.com` | + +`OPENAPI_GLOBAL` changes the REST API host but uses the same WebSocket hosts as `GLOBAL`. + +Pass the same `market` to every client used by one account: + + + +```typescript +import { RestClient, WebsocketAPIClient, WebsocketClient } from 'okx-api'; + +const market = 'EEA' as const; +const credentials = { + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, +}; + +const rest = new RestClient({ + ...credentials, + market, +}); + +const streams = new WebsocketClient({ + accounts: [credentials], + market, +}); + +const wsApi = new WebsocketAPIClient({ + accounts: [credentials], + market, +}); +const wsApiConnection = wsApi.getWSClient(); + +async function main() { + try { + const time = await rest.getSystemTime({}); + console.log('REST API connected:', time[0]?.ts); + } catch (error) { + console.error('REST API connection failed:', error); + } + + streams.subscribe({ + channel: 'account', + }); + + try { + await wsApi.connectWSAPI(); + console.log('WebSocket API connected'); + } catch (error) { + console.error('WebSocket API connection failed:', error); + shutdown(); + } } -⋮---- -export interface InviteeDetail { - inviteeLevel: string; - joinTime: string; - inviteeRebateRate: string; - totalCommission: string; - firstTradeTime: string; - level: string; - depAmt: string; - wdAmt: string; - volMonth: string; - totalVol: string; - accFee: string; - kycTime: string; - region: string; - affiliateCode: string; - /** Trading volume in selected periodType window (USDT). Only when periodType supplied. */ - volPeriod?: string; + +function shutdown() { + streams.closeAll(); + wsApiConnection.closeAll(); } -⋮---- -/** Trading volume in selected periodType window (USDT). Only when periodType supplied. */ -⋮---- -export type AffiliateInviteeListKycStatus = 'unverified' | 'verified'; -⋮---- -export interface AffiliateInviteeListItem { - uid: string; - country: string; - joinTime: string; - firstTradeTime: string; - channelName: string; - rebateRate: string; - feeTierRank: string; - kycStatus: AffiliateInviteeListKycStatus; - kycTime: string; - depAmt: string; - totalVol: string; - totalFee: string; - totalCommission: string; - isCompliant: boolean; + +process.once('SIGINT', shutdown); + +main(); +``` + +Change `market` to the API group for the account. Product and endpoint availability can differ by region, so use the corresponding [Global](https://www.okx.com/docs-v5/en/), [EEA](https://my.okx.com/docs-v5/en/), or [US](https://app.okx.com/docs-v5/en/) OKX documentation. + +`baseUrl` and `wsUrl` are custom overrides. Use `market` for the supported regional groups so REST API and every WebSocket connection remain aligned. + +A proxy does not change an account's API group. Regional routing selects the OKX hosts; a proxy only changes the network path used to reach them. + +--- + + + +## Proxies for REST API and WebSocket + +Proxies are useful when a deployment needs a stable egress IP, must pass through an approved corporate network, or uses controlled network failover. They do not replace OKX regional routing or account eligibility checks. + +The broader [Using proxy with Siebly SDKs](https://siebly.io/blog/using-proxy-with-siebly-sdks) article covers the shared constructor pattern. The examples below use the current `okx-api` options directly. + +### HTTP or HTTPS proxy + +Install the agent: + +```bash +npm install okx-api https-proxy-agent +``` + +Set `OKX_PROXY_URL` to the full proxy URL, including credentials when required. + +This public check sends both REST API and WebSocket traffic through the same proxy: + + + +```typescript +import { HttpsProxyAgent } from 'https-proxy-agent'; +import { RestClient, WebsocketClient } from 'okx-api'; + +const proxyUrl = process.env.OKX_PROXY_URL; + +if (!proxyUrl) { + throw new Error('Set OKX_PROXY_URL before running this example.'); } -⋮---- -export type AffiliateLinkListLinkType = 'standard' | 'co_inviter'; -⋮---- -export type AffiliateLinkListLinkStatus = 'normal' | 'abnormal'; -⋮---- -export interface AffiliateLinkListItem { - channelId: string; - channelName: string; - joinLink: string; - linkType: AffiliateLinkListLinkType; - inviterCommissionRate: string; - coInviterCommissionRate: string; - inviteeDiscountRate: string; - inviteeCnt: string; - traderCnt: string; - totalCommission: string; - commission24h: string; - cTime: string; - isDefault: boolean; - linkStatus: AffiliateLinkListLinkStatus; -} -⋮---- -export type AffiliateChannelAssessmentStatus = - | 'valid' - | 'not_reach_trade' - | 'not_reach_invite' - | 'not_reach_both'; -⋮---- -export type AffiliateInviterChannelStatus = - | 'valid' - | 'identity_invalid' - | 'level_downgraded'; -⋮---- -export type AffiliateCoInviterChannelStatus = - | 'valid' - | 'identity_invalid' - | 'not_reach_assessment' - | 'identity_invalid_and_not_reach_assessment'; -⋮---- -export interface AffiliateCoInviterLinkListItem { - channelId: string; - channelName: string; - joinLink: string; - inviterCommissionRate: string; - coInviterCommissionRate: string; - inviteeDiscountRate: string; - parUserName: string; - coUserName: string; - isCompliant: boolean; - note?: string; - isDefault: boolean; - totalCommission: string; - commission24h: string; - inviteeCnt: string; - traderCnt: string; - clickCnt: string; - totalFee: string; - cTime: string; - channelAssessmentStatus: AffiliateChannelAssessmentStatus; - inviterChannelStatus: AffiliateInviterChannelStatus; - coInviterChannelStatus: AffiliateCoInviterChannelStatus; - linkStatus: AffiliateLinkListLinkStatus; -} -⋮---- -export interface AffiliateSubAffiliateListItem { - subAffiliateUid: string; - country: string; - joinTime: string; - subAffiliateLevel: string; - commissionRate: string; - isCompliant: boolean; - inviteeCnt: string; - traderCnt: string; - depAmt: string; - totalVol: string; - totalFee: string; - totalCommission: string; + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); } -================ -File: src/types/rest/response/private-funding.ts -================ -import { ASSET_BILL_TYPE } from '../../../constants/funding.js'; -⋮---- -export interface FundingCurrency { - ccy: string; // Currency code (e.g., "BTC") - name: string; // Currency name - logoLink: string; // Currency logo URL - chain: string; // Chain name (e.g., "BTC-Bitcoin") - ctAddr: string; // Contract address - canDep: boolean; // Deposit availability - canWd: boolean; // Withdrawal availability - canInternal: boolean; // Internal transfer availability - depEstOpenTime: string; // Estimated deposit opening time (timestamp) - wdEstOpenTime: string; // Estimated withdrawal opening time (timestamp) - minDep: string; // Minimum deposit amount - minWd: string; // Minimum withdrawal amount - minInternal: string; // Minimum internal transfer amount - maxWd: string; // Maximum withdrawal amount per transaction - wdTickSz: string; // Withdrawal precision (decimal places) - wdQuota: string; // 24h withdrawal limit in USD - usedWdQuota: string; // Used withdrawal quota in USD - fee: string; // Fixed withdrawal fee - minFee: string; // Minimum withdrawal fee (deprecated) - maxFee: string; // Maximum withdrawal fee (deprecated) - minFeeForCtAddr: string; // Minimum contract address withdrawal fee (deprecated) - maxFeeForCtAddr: string; // Maximum contract address withdrawal fee (deprecated) - burningFeeRate: string; // Burning fee rate (e.g., "0.05" for 5%) - mainNet: boolean; // Is main network - needTag: boolean; // Requires tag/memo for withdrawal - minDepArrivalConfirm: string; // Min confirmations for deposit credit - minWdUnlockConfirm: string; // Min confirmations for withdrawal unlock - depQuotaFixed: string; // Fixed deposit limit in USD - usedDepQuotaFixed: string; // Used fixed deposit quota in USD - depQuoteDailyLayer2: string; // Layer2 daily deposit limit -} -⋮---- -ccy: string; // Currency code (e.g., "BTC") -name: string; // Currency name -logoLink: string; // Currency logo URL -chain: string; // Chain name (e.g., "BTC-Bitcoin") -ctAddr: string; // Contract address -canDep: boolean; // Deposit availability -canWd: boolean; // Withdrawal availability -canInternal: boolean; // Internal transfer availability -depEstOpenTime: string; // Estimated deposit opening time (timestamp) -wdEstOpenTime: string; // Estimated withdrawal opening time (timestamp) -minDep: string; // Minimum deposit amount -minWd: string; // Minimum withdrawal amount -minInternal: string; // Minimum internal transfer amount -maxWd: string; // Maximum withdrawal amount per transaction -wdTickSz: string; // Withdrawal precision (decimal places) -wdQuota: string; // 24h withdrawal limit in USD -usedWdQuota: string; // Used withdrawal quota in USD -fee: string; // Fixed withdrawal fee -minFee: string; // Minimum withdrawal fee (deprecated) -maxFee: string; // Maximum withdrawal fee (deprecated) -minFeeForCtAddr: string; // Minimum contract address withdrawal fee (deprecated) -maxFeeForCtAddr: string; // Maximum contract address withdrawal fee (deprecated) -burningFeeRate: string; // Burning fee rate (e.g., "0.05" for 5%) -mainNet: boolean; // Is main network -needTag: boolean; // Requires tag/memo for withdrawal -minDepArrivalConfirm: string; // Min confirmations for deposit credit -minWdUnlockConfirm: string; // Min confirmations for withdrawal unlock -depQuotaFixed: string; // Fixed deposit limit in USD -usedDepQuotaFixed: string; // Used fixed deposit quota in USD -depQuoteDailyLayer2: string; // Layer2 daily deposit limit -⋮---- -export interface FundingBalance { - availBal: string; - bal: string; - ccy: string; - frozenBal: string; -} -⋮---- -export interface AccountAssetValuation { - details: { - classic: string; - earn: string; - funding: string; - trading: string; - }; - totalBal: string; - ts: string; -} -⋮---- -export interface FundTransferResult { - transId: string; - ccy: string; - clientId: string; - from: string; - amt: string; - to: string; -} -export interface FundTransferState { - amt: string; - ccy: string; - clientId: string; - from: string; - instId: never; // deprecated - state: string; - subAcct: string; - to: string; - toInstId: never; // deprecated - transId: string; - type: string; -} -⋮---- -instId: never; // deprecated -⋮---- -toInstId: never; // deprecated -⋮---- -export interface AssetBillDetails { - billId: string; - ccy: string; - clientId: string; - balChg: string; - bal: string; - type: `${ASSET_BILL_TYPE}`; - notes: string; - ts: string; -} -⋮---- -export interface WithdrawResponse { - ccy: string; - chain: string; - amt: string; - wdId: string; - clientId: string; -} -⋮---- -export interface NonTradableAsset { - ccy: string; - name: string; - logoLink: string; - bal: string; - canWd: boolean; - chain: string; - minWd: string; - wdAll: boolean; - fee: string; - ctAddr: string; - wdTickSz: string; - needTag: boolean; - burningFeeRate: string; - feeCcy: string; -} -⋮---- -export interface DepositHistory { - ccy: string; // Currency, e.g. BTC - chain: string; // Chain name - amt: string; // Deposit amount - from: string; // Deposit account. If the deposit comes from internal transfer, displays account info (phone/email, masked). Returns "" otherwise. - areaCodeFrom: string; // If from is a phone number, this parameter returns area code of the phone number - to: string; // Deposit address. If the deposit comes from on-chain, displays the on-chain address. Returns "" otherwise. - txId: string; // Hash record of the deposit - ts: string; // Timestamp that the deposit record is created, Unix timestamp format in milliseconds, e.g. 1655251200000 - state: string; // Status of deposit: 0=waiting for confirmation, 1=deposit credited, 2=deposit successful, 8=pending due to temp suspension, 11=match blacklist, 12=account/deposit frozen, 13=sub-account deposit interception, 14=KYC limit - depId: string; // Deposit ID - fromWdId: string; // Internal transfer initiator's withdrawal ID. If deposit comes from internal transfer, displays the withdrawal ID, returns "" otherwise - actualDepBlkConfirm: string; // The actual amount of blockchain confirmed in a single deposit -} -⋮---- -ccy: string; // Currency, e.g. BTC -chain: string; // Chain name -amt: string; // Deposit amount -from: string; // Deposit account. If the deposit comes from internal transfer, displays account info (phone/email, masked). Returns "" otherwise. -areaCodeFrom: string; // If from is a phone number, this parameter returns area code of the phone number -to: string; // Deposit address. If the deposit comes from on-chain, displays the on-chain address. Returns "" otherwise. -txId: string; // Hash record of the deposit -ts: string; // Timestamp that the deposit record is created, Unix timestamp format in milliseconds, e.g. 1655251200000 -state: string; // Status of deposit: 0=waiting for confirmation, 1=deposit credited, 2=deposit successful, 8=pending due to temp suspension, 11=match blacklist, 12=account/deposit frozen, 13=sub-account deposit interception, 14=KYC limit -depId: string; // Deposit ID -fromWdId: string; // Internal transfer initiator's withdrawal ID. If deposit comes from internal transfer, displays the withdrawal ID, returns "" otherwise -actualDepBlkConfirm: string; // The actual amount of blockchain confirmed in a single deposit +const proxyAgent = new HttpsProxyAgent(proxyUrl); +const market = 'OPENAPI_GLOBAL' as const; -================ -File: src/types/rest/client.ts -================ -import { APIMarket } from '../shared.js'; -⋮---- -export interface RestClientOptions { - apiKey?: string; - apiSecret?: string; - apiPass?: string; +const rest = new RestClient( + { market }, + { + httpsAgent: proxyAgent, + proxy: false, + }, +); - /** - * The API group this client should connect to: - * - market: 'prod' (default: connects to OKX global) https://www.okx.com/docs-v5/en/#overview-production-trading-services - * - market: 'OPENAPI_GLOBAL' // OKX Global REST at https://openapi.okx.com - * - market: 'EEA' // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services - * - market: 'US' // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services - */ - market?: APIMarket; +const ws = new WebsocketClient({ + market, + wsOptions: { + agent: proxyAgent, + }, +}); - /** - * Set to `true` to use OKX's demo trading functionality - */ - demoTrading?: boolean; +ws.on('open', ({ wsKey }) => { + console.log('WebSocket connected through proxy:', wsKey); +}); - // Default: false. If true, we'll throw errors if any params are undefined - strict_param_validation?: boolean; +ws.on('update', (event) => { + console.log(event.arg.channel, event.data); +}); - // Optionally override REST API base URL (e.g. 'https://www.okx.com' or 'https://openapi.okx.com'). - // Note: to use my.okx or app.okx or eea.okx or us.okx, use the "market" parameter - // e.g 'https://eea.okx.com' - baseUrl?: string; +ws.on('exception', (error) => { + console.error('WebSocket proxy error:', errorMessage(error)); +}); - // Default: true. whether to try and post-process request exceptions. - parse_exceptions?: boolean; +async function main() { + try { + const time = await rest.getSystemTime({}); + console.log('REST API connected through proxy:', time[0]?.ts); + } catch (error) { + console.error('REST API proxy request failed:', errorMessage(error)); + } - /** - * Enable keep alive for REST API requests (via axios). - */ - keepAlive?: boolean; + ws.subscribe({ + channel: 'tickers', + instId: 'BTC-USDT', + }); +} - /** - * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. - * Only relevant if keepAlive is set to true. - * Default: 1000 (defaults comes from https agent) - */ - keepAliveMsecs?: number; +process.once('SIGINT', () => { + ws.closeAll(); +}); - /** - * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method - * - * Look in the examples folder for a demonstration on using node's createHmac instead. - */ - customSignMessageFn?: (message: string, secret: string) => Promise; -} -⋮---- -/** - * The API group this client should connect to: - * - market: 'prod' (default: connects to OKX global) https://www.okx.com/docs-v5/en/#overview-production-trading-services - * - market: 'OPENAPI_GLOBAL' // OKX Global REST at https://openapi.okx.com - * - market: 'EEA' // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services - * - market: 'US' // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services - */ -⋮---- -/** - * Set to `true` to use OKX's demo trading functionality - */ -⋮---- -// Default: false. If true, we'll throw errors if any params are undefined -⋮---- -// Optionally override REST API base URL (e.g. 'https://www.okx.com' or 'https://openapi.okx.com'). -// Note: to use my.okx or app.okx or eea.okx or us.okx, use the "market" parameter -// e.g 'https://eea.okx.com' -⋮---- -// Default: true. whether to try and post-process request exceptions. -⋮---- -/** - * Enable keep alive for REST API requests (via axios). - */ -⋮---- -/** - * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. - * Only relevant if keepAlive is set to true. - * Default: 1000 (defaults comes from https agent) - */ -⋮---- -/** - * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method - * - * Look in the examples folder for a demonstration on using node's createHmac instead. - */ +main(); +``` -================ -File: src/types/websockets/ws-api-response.ts -================ -import { numberInString } from '../rest/shared.js'; -⋮---- -export interface WSAPICancelOrderResultV5 { - clOrdId: string; - ordId: string; - ts: numberInString; - sCode: string; - subCode?: string; - sMsg: string; -} -⋮---- -export interface WSAPISpreadPlaceOrderResultV5 { - clOrdId: string; - ordId: string; - tag: string; - sCode: numberInString; - subCode?: string; - sMsg: string; +REST API networking options belong in the second `RestClient` argument: + +- `httpsAgent` carries HTTPS requests through the proxy agent. +- `proxy: false` prevents Axios from applying another proxy configuration on top of that agent. + +WebSocket networking options belong in `wsOptions.agent`. The same setting works for public streams, private streams, business streams, and `WebsocketAPIClient`. + +OKX authenticates private WebSockets over the socket. Unlike exchanges that fetch a listen key or WebSocket token through REST API first, OKX does not need a second REST API proxy setting inside its WebSocket client. + +### Private streams and WebSocket API through a proxy + +Use the same agent with credentials: + + + +```typescript +import { HttpsProxyAgent } from 'https-proxy-agent'; +import { WebsocketAPIClient, WebsocketClient } from 'okx-api'; + +const proxyUrl = process.env.OKX_PROXY_URL; + +if (!proxyUrl) { + throw new Error('Set OKX_PROXY_URL before running this example.'); } -⋮---- -export interface WSAPISpreadAmendOrderResultV5 { - clOrdId: string; - ordId: string; - reqId: string; - sCode: string; - subCode?: string; - sMsg: string; + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); } -⋮---- -export interface WSAPISpreadCancelOrderResultV5 { - clOrdId: string; - ordId: string; - sCode: string; - subCode?: string; - sMsg: string; + +const credentials = { + apiKey: process.env.OKX_API_KEY!, + apiSecret: process.env.OKX_API_SECRET!, + apiPass: process.env.OKX_API_PASSPHRASE!, +}; +const proxyAgent = new HttpsProxyAgent(proxyUrl); +const market = 'OPENAPI_GLOBAL' as const; + +const streams = new WebsocketClient({ + accounts: [credentials], + market, + wsOptions: { + agent: proxyAgent, + }, +}); + +const wsApi = new WebsocketAPIClient({ + accounts: [credentials], + market, + attachEventListeners: false, + wsOptions: { + agent: proxyAgent, + }, +}); +const wsApiConnection = wsApi.getWSClient(); + +streams.on('authenticated', ({ wsKey }) => { + console.log('Private stream authenticated:', wsKey); +}); +streams.on('exception', (error) => { + console.error('Private stream error:', errorMessage(error)); +}); +wsApiConnection.on('authenticated', ({ wsKey }) => { + console.log('WebSocket API authenticated:', wsKey); +}); +wsApiConnection.on('exception', (error) => { + console.error('WebSocket API error:', errorMessage(error)); +}); + +async function main() { + streams.subscribe([ + { channel: 'account' }, + { channel: 'orders', instType: 'ANY' }, + ]); + + try { + await wsApi.connectWSAPI(); + console.log('Private connections are ready'); + } catch (error) { + console.error('WebSocket API connection failed:', errorMessage(error)); + streams.closeAll(); + wsApiConnection.closeAll(); + } } -⋮---- -/** - * @see Ws public channel: estimated-price - */ -export type WsEstimatedPriceSettleType = 'settlement' | 'delivery' | 'exercise'; -⋮---- -export interface WsEstimatedPriceData { - instId: string; - instType: string; - settlePx: string; - settleType: WsEstimatedPriceSettleType; - ts: string; + +process.once('SIGINT', () => { + streams.closeAll(); + wsApiConnection.closeAll(); +}); + +main(); +``` + +This validates private authentication without placing an order. Add `demoTrading: true` to both clients when testing with demo keys. + +### SOCKS5 proxy + +Install the SOCKS agent: + +```bash +npm install okx-api socks-proxy-agent +``` + +Use `SocksProxyAgent` in the same REST API and WebSocket positions: + + + +```typescript +import { RestClient, WebsocketClient } from 'okx-api'; +import { SocksProxyAgent } from 'socks-proxy-agent'; + +const proxyUrl = process.env.OKX_SOCKS_PROXY_URL; + +if (!proxyUrl) { + throw new Error('Set OKX_SOCKS_PROXY_URL before running this example.'); } -================ -File: src/types/websockets/ws-events.ts -================ -import { WsChannel } from './ws-request.js'; -⋮---- -export interface MessageEventLike { - target: WebSocket; - type: 'message'; - data: string; +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); } -⋮---- -export function isMessageEvent(msg: unknown): msg is MessageEventLike -⋮---- -export interface WsEvent { - event: - | 'error' - | 'login' - | 'subscribe' - | 'unsubscribe' - | 'channel-conn-count' - | 'notice'; - code?: string; - msg?: string; - connId?: string; - arg?: any; - data?: any; + +const proxyAgent = new SocksProxyAgent(proxyUrl); + +const rest = new RestClient( + {}, + { + httpsAgent: proxyAgent, + proxy: false, + }, +); + +const ws = new WebsocketClient({ + wsOptions: { + agent: proxyAgent, + }, +}); + +async function main() { + try { + const time = await rest.getSystemTime({}); + console.log('REST API connected through SOCKS5:', time[0]?.ts); + } catch (error) { + console.error('SOCKS5 REST API request failed:', errorMessage(error)); + } + + ws.subscribe({ + channel: 'tickers', + instId: 'BTC-USDT', + }); } + +process.once('SIGINT', () => { + ws.closeAll(); +}); + +main(); +``` + +### Proxy checks + +- Keep proxy URLs and credentials in environment variables or a secret manager. +- URL-encode usernames and passwords when constructing a proxy URL from separate values. +- Make sure the proxy egress IP matches the API key's OKX IP whitelist. +- Test a public REST API call and public WebSocket subscription before private authentication. +- Measure request, connection, and reconnect latency through the proxy. +- Treat repeated HTTP 407 responses, TLS errors, and WebSocket reconnect loops as network failures. +- Keep the host clock synchronized. Extra network latency does not change how OKX signatures are calculated. +- Do not add a generic `recvWindow` setting. `okx-api` does not expose one. +- The SDK does not rotate proxy endpoints. Handle endpoint selection outside the client when rotation is required. + +--- + + + +## Production notes + +Before an OKX integration trades unattended: + +1. Roll out in stages: public REST API, private read-only REST API, public streams, private streams, demo writes, then small controlled live tests. +2. Use a unique `clOrdId` on every application-owned order. +3. Check REST API item-level `sCode` values and WebSocket API top-level plus item-level codes. +4. Treat command acceptance as pending until a private stream or REST API query confirms the resulting order state. +5. Reconcile balances, positions, pending orders, recent history, and fills after a private stream gap. +6. Keep the system clock synchronized. OKX rejects stale signed requests. +7. Respect IP, user, instrument, and connection rate limits from the relevant OKX endpoint documentation. +8. Keep `market`, account mode, position mode, `tdMode`, `instType`, and `instId` in structured logs. +9. Keep live, demo, and regional credentials separate. +10. Keep credentials out of frontend code, exceptions, and logs. +11. Monitor proxy availability, latency, and egress IP when a proxy is enabled. +12. Unsubscribe or call `closeAll()` during a controlled shutdown. + +The SDK restores WebSocket connections and cached subscriptions. Your application must still recover state, reconcile orders, and decide when writes can resume after a gap. + +--- + + + +## FAQ + +### Do public OKX API calls need keys? + +Most public REST API endpoints and public WebSocket channels do not. Private account methods, private channels, WebSocket API commands, and a small number of high-depth public channels require credentials. + +### What is `apiPass`? + +It is the passphrase chosen when the OKX API key was created. It is not the account login password. + +### Which SDK client should I use? + +Use `RestClient` for request/response calls and broad endpoint coverage, `WebsocketClient` for live channel updates, and `WebsocketAPIClient` for supported promise-based commands over WebSocket. Many applications use all three. + +### Why do REST API methods return arrays? + +The SDK returns the parsed OKX `data` value after a successful call. OKX commonly puts result rows in a `data` array, including endpoints that normally return one row. + +### What is the difference between `SPOT`, `MARGIN`, `SWAP`, `FUTURES`, and `OPTION`? + +They are OKX instrument types. Spot and Margin use cash-market instrument IDs, Swap identifies perpetual contracts, Futures identifies dated contracts, and Option identifies option contracts. Query `getInstruments()` for current product details. + +### What is the difference between `instType`, `instId`, and `instFamily`? + +`instType` is a product family, `instId` is one exact instrument, and `instFamily` groups related derivatives. The method's TypeScript request type shows which one it needs. + +### Why did an order fail under the current account mode? + +Valid `tdMode`, `posSide`, leverage, and margin fields depend on account mode and position mode. Read `getAccountConfiguration()`, then build requests for that configuration instead of copying fields from another account. + +### Is OKX demo trading the same as testnet? + +No. The SDK uses OKX demo trading with separate demo API keys and `demoTrading: true`. Do not use testnet flags from another exchange SDK. + +### Why should I check both `code` and `sCode`? + +WebSocket API responses have a top-level command result and item-level results. REST API order methods return the parsed items, whose `sCode` values can report individual failures. Batch requests can have mixed outcomes. + +### Why did a candle subscription open a business WebSocket? + +OKX routes candle channels through its business WebSocket. `WebsocketClient` detects the channel and selects that connection automatically. + +### Which regional `market` value should I use? + +Use the group associated with the account's registration domain: the Global default or `OPENAPI_GLOBAL`, `EEA` for `my.okx.com`, and `US` for `app.okx.com`. + +### Can regional routing and demo trading be combined? + +Yes. Pass both the regional `market` and `demoTrading: true` to every client in the workflow, using demo keys for that account region. + +### How do I proxy REST API calls? + +Pass an Axios-compatible proxy agent as `httpsAgent` in the second `RestClient` argument. When using an agent, set `proxy: false`. + +### How do I proxy WebSocket streams and WebSocket API commands? + +Pass the agent as `wsOptions.agent` to `WebsocketClient` or `WebsocketAPIClient`. + +### Does a proxy change request signing? + +No. The SDK signs private requests locally before sending them. A proxy changes the network route, so latency and egress IP still need monitoring. + +### Can I use `okx-api` from plain JavaScript? + +Yes. The package supports ESM imports and CommonJS `require()`. Remove TypeScript annotations when using JavaScript: + +```javascript +const { RestClient } = require('okx-api'); + +const client = new RestClient(); +client.getTicker({ instId: 'BTC-USDT' }).then(console.log); +``` + +--- + + + +## Next steps + +- [OKX JavaScript SDK by Siebly](https://siebly.io/sdk/okx/javascript) +- [`okx-api` on npm](https://www.npmjs.com/package/okx-api) +- [OKX SDK source on GitHub](https://github.com/sieblyio/okx-api) +- [OKX SDK examples on Siebly](https://siebly.io/examples/OKX) +- [OKX SDK endpoint map](./endpointFunctionList.md) +- [OKX Global API documentation](https://www.okx.com/docs-v5/en/) +- [OKX EEA API documentation](https://my.okx.com/docs-v5/en/) +- [OKX US API documentation](https://app.okx.com/docs-v5/en/) +- [Siebly trading-system glossary](https://siebly.io/reference/glossary) +- [Siebly Exchange State reference](https://siebly.io/reference/exchange-state) +- [Siebly Runtime Workflows reference](https://siebly.io/reference/runtime-workflows) + +================ +File: examples/Rest/rest-private-trade.ts +================ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { RestClient } from '../../src/index.js'; +import { OrderRequest } from '../../src/types/rest/request/trade.js'; ⋮---- -export interface WsDataEvent { - arg: { - channel: WsChannel; - uid?: string; - instId?: string; - instFamily?: string; - instType?: string; - }; - data: T; -} +// or +// import { SpotClient } from 'okx-api'; ⋮---- -export interface WsLoginEvent extends WsEvent { - event: 'login'; -} +// read from environmental variables ⋮---- -export interface WsChannelConnInfoEvent extends WsEvent { - event: 'channel-conn-count'; - channel: string; - connId: string; - connCount: string; -} +// If running from CLI in unix, you can pass env vars as such: +// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/rest-private-trade.ts ⋮---- -export type WsResponse = WsEvent; - -================ -File: src/types/shared.ts -================ -export interface APICredentials { - apiKey: string; - apiSecret: string; - apiPass: string; -} +// note the single quotes, preventing special characters such as $ from being incorrectly passed ⋮---- -/** - * The API Market represents the OKX Domain that you have signed up for. At this time, there are 4 supported domain groups: - * - * - GLOBAL, otherwise known as "www.okx.com". - * - OPENAPI_GLOBAL, OKX Global REST at openapi.okx.com (same WS as GLOBAL). - * - EEA, otherwise known as "my.okx.com". - * - US, otherwise known as "app.okx.com". - */ -export type APIMarket = - | 'prod' // same as GLOBAL. Kept for some backwards compatibility - // also known as "www.okx.com" or OKX Global: https://www.okx.com/docs-v5/en/#overview-production-trading-services - | 'GLOBAL' - // OKX Global REST at https://openapi.okx.com. WebSocket URLs unchanged (same as GLOBAL). - | 'OPENAPI_GLOBAL' - // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services - | 'EEA' - // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services - | 'US'; +// apiKey: 'apiKeyHere', ⋮---- -| 'prod' // same as GLOBAL. Kept for some backwards compatibility -// also known as "www.okx.com" or OKX Global: https://www.okx.com/docs-v5/en/#overview-production-trading-services +// apiSecret: 'apiSecretHere', ⋮---- -// OKX Global REST at https://openapi.okx.com. WebSocket URLs unchanged (same as GLOBAL). +// apiPass: 'apiPassHere', ⋮---- -// also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services +// const wsClient = new WebsocketClient({ +// apiKey: API_KEY, +// apiSecret: API_SECRET, +// apiPass: API_PASS, +// }); ⋮---- -// also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services - -================ -File: src/websocket-api-client.ts -================ -import { OrderIdRequest } from './types/rest/request/trade.js'; -import { OrderResult } from './types/rest/response/private-trade.js'; -import { WSAPIResponse } from './types/websockets/ws-api.js'; -import { - WSAPIAmendOrderRequestV5, - WSAPIAmendSpreadOrderRequestV5, - WSAPICancelSpreadOrderRequestV5, - WSAPIMassCancelOrdersRequestV5, - WSAPIPlaceOrderRequestV5, - WSAPIPlaceSpreadOrderRequestV5, - WSAPISpreadMassCancelOrdersRequestV5, -} from './types/websockets/ws-api-request.js'; -import { - WSAPICancelOrderResultV5, - WSAPISpreadAmendOrderResultV5, - WSAPISpreadCancelOrderResultV5, - WSAPISpreadPlaceOrderResultV5, -} from './types/websockets/ws-api-response.js'; -import { WSClientConfigurableOptions } from './types/websockets/ws-general.js'; -import { DefaultLogger } from './util/logger.js'; -import { WebsocketClient } from './websocket-client.js'; +function logWSEvent(type: string, data: any) ⋮---- -/** - * Configurable options specific to only the REST-like WebsocketAPIClient - */ -export interface WSAPIClientConfigurableOptions { - /** - * Default: true - * - * Attach default event listeners, which will console log any high level - * events (opened/reconnecting/reconnected/etc). - * - * If you disable this, you should set your own event listeners - * on the embedded WS Client `wsApiClient.getWSClient().on(....)`. - */ - attachEventListeners: boolean; -} +// simple sleep function +function promiseSleep(milliseconds: number) ⋮---- -/** - * Default: true - * - * Attach default event listeners, which will console log any high level - * events (opened/reconnecting/reconnected/etc). - * - * If you disable this, you should set your own event listeners - * on the embedded WS Client `wsApiClient.getWSClient().on(....)`. - */ +// WARNING: for sensitive math you should be using a library such as decimal.js! +function roundDown(value: any, decimals: number) ⋮---- -/** - * This is a minimal Websocket API wrapper around the WebsocketClient. It allows you to use the WebSocket API in a promise-driven way, send a request and await the response. - * - * Note: You can also directly use the sendWSAPIRequest() method to make WS API calls, but some - * may find the below methods slightly more intuitive. - * - * Refer to the WS API promises example for a more detailed example on using sendWSAPIRequest() directly: - * https://github.com/tiagosiebler/okx-api/blob/master/examples/ws-api-trade-raw.ts - */ -export class WebsocketAPIClient +/** This is a simple script wrapped in a immediately invoked function expression, designed to check for any available BTC balance and immediately sell the full amount for USDT */ ⋮---- -constructor( - options?: WSClientConfigurableOptions & - Partial, - logger?: DefaultLogger, -) +// // Add event listeners to log websocket events on account +// wsClient.on('update', (data) => logWSEvent('update', data)); +// wsClient.on('open', (data) => logWSEvent('open', data)); +// wsClient.on('response', (data) => logWSEvent('response', data)); +// wsClient.on('reconnect', (data) => logWSEvent('reconnect', data)); +// wsClient.on('reconnected', (data) => logWSEvent('reconnected', data)); +// wsClient.on('authenticated', (data) => logWSEvent('authenticated', data)); +// wsClient.on('exception', (data) => logWSEvent('exception', data)); ⋮---- -public getWSClient(): WebsocketClient +// // Subscribe to private account topics +// wsClient.subscribeTopic('SPBL', 'account'); +// wsClient.subscribeTopic('SPBL', 'orders'); ⋮---- -public setTimeOffsetMs(newOffset: number): void +// wait briefly for ws to be ready (could also use the response or authenticated events, to make sure topics are subscribed to before starting) ⋮---- -/** - * - * - * OKX WebSocket API Methods - * - * - */ +// const balances = allBalances.filter((bal) => Number(bal.available) != 0); ⋮---- -/** - * Submit a new order - * - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order - */ -submitNewOrder( - params: WSAPIPlaceOrderRequestV5, -): Promise> +// console.log('balance: ', JSON.stringify(balances, null, 2)); ⋮---- -/** - * Submit multiple orders in a batch - * - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-multiple-orders - */ -submitMultipleOrders( - params: WSAPIPlaceOrderRequestV5[], -): Promise> +// example to find minimum allowed size for a symbol and place an order with it +/* const symbol = 'BTC-USDT-SWAP'; + + const symbolsResult = await client.getInstruments({ + instType: 'SWAP', + }); + const btcRules = symbolsResult.find((rule) => rule.instId === symbol); + console.log('btc trading rules: ', btcRules); + if (!btcRules) { + return console.log('no rules found for trading ' + symbol); + } + + const minSize = Number(btcRules.minSz); + + const order = { + instId: symbol, + tdMode: 'cross', + ordType: 'market', + side: 'sell', + sz: String(minSize), + } as const; + + console.log('submitting order: ', order); + + const sellResult = await client.submitOrder(order); + + console.log('sell result: ', sellResult); */ + +================ +File: examples/Websocket/WS-API/ws-api-client.ts +================ +import { DefaultLogger, WebsocketAPIClient } from '../../../src/index.js'; ⋮---- -/** - * Cancel a single order - * - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-cancel-order - */ -cancelOrder( - params: OrderIdRequest, -): Promise> +// or use the module installed via `npm install okx-api`: +// import { WebsocketClient, DefaultLogger } from 'okx-api'; ⋮---- -/** - * Cancel multiple orders - * - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-cancel-multiple-orders - */ -cancelMultipleOrders( - params: OrderIdRequest[], -): Promise> +// or if you're not using typescript (e.g. pure nodejs), change the "import" to "require": +// const { WebsocketClient, DefaultLogger } = require('okx-api'); ⋮---- -/** - * Amend a single order - * - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-amend-order - */ -amendOrder( - params: WSAPIAmendOrderRequestV5, -): Promise> +// function attachEventHandlers( +// wsClient: TWSClient, +// ): void { +// wsClient.on('update', (data) => { +// console.log('raw message received ', JSON.stringify(data)); +// }); +// wsClient.on('open', (data) => { +// console.log('ws connected', data.wsKey); +// }); +// wsClient.on('reconnect', ({ wsKey }) => { +// console.log('ws automatically reconnecting.... ', wsKey); +// }); +// wsClient.on('reconnected', (data) => { +// console.log('ws has reconnected ', data?.wsKey); +// }); +// wsClient.on('authenticated', (data) => { +// console.log('ws has authenticated ', data?.wsKey); +// }); +// } ⋮---- -/** - * Amend multiple orders - * - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-amend-multiple-orders - */ -amendMultipleOrders( - params: WSAPIAmendOrderRequestV5[], -): Promise> +// For private events, all 3 of the following are required (per account): ⋮---- -/** - * Mass cancel orders - * - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-mass-cancel-order - */ -massCancelOrders( - params: WSAPIMassCancelOrdersRequestV5, -): Promise> +// For Global users (www.okx.com), you don't need to set the market. +// It will use global by default. +// Not needed: market: 'GLOBAL', +⋮---- +// For EEA users (my.okx.com), set market to "EEA": +// market: 'EEA', +⋮---- +// For US users (app.okx.com), set market to "US": +// market: 'US', +⋮---- +// For private topics, include one or more accounts in an array. Otherwise only public topics will work +⋮---- +// Optional, see above "attachEventListeners". Attach basic event handlers, so nothing is left unhandled +// attachEventHandlers(wsClient.getWSClient()); +⋮---- +// Optional: prepare the WebSocket API connection in advance. +// This happens automatically but you can do this early before making any API calls, to prevent delays from a cold start. +// await wsClient.connectWSAPI(); ⋮---- /** - * Amend a spread order + * OKX's WebSocket API be used like a REST API, through this SDK's WebsocketAPIClient. The WebsocketAPIClient is a utility class wrapped around WebsocketClient's sendWSAPIRequest() capabilities. * - * https://www.okx.com/docs-v5/en/#spread-trading-websocket-trade-api-ws-amend-order + * Each request sent via the WebsocketAPIClient will automatically: + * - route via the active WS API connection + * - return a Promise, which automatically resolves/rejects when a matching response is received */ -amendSpreadOrder( - params: WSAPIAmendSpreadOrderRequestV5, - ): Promise< - WSAPIResponse<[WSAPISpreadAmendOrderResultV5], 'sprd-amend-order'> - > { - return this.wsClient.sendWSAPIRequest( - this.getWSClient().getMarketWsKey('business'), - 'sprd-amend-order', - params, - ); ⋮---- /** - * Cancel a spread order - * - * https://www.okx.com/docs-v5/en/#spread-trading-websocket-trade-api-ws-cancel-order + * Place Order + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order */ -cancelSpreadOrder( - params: WSAPICancelSpreadOrderRequestV5, - ): Promise< - WSAPIResponse<[WSAPISpreadCancelOrderResultV5], 'sprd-cancel-order'> - > { - return this.wsClient.sendWSAPIRequest( - this.getWSClient().getMarketWsKey('business'), - 'sprd-cancel-order', - params, - ); ⋮---- /** - * Mass cancel spread orders - * - * https://www.okx.com/docs-v5/en/#spread-trading-websocket-trade-api-ws-cancel-all-orders - */ -massCancelSpreadOrders( - params: WSAPISpreadMassCancelOrdersRequestV5, -): Promise>( - event: U, - listener: WSClientEventMap[U], - ): this; - - emit>( - event: U, - ...args: Parameters[U]> - ): boolean; -} +// or use the module installed via `npm install okx-api`: +// import { WebsocketClient, DefaultLogger } from 'okx-api'; ⋮---- -on>( - event: U, - listener: WSClientEventMap[U], - ): this; +// or if you're not using typescript (e.g. pure nodejs), change the "import" to "require": +// const { WebsocketClient, DefaultLogger } = require('okx-api'); ⋮---- -emit>( - event: U, - ...args: Parameters[U]> - ): boolean; +// For private events, all 3 of the following are required (per account): ⋮---- -export class WebsocketClient extends BaseWebsocketClient< +// If running from CLI in unix, you can pass env vars as such: +// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts ⋮---- -constructor(options?: WSClientConfigurableOptions, logger?: DefaultLogger) +// For private topics, include one or more accounts in an array. Otherwise only public topics will work ⋮---- -/** - * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library - */ -public connectAll(): Promise[] +// console.log('WS raw message received ', JSON.stringify(data, null, 2)); ⋮---- -public connectPublic( - businessEndpoint?: boolean, -): Promise +// prodPrivate is for the www.okx.com /ws/v5/private channel ⋮---- -public connectPrivate( - businessEndpoint?: boolean, -): Promise +// prodBusiness is for the www.okx.com /ws/v5/business channel +// const OKX_GLOBAL_BUSINESS_CHANNEL = WS_KEY_MAP.prodBusiness; ⋮---- /** - * Ensures the WS API connection is active and ready. + * OKX's WebSocket API can be used via the sendWSAPIRequest() method. * - * You do not need to call this, but if you call this before making any WS API requests, - * it can accelerate the first request (by preparing the connection in advance). + * The correct WS Key depends on where you registered (www.okx.com vs app.okx.com vs my.okx.com), and whether you are using book trading (uses private connection) or spread trading (uses business connection) functionality. + * + * Note: for a better user experience, it is recommended to use the WebsocketAPIClient. */ -public connectWSAPI(): Promise -⋮---- -/** This call automatically ensures the connection is active AND authenticated before resolving */ ⋮---- /** - * Subscribe to topics & track/persist them. They will be automatically resubscribed to if the connection drops/reconnects. - * @param wsEvents topic or list of topics - * @param isPrivateTopic optional - the library will try to detect private topics, you can use this to mark a topic as private (if the topic isn't recognised yet) + * Place Order + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order */ -public subscribe( - wsEvents: WsChannelSubUnSubRequestArg[] | WsChannelSubUnSubRequestArg, - isPrivateTopic?: boolean, -): Promise[] -⋮---- -// Format and batch topic requests by WsKey (resolved dynamically) ⋮---- -// Arrange into per-wsKey sorted lists +/** + const res = { + id: '2', + op: 'order', + code: '1', + msg: '', + data: [ + { + tag: '159881cb7207BCDE', + ts: '1753714603721', + ordId: '', + clOrdId: '', + sCode: '51008', + sMsg: 'Order failed. Insufficient USDT balance in account.' + } + ], + inTime: '1753714603720755', + outTime: '1753714603721942', + wsKey: 'prodPrivate', + isWSAPIResponse: false + } + + const res = { + id: '2', + op: 'order', + code: '1', + msg: '', + data: [ + { + tag: '159881cb7207BCDE', + ts: '1753714567149', + ordId: '', + clOrdId: '', + sCode: '51010', + sMsg: "You can't complete this request under your current account mode." + } + ], + inTime: '1753714567149196', + outTime: '1753714567149913', + wsKey: 'prodPrivate', + isWSAPIResponse: false + } + + */ ⋮---- /** - * Unsubscribe from topics & remove them from memory. They won't be re-subscribed to if the connection reconnects. - * @param wsTopics topic or list of topics - * @param isPrivateTopic optional - the library will try to detect private topics, you can use this to mark a topic as private (if the topic isn't recognised yet) + * Cancel Order + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-cancel-order */ -public unsubscribe( - wsEvents: WsChannelSubUnSubRequestArg[] | WsChannelSubUnSubRequestArg, - isPrivateTopic?: boolean, -) -⋮---- -// Format and batch topic requests by WsKey (resolved dynamically) -⋮---- -// Arrange into per-wsKey sorted lists ⋮---- /** - * - * - * Internal methods required to integrate with the BaseWSClient - * - * - */ + const res = { + id: '2', + op: 'cancel-order', + code: '1', + msg: '', + data: [ + { + ts: '1753714393003', + ordId: '2510789768709120', + clOrdId: '', + sCode: '51400', + sMsg: 'Order cancellation failed as the order has been filled, canceled or does not exist.' + } + ], + inTime: '1753714393003190', + outTime: '1753714393004074', + wsKey: 'prodPrivate', + isWSAPIResponse: false + } + */ + +================ +File: src/types/rest/request/affiliate.ts +================ +export type AffiliatePeriodType = + | 'last_7d' + | 'last_30d' + | 'this_month' + | 'last_month' + | 'total' + | 'today' + | 'this_week' + | 'custom'; ⋮---- -public getMarketWsKey(type: 'private' | 'business'): WsKey +export type AffiliateCommissionCategory = 'SPOT' | 'DERIVATIVE' | 'BSC'; ⋮---- -// returns private or business ws key for the active api market -// defaults to global -// automatically resolves to demo trading wsKeys under the hood (WSClient) +export type AffiliateKycStatus = 'unverified' | 'verified'; ⋮---- -protected sendPingEvent(wsKey: WsKey): void +export type AffiliateLinkType = 'standard' | 'co_inviter'; ⋮---- -protected sendPongEvent(wsKey: WsKey): void +export type AffiliateLinkStatus = 'normal' | 'abnormal'; ⋮---- -protected isWsPing(data: any): boolean +export type AffiliateInviteeListOrderBy = + | 'cTime' + | 'depAmt' + | 'vol' + | 'fee' + | 'rebate'; ⋮---- -protected isWsPong(data: any): boolean +export type AffiliateSubAffiliateListOrderBy = + | 'cTime' + | 'depAmt' + | 'vol' + | 'fee' + | 'rebate'; ⋮---- -protected isPrivateTopicRequest( - _request: WsTopicRequest, - wsKey: WsKey, -): boolean +export type AffiliateOrderDir = 'asc' | 'desc'; ⋮---- -protected getPrivateWSKeys(): WsKey[] +export interface GetAffiliatePerformanceSummaryRequest { + periodType?: AffiliatePeriodType; + /** Required when periodType=custom, together with end. Inclusive. */ + begin?: string; + /** Required when periodType=custom, together with begin. Inclusive. */ + end?: string; +} ⋮---- -protected isAuthOnConnectWsKey(wsKey: WsKey): boolean +/** Required when periodType=custom, together with end. Inclusive. */ ⋮---- -protected async getWsUrl(wsKey: WsKey): Promise +/** Required when periodType=custom, together with begin. Inclusive. */ ⋮---- -protected getMaxTopicsPerSubscribeEvent(): number | null +export interface GetInviteeDetailRequest { + uid: string; + /** + * Stats window for `volPeriod`: last_7d, last_30d, this_month, last_month, total, today, this_week. + * When omitted, volPeriod is not returned. + */ + periodType?: Exclude; +} ⋮---- /** - * @returns one or more correctly structured request events for performing a operations over WS. This can vary per exchange spec. + * Stats window for `volPeriod`: last_7d, last_30d, this_month, last_month, total, today, this_week. + * When omitted, volPeriod is not returned. */ -protected async getWsRequestEvents( - operation: WSOperation, - requests: WsTopicRequest[], -): Promise>[]> ⋮---- -// Previously used to track topics in a request. Keeping this for subscribe/unsubscribe requests, no need for incremental values +export interface GetAffiliateInviteeListRequest { + page?: string; + limit?: string; + periodType?: AffiliatePeriodType; + /** Required when periodType=custom, together with end. Inclusive. */ + begin?: string; + /** Required when periodType=custom, together with begin. Inclusive. */ + end?: string; + keyword?: string; + commissionCategory?: AffiliateCommissionCategory; + orderBy?: AffiliateInviteeListOrderBy; + orderDir?: AffiliateOrderDir; + kycStatus?: AffiliateKycStatus; + subAffiliateUid?: string; + /** External user UIDs for exact match. Single or up to 100 comma-separated. */ + uid?: string; + /** Filter lower bound on joinTime (Unix ms). Required with joinTimeEnd; max 90d span, not older than 180d. */ + joinTimeBegin?: string; + /** Filter upper bound on joinTime (Unix ms). Required with joinTimeBegin. */ + joinTimeEnd?: string; +} ⋮---- -/** - { - "op":"subscribe", - "args":[ - { - "channel": "tickers", - "instId": "BTC-USDT" - }, - { - "channel": "tickers", - "instId": "BTC-USDT" - } - ] - } - */ +/** Required when periodType=custom, together with end. Inclusive. */ ⋮---- -// const request = { -// topic: 'tickers', -// payload: { instId: 'BTC-USDT' }, -// }; -// becomes: -// const request = { -// channel: 'ticker', -// instId: 'BTC-USDT', -// }; +/** Required when periodType=custom, together with begin. Inclusive. */ ⋮---- -private async signMessage( - paramsStr: string, - secret: string, - method: SignEncodeMethod, - algorithm: SignAlgorithm, -): Promise +/** External user UIDs for exact match. Single or up to 100 comma-separated. */ ⋮---- -protected async getWsAuthRequestEvent( - wsKey: WsKey, - skipIsPublicWsKeyCheck: boolean, -): Promise | null> +/** Filter lower bound on joinTime (Unix ms). Required with joinTimeEnd; max 90d span, not older than 180d. */ ⋮---- -// Filter out failed accounts +/** Filter upper bound on joinTime (Unix ms). Required with joinTimeBegin. */ ⋮---- -private async getWsAuthSignature( - wsKey: WsKey, - credentials: APICredentials, -): Promise< +export interface GetAffiliateLinkListRequest { + page?: string; + limit?: string; + linkType?: AffiliateLinkType; + linkStatus?: AffiliateLinkStatus; +} ⋮---- -// const signatureExpiresAt = timestamp + 5; +export interface GetAffiliateCoInviterLinkListRequest { + page?: string; + limit?: string; + linkStatus?: AffiliateLinkStatus; +} ⋮---- -/** - * Abstraction called to sort ws events into emittable event types (response to a request, data update, etc) +export interface GetAffiliateSubAffiliateListRequest { + page?: string; + limit?: string; + keyword?: string; + commissionCategory?: AffiliateCommissionCategory; + orderBy?: AffiliateSubAffiliateListOrderBy; + orderDir?: AffiliateOrderDir; +} + +================ +File: src/types/rest/request/funding.ts +================ +export interface FundsTransferRequest { + ccy: string; + amt: string; + from: '6' | '18'; + to: '6' | '18'; + subAcct?: string; + type?: '0' | '1' | '2' | '3' | '4'; + loanTrans?: boolean; + clientId?: string; + omitPosRisk?: string; +} +⋮---- +export interface WithdrawRequest { + ccy: string; + amt: string; + dest: '3' | '4'; + toAddr: string; + /** + * Address type: + * - 1: wallet address, email, phone, or login account name + * - 2: UID (only for whitelisted users; applicable only when dest=3) */ -protected resolveEmittableEvents( - wsKey: WsKey, - event: MessageEventLike, -): EmittableEvent[] + toAddrType?: '1' | '2'; + chain?: string; + areaCode?: string; + clientId?: string; + // Recipient information for specific entity users doing on-chain/lightning withdrawal + rcvrInfo?: { + // Required: 'exchange' for exchange wallet, 'private' for private wallet + walletType: 'exchange' | 'private'; + // Exchange ID (required if walletType = 'exchange'). Use '0' if exchange not in list + exchId?: string; + // Receiver's first name (required if walletType = 'exchange') + rcvrFirstName?: string; + // Receiver's last name (required if walletType = 'exchange') + rcvrLastName?: string; + // Recipient's country - English name or ISO 3166-1 two-letter code + rcvrCountry?: string; + // State/Province of the recipient + rcvrCountrySubDivision?: string; + // Town/city where the recipient is located + rcvrTownName?: string; + // Recipient's street address + rcvrStreetName?: string; + }; +} ⋮---- /** - * WS API response handling - */ -⋮---- -// const eg1 = { -// id: '2', -// op: 'order', -// code: '1', -// msg: '', -// data: [ -// { -// tag: '159881cb7207BCDE', -// ts: '1753783406701', -// ordId: '', -// clOrdId: '', -// sCode: '51008', -// sMsg: 'Order failed. Insufficient USDT balance in account.', -// }, -// ], -// inTime: '1753783406701275', -// outTime: '1753783406702251', -// wsKey: 'prodPrivate', -// }; -⋮---- -// check getPromiseRefForWSAPIRequest -⋮---- -// WS API Success -⋮---- -// messageType: typeof msg, -// messageString: JSON.stringify(msg), -⋮---- -// Successfully authenticated -⋮---- -// this.logger.trace(`Ws subscribe reply:`, { ...msg, wsKey }); -⋮---- -// Queue immediate reconnection workflow -⋮---- -// Emit notice to client for visibility -⋮---- -// messageType: typeof msg, -// messageString: JSON.stringify(msg), -⋮---- -// fallback emit anyway -⋮---- -/** - * OKX supports order placement via WebSockets. This is the WS API: - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order - * - * For convenient promise-wrapped usage of the WS API, instance the WebsocketAPIClient class exported by this SDK. - * - * For demo trading, set demoTrading:true in the WS Client config. - * - * @returns a promise that resolves/rejects when a matching response arrives - */ -async sendWSAPIRequest< - TWSKey extends keyof WsAPIWsKeyTopicMap, - TWSOperation extends WsAPIWsKeyTopicMap[TWSKey], - TWSParams extends WsAPITopicRequestParamMap[TWSOperation], - TWSAPIResponse extends - WsAPIOperationResponseMap[TWSOperation] = WsAPIOperationResponseMap[TWSOperation], - >( - rawWsKey: WsKey, - operation: TWSOperation, - params: TWSParams & { signRequest?: boolean }, - requestFlags?: WSAPIRequestFlags, -): Promise -⋮---- -// If demo trading, enforce demo wskey for WS API calls -⋮---- -// Ensure "args" is always wrapped as array -⋮---- -// Store deferred promise, resolved within the "resolveEmittableEvents" method while parsing incoming events -⋮---- -// Enriched WS API response includes wsKey & the request that was connected to the response -type DeferredWSAPIResponse = TWSAPIResponse & { - request: WSAPIRequestOKX & { wsKey: WsKey }; - }; -⋮---- -// Enrich returned promise with request context for easier debugging -⋮---- -// throw e; -⋮---- -// Send event -⋮---- -// Return deferred promise, so caller can await this call - -================ -File: webpack/webpack.config.cjs -================ -function generateConfig(name) -⋮---- -// Add '.ts' and '.tsx' as resolvable extensions. -⋮---- -// Node.js core modules not available in browsers -// The REST client's https.Agent (for keepAlive) is Node.js-only and won't work in browsers -⋮---- -// Code is already transpiled from TypeScript, no additional loaders needed - -================ -File: .gitignore -================ -!.gitkeep -.DS_STORE -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json -pids -*.pid -*.seed -*.pid.lock -node_modules/ -.npm -.eslintcache -.node_repl_history -*.tgz -.yarn-integrity -.env -.env.test -.cache -lib -dist -bundleReport.html -.history/ -.idea -privaterepotracker -restClientRegex.ts -testfile.ts -localtest.sh -coverage/ - -repomix.sh - -================ -File: src/types/rest/request/funding.ts -================ -export interface FundsTransferRequest { - ccy: string; - amt: string; - from: '6' | '18'; - to: '6' | '18'; - subAcct?: string; - type?: '0' | '1' | '2' | '3' | '4'; - loanTrans?: boolean; - clientId?: string; - omitPosRisk?: string; -} -⋮---- -export interface WithdrawRequest { - ccy: string; - amt: string; - dest: '3' | '4'; - toAddr: string; - /** - * Address type: - * - 1: wallet address, email, phone, or login account name - * - 2: UID (only for whitelisted users; applicable only when dest=3) - */ - toAddrType?: '1' | '2'; - chain?: string; - areaCode?: string; - clientId?: string; - // Recipient information for specific entity users doing on-chain/lightning withdrawal - rcvrInfo?: { - // Required: 'exchange' for exchange wallet, 'private' for private wallet - walletType: 'exchange' | 'private'; - // Exchange ID (required if walletType = 'exchange'). Use '0' if exchange not in list - exchId?: string; - // Receiver's first name (required if walletType = 'exchange') - rcvrFirstName?: string; - // Receiver's last name (required if walletType = 'exchange') - rcvrLastName?: string; - // Recipient's country - English name or ISO 3166-1 two-letter code - rcvrCountry?: string; - // State/Province of the recipient - rcvrCountrySubDivision?: string; - // Town/city where the recipient is located - rcvrTownName?: string; - // Recipient's street address - rcvrStreetName?: string; - }; -} -⋮---- -/** - * Address type: - * - 1: wallet address, email, phone, or login account name - * - 2: UID (only for whitelisted users; applicable only when dest=3) - */ + * Address type: + * - 1: wallet address, email, phone, or login account name + * - 2: UID (only for whitelisted users; applicable only when dest=3) + */ ⋮---- // Recipient information for specific entity users doing on-chain/lightning withdrawal ⋮---- @@ -7417,1028 +6641,787 @@ before?: string; // Pagination of data to return records newer than the requeste limit?: string; // Number of results per request. Max is 100; default is 100 ================ -File: src/types/rest/request/public.ts +File: src/types/rest/response/private-affiliate.ts ================ -export interface EconomicCalendarRequest { - region?: string; - importance?: '1' | '2' | '3'; - before?: string; - after?: string; - limit?: string; -} +import type { AffiliateCommissionCategory } from '../request/affiliate.js'; ⋮---- -export interface UnitConvertRequest { - type?: '1' | '2'; - instId: string; - sz: string; - px?: string; - unit?: 'coin' | 'usds'; - opType: 'open' | 'close'; +export interface AffiliatePerformanceSummaryDetail { + commissionCategory: AffiliateCommissionCategory; + firstTraderCnt: string; + traderCnt: string; + vol: string; + commission: string; } ⋮---- -export interface CandleRequest { - instId: string; - after?: string; - before?: string; - bar?: string; - limit?: string; +export interface AffiliatePerformanceSummary { + uTime: string; + inviteeCnt: string; + depAmt: string; + details: AffiliatePerformanceSummaryDetail[]; } ⋮---- -export interface GetPremiumHistoryRequest { - instId: string; - after?: string; - before?: string; - limit?: string; +export interface InviteeDetail { + inviteeLevel: string; + joinTime: string; + inviteeRebateRate: string; + totalCommission: string; + firstTradeTime: string; + level: string; + depAmt: string; + wdAmt: string; + volMonth: string; + totalVol: string; + accFee: string; + kycTime: string; + region: string; + affiliateCode: string; + /** Trading volume in selected periodType window (USDT). Only when periodType supplied. */ + volPeriod?: string; } ⋮---- -export interface GetContractOpenInterestHistoryRequest { - instId: string; - period?: string; - end?: string; - begin?: string; - limit?: string; -} +/** Trading volume in selected periodType window (USDT). Only when periodType supplied. */ ⋮---- -export interface GetContractTakerVolumeRequest { - instId: string; - period?: string; - unit?: string; - end?: string; - begin?: string; - limit?: string; -} +export type AffiliateInviteeListKycStatus = 'unverified' | 'verified'; ⋮---- -export interface GetTopTradersContractLongShortRatioRequest { - instId: string; - period?: string; - end?: string; - begin?: string; - limit?: string; +export interface AffiliateInviteeListItem { + uid: string; + country: string; + joinTime: string; + firstTradeTime: string; + channelName: string; + rebateRate: string; + feeTierRank: string; + kycStatus: AffiliateInviteeListKycStatus; + kycTime: string; + depAmt: string; + totalVol: string; + totalFee: string; + totalCommission: string; + isCompliant: boolean; } ⋮---- -export interface GetOptionTradesRequest { - instId?: string; - instFamily?: string; - optType?: 'C' | 'P'; -} +export type AffiliateLinkListLinkType = 'standard' | 'co_inviter'; ⋮---- -/** - * @see GET /api/v5/public/market-data-history - * Module 11: borrowing rate (T+2 typical, UTC+8 for timestamp parsing). - * Max query range (2026-08-06): 10 days for daily, 10 months for monthly (was 20). - */ -export interface GetHistoricalMarketDataRequest { - /** - * 1: trades, 2: 1m candles, 3: funding rate, 4: 400-level book, 5: 5000-level, 6: 50-level (use 4/5), 11: borrowing rate - */ - module: string; - instType: 'SPOT' | 'FUTURES' | 'SWAP' | 'OPTION'; - instIdList?: string; - instFamilyList?: string; - dateAggrType: 'daily' | 'monthly'; - begin: string; - end: string; +export type AffiliateLinkListLinkStatus = 'normal' | 'abnormal'; +⋮---- +export interface AffiliateLinkListItem { + channelId: string; + channelName: string; + joinLink: string; + linkType: AffiliateLinkListLinkType; + inviterCommissionRate: string; + coInviterCommissionRate: string; + inviteeDiscountRate: string; + inviteeCnt: string; + traderCnt: string; + totalCommission: string; + commission24h: string; + cTime: string; + isDefault: boolean; + linkStatus: AffiliateLinkListLinkStatus; } ⋮---- -/** - * 1: trades, 2: 1m candles, 3: funding rate, 4: 400-level book, 5: 5000-level, 6: 50-level (use 4/5), 11: borrowing rate - */ +export type AffiliateChannelAssessmentStatus = + | 'valid' + | 'not_reach_trade' + | 'not_reach_invite' + | 'not_reach_both'; ⋮---- -/** - * @see GET /api/v5/public/event-contract/series - */ -export interface GetEventContractSeriesRequest { - seriesId?: string; -} +export type AffiliateInviterChannelStatus = + | 'valid' + | 'identity_invalid' + | 'level_downgraded'; ⋮---- -/** - * @see GET /api/v5/public/event-contract/events - */ -export interface GetEventContractEventsRequest { - seriesId: string; - eventId?: string; - state?: 'preopen' | 'live' | 'settling' | 'expired' | string; - limit?: string; - before?: string; - after?: string; -} +export type AffiliateCoInviterChannelStatus = + | 'valid' + | 'identity_invalid' + | 'not_reach_assessment' + | 'identity_invalid_and_not_reach_assessment'; ⋮---- -/** - * @see GET /api/v5/public/event-contract/markets - */ -export interface GetEventContractMarketsRequest { - seriesId: string; - eventId?: string; - instId?: string; - state?: 'preopen' | 'live' | 'settling' | 'expired' | string; - limit?: string; - before?: string; - after?: string; +export interface AffiliateCoInviterLinkListItem { + channelId: string; + channelName: string; + joinLink: string; + inviterCommissionRate: string; + coInviterCommissionRate: string; + inviteeDiscountRate: string; + parUserName: string; + coUserName: string; + isCompliant: boolean; + note?: string; + isDefault: boolean; + totalCommission: string; + commission24h: string; + inviteeCnt: string; + traderCnt: string; + clickCnt: string; + totalFee: string; + cTime: string; + channelAssessmentStatus: AffiliateChannelAssessmentStatus; + inviterChannelStatus: AffiliateInviterChannelStatus; + coInviterChannelStatus: AffiliateCoInviterChannelStatus; + linkStatus: AffiliateLinkListLinkStatus; } ⋮---- -export interface GetInsuranceFundRequest { - instType?: string; - type?: - | 'liquidation_balance_deposit' - | 'bankruptcy_loss' - | 'platform_revenue' - | 'adl'; - instFamily?: string; - ccy?: string; - before?: string; - after?: string; - limit?: string; +export interface AffiliateSubAffiliateListItem { + subAffiliateUid: string; + country: string; + joinTime: string; + subAffiliateLevel: string; + commissionRate: string; + isCompliant: boolean; + inviteeCnt: string; + traderCnt: string; + depAmt: string; + totalVol: string; + totalFee: string; + totalCommission: string; } ================ -File: src/types/rest/response/private-trade.ts +File: src/types/rest/response/private-funding.ts ================ -import { - AlgoOrderState, - AlgoOrderType, - AlgoPositionSide, - numberInString, - OrderState, - OrderType, - PositionSide, -} from '../shared.js'; +import { ASSET_BILL_TYPE } from '../../../constants/funding.js'; ⋮---- -/** - * Nested rows in `attachAlgoOrds` on orders / history (incl. trailing stop fields) - */ -export interface AttachAlgoOrderDetail { - attachAlgoClOrdId?: string; - tpTriggerPx?: string; - tpTriggerRatio?: string; - tpOrdPx?: string; - tpOrdKind?: string; - slTriggerPx?: string; - slTriggerRatio?: string; - slOrdPx?: string; - tpTriggerPxType?: string; - slTriggerPxType?: string; - sz?: string; - amendPxOnTriggerType?: string; - callbackRatio?: string; - callbackSpread?: string; - activePx?: string; +export interface FundingCurrency { + ccy: string; // Currency code (e.g., "BTC") + name: string; // Currency name + logoLink: string; // Currency logo URL + chain: string; // Chain name (e.g., "BTC-Bitcoin") + ctAddr: string; // Contract address + canDep: boolean; // Deposit availability + canWd: boolean; // Withdrawal availability + canInternal: boolean; // Internal transfer availability + depEstOpenTime: string; // Estimated deposit opening time (timestamp) + wdEstOpenTime: string; // Estimated withdrawal opening time (timestamp) + minDep: string; // Minimum deposit amount + minWd: string; // Minimum withdrawal amount + minInternal: string; // Minimum internal transfer amount + maxWd: string; // Maximum withdrawal amount per transaction + wdTickSz: string; // Withdrawal precision (decimal places) + wdQuota: string; // 24h withdrawal limit in USD + usedWdQuota: string; // Used withdrawal quota in USD + fee: string; // Fixed withdrawal fee + minFee: string; // Minimum withdrawal fee (deprecated) + maxFee: string; // Maximum withdrawal fee (deprecated) + minFeeForCtAddr: string; // Minimum contract address withdrawal fee (deprecated) + maxFeeForCtAddr: string; // Maximum contract address withdrawal fee (deprecated) + burningFeeRate: string; // Burning fee rate (e.g., "0.05" for 5%) + mainNet: boolean; // Is main network + needTag: boolean; // Requires tag/memo for withdrawal + minDepArrivalConfirm: string; // Min confirmations for deposit credit + minWdUnlockConfirm: string; // Min confirmations for withdrawal unlock + depQuotaFixed: string; // Fixed deposit limit in USD + usedDepQuotaFixed: string; // Used fixed deposit quota in USD + depQuoteDailyLayer2: string; // Layer2 daily deposit limit } ⋮---- -export interface OrderResult { - clOrdId: string; - ordId: string; - tag: string; - ts: string; - sCode: numberInString; - subCode?: string; - sMsg: string; +ccy: string; // Currency code (e.g., "BTC") +name: string; // Currency name +logoLink: string; // Currency logo URL +chain: string; // Chain name (e.g., "BTC-Bitcoin") +ctAddr: string; // Contract address +canDep: boolean; // Deposit availability +canWd: boolean; // Withdrawal availability +canInternal: boolean; // Internal transfer availability +depEstOpenTime: string; // Estimated deposit opening time (timestamp) +wdEstOpenTime: string; // Estimated withdrawal opening time (timestamp) +minDep: string; // Minimum deposit amount +minWd: string; // Minimum withdrawal amount +minInternal: string; // Minimum internal transfer amount +maxWd: string; // Maximum withdrawal amount per transaction +wdTickSz: string; // Withdrawal precision (decimal places) +wdQuota: string; // 24h withdrawal limit in USD +usedWdQuota: string; // Used withdrawal quota in USD +fee: string; // Fixed withdrawal fee +minFee: string; // Minimum withdrawal fee (deprecated) +maxFee: string; // Maximum withdrawal fee (deprecated) +minFeeForCtAddr: string; // Minimum contract address withdrawal fee (deprecated) +maxFeeForCtAddr: string; // Maximum contract address withdrawal fee (deprecated) +burningFeeRate: string; // Burning fee rate (e.g., "0.05" for 5%) +mainNet: boolean; // Is main network +needTag: boolean; // Requires tag/memo for withdrawal +minDepArrivalConfirm: string; // Min confirmations for deposit credit +minWdUnlockConfirm: string; // Min confirmations for withdrawal unlock +depQuotaFixed: string; // Fixed deposit limit in USD +usedDepQuotaFixed: string; // Used fixed deposit quota in USD +depQuoteDailyLayer2: string; // Layer2 daily deposit limit +⋮---- +export interface FundingBalance { + availBal: string; + bal: string; + ccy: string; + frozenBal: string; } ⋮---- -export interface CancelledOrderResult { - clOrdId: string; - ordId: string; - sCode: string; - subCode?: string; - sMsg: string; +export interface AccountAssetValuation { + details: { + classic: string; + earn: string; + funding: string; + trading: string; + }; + totalBal: string; + ts: string; } ⋮---- -export interface AmendedOrder { - clOrdId: string; - ordId: string; - reqId: string; - sCode: string; - subCode?: string; - sMsg: string; +export interface FundTransferResult { + transId: string; + ccy: string; + clientId: string; + from: string; + amt: string; + to: string; } -export interface ClosedPositions { - instId: string; - posSide: PositionSide; +export interface FundTransferState { + amt: string; + ccy: string; + clientId: string; + from: string; + instId: never; // deprecated + state: string; + subAcct: string; + to: string; + toInstId: never; // deprecated + transId: string; + type: string; } ⋮---- -export interface OrderDetails { - instType: string; - instId: string; +instId: never; // deprecated +⋮---- +toInstId: never; // deprecated +⋮---- +export interface AssetBillDetails { + billId: string; ccy: string; - ordId: string; - clOrdId: string; - tag: string; - px: string; - sz: string; - pnl: string; - ordType: OrderType; - side: string; - posSide: PositionSide; - tdMode: string; - accFillSz: string; - fillPx: string; - tradeId: string; - fillSz: string; - fillTime: string; - state: OrderState; - avgPx: string; - lever: string; - tpTriggerPx: string; - tpTriggerPxType: string; - tpOrdPx: string; - slTriggerPx: string; - slTriggerPxType: string; - slOrdPx: string; - attachAlgoOrds?: AttachAlgoOrderDetail[]; - feeCcy: string; - fee: string; - rebateCcy: string; - rebate: string; - tgtCcy: string; - category: string; - outcome?: string; - uTime: string; - cTime: string; + clientId: string; + balChg: string; + bal: string; + type: `${ASSET_BILL_TYPE}`; + notes: string; + ts: string; } ⋮---- -export interface OrderListItem { - accFillSz: string; - avgPx: string; - cTime: string; - category: string; +export interface WithdrawResponse { ccy: string; - clOrdId: string; - fee: string; - feeCcy: string; - fillPx: string; - fillSz: string; - fillTime: string; - instId: string; - instType: string; - lever: string; - ordId: string; - ordType: OrderType; - pnl: string; - posSide: PositionSide; - px: string; - pxUsd: string; - pxVol: string; - pxType: string; - rebate: string; - rebateCcy: string; - side: string; - attachAlgoClOrdId: string; - slOrdPx: string; - slTriggerPx: string; - slTriggerPxType: string; - state: OrderState; - stpId: string; - stpMode: string; - sz: string; - tag: string; - tgtCcy: string; - tdMode: string; - source: string; - tpOrdPx: string; - tpTriggerPx: string; - tpTriggerPxType: string; - tradeId: string; - reduceOnly: string; - quickMgnType: string; - algoClOrdId: string; - algoId: string; - uTime: string; - attachAlgoOrds?: AttachAlgoOrderDetail[]; - outcome?: string; + chain: string; + amt: string; + wdId: string; + clientId: string; } ⋮---- -export interface HistoricOrder { - instType: string; - instId: string; +export interface NonTradableAsset { ccy: string; - ordId: string; - clOrdId: string; - tag: string; - px: string; - pxUsd: string; - pxVol: string; - pxType: string; - sz: string; - ordType: OrderType; - side: string; - posSide: PositionSide; - tdMode: string; - accFillSz: string; - fillPx: string; - tradeId: string; - fillSz: string; - fillTime: string; - state: OrderState; - avgPx: string; - lever: string; - attachAlgoClOrdId: string; - tpTriggerPx: string; - tpTriggerPxType: string; - tpOrdPx: string; - slTriggerPx: string; - slTriggerPxType: string; - slOrdPx: string; - attachAlgoOrds?: AttachAlgoOrderDetail[]; - stpId: string; - stpMode: string; - feeCcy: string; + name: string; + logoLink: string; + bal: string; + canWd: boolean; + chain: string; + minWd: string; + wdAll: boolean; fee: string; - rebateCcy: string; - source: string; - rebate: string; - tgtCcy: string; - pnl: string; - category: string; - reduceOnly: string; - cancelSource: string; - cancelSourceReason: string; - algoClOrdId: string; - algoId: string; - outcome?: string; - uTime: string; - cTime: string; -} -⋮---- -export interface OrderFill { - instType: string; - instId: string; - tradeId: string; - ordId: string; - clOrdId: string; - billId: string; - tag: string; - fillPx: string; - fillSz: string; - side: string; - posSide: PositionSide; - execType: string; + ctAddr: string; + wdTickSz: string; + needTag: boolean; + burningFeeRate: string; feeCcy: string; - fee: string; - ts: string; -} -⋮---- -export interface AlgoOrderResult { - algoId: string; - algoClOrdId: string; - sCode: string; - sMsg: string; } ⋮---- -export interface AmendAlgoOrderResult extends AlgoOrderResult { - reqId: string; +export interface DepositHistory { + ccy: string; // Currency, e.g. BTC + chain: string; // Chain name + amt: string; // Deposit amount + from: string; // Deposit account. If the deposit comes from internal transfer, displays account info (phone/email, masked). Returns "" otherwise. + areaCodeFrom: string; // If from is a phone number, this parameter returns area code of the phone number + to: string; // Deposit address. If the deposit comes from on-chain, displays the on-chain address. Returns "" otherwise. + txId: string; // Hash record of the deposit + ts: string; // Timestamp that the deposit record is created, Unix timestamp format in milliseconds, e.g. 1655251200000 + state: string; // Status of deposit: 0=waiting for confirmation, 1=deposit credited, 2=deposit successful, 8=pending due to temp suspension, 11=match blacklist, 12=account/deposit frozen, 13=sub-account deposit interception, 14=KYC limit + depId: string; // Deposit ID + fromWdId: string; // Internal transfer initiator's withdrawal ID. If deposit comes from internal transfer, displays the withdrawal ID, returns "" otherwise + actualDepBlkConfirm: string; // The actual amount of blockchain confirmed in a single deposit } ⋮---- -export interface AlgoOrderDetailsResult { - instType: string; - instId: string; - ordId: string; - ordIdList: string[]; - ccy: string; - clOrdId: string; - algoId: string; - attachAlgoOrds?: AttachAlgoOrderDetail[]; - sz: string; - closeFraction: string; - ordType: AlgoOrderType; - side: string; - posSide: AlgoPositionSide; - tdMode: string; - tgtCcy: string; - state: AlgoOrderState; - lever: string; - tpTriggerPx: string; - tpTriggerPxType: string; - tpOrdPx: string; - slTriggerPx: string; - slTriggerPxType: string; - slOrdPx: string; - triggerPx: string; - triggerPxType: string; - ordPx: string; - actualSz: string; - actualPx: string; - actualSide: string; - pxVar: string; - pxSpread: string; - pxLimit: string; - szLimit: string; - tag: string; - timeInterval: string; - callbackRatio: string; - callbackSpread: string; - activePx: string; - moveTriggerPx: string; - reduceOnly: string; - triggerTime: string; - quickMgnType: string; - last: string; - failCode: string; - algoClOrdId: string; - amendPxOnTriggerType: string; - cTime: string; - isTradeBorrowMode: boolean; - chaseType?: string; - chaseVal?: string; - maxChaseType?: string; - maxChaseVal?: string; - /** Sub-order type for trigger orders: fok, ioc, chase, or empty. */ - advanceOrdType?: string; - /** Chase params when advanceOrdType is chase. */ - advChaseParams?: { - chaseType?: string; - chaseVal?: string; - maxChaseType?: string; - maxChaseVal?: string; - }[]; - /** algoId(s) of algo order(s) spawned when trigger fires (chase). Empty before trigger. */ - subAlgoIdList?: string[]; +ccy: string; // Currency, e.g. BTC +chain: string; // Chain name +amt: string; // Deposit amount +from: string; // Deposit account. If the deposit comes from internal transfer, displays account info (phone/email, masked). Returns "" otherwise. +areaCodeFrom: string; // If from is a phone number, this parameter returns area code of the phone number +to: string; // Deposit address. If the deposit comes from on-chain, displays the on-chain address. Returns "" otherwise. +txId: string; // Hash record of the deposit +ts: string; // Timestamp that the deposit record is created, Unix timestamp format in milliseconds, e.g. 1655251200000 +state: string; // Status of deposit: 0=waiting for confirmation, 1=deposit credited, 2=deposit successful, 8=pending due to temp suspension, 11=match blacklist, 12=account/deposit frozen, 13=sub-account deposit interception, 14=KYC limit +depId: string; // Deposit ID +fromWdId: string; // Internal transfer initiator's withdrawal ID. If deposit comes from internal transfer, displays the withdrawal ID, returns "" otherwise +actualDepBlkConfirm: string; // The actual amount of blockchain confirmed in a single deposit + +================ +File: src/types/rest/client.ts +================ +import { APIMarket } from '../shared.js'; +⋮---- +export interface RestClientOptions { + apiKey?: string; + apiSecret?: string; + apiPass?: string; + + /** + * The API group this client should connect to: + * - market: 'prod' (default: connects to OKX global) https://www.okx.com/docs-v5/en/#overview-production-trading-services + * - market: 'OPENAPI_GLOBAL' // OKX Global REST at https://openapi.okx.com + * - market: 'EEA' // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services + * - market: 'US' // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services + */ + market?: APIMarket; + + /** + * Set to `true` to use OKX's demo trading functionality + */ + demoTrading?: boolean; + + // Default: false. If true, we'll throw errors if any params are undefined + strict_param_validation?: boolean; + + // Optionally override REST API base URL (e.g. 'https://www.okx.com' or 'https://openapi.okx.com'). + // Note: to use my.okx or app.okx or eea.okx or us.okx, use the "market" parameter + // e.g 'https://eea.okx.com' + baseUrl?: string; + + // Default: true. whether to try and post-process request exceptions. + parse_exceptions?: boolean; + + /** + * Enable keep alive for REST API requests (via axios). + */ + keepAlive?: boolean; + + /** + * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. + * Only relevant if keepAlive is set to true. + * Default: 1000 (defaults comes from https agent) + */ + keepAliveMsecs?: number; + + /** + * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * + * Look in the examples folder for a demonstration on using node's createHmac instead. + */ + customSignMessageFn?: (message: string, secret: string) => Promise; } ⋮---- -/** Sub-order type for trigger orders: fok, ioc, chase, or empty. */ +/** + * The API group this client should connect to: + * - market: 'prod' (default: connects to OKX global) https://www.okx.com/docs-v5/en/#overview-production-trading-services + * - market: 'OPENAPI_GLOBAL' // OKX Global REST at https://openapi.okx.com + * - market: 'EEA' // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services + * - market: 'US' // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services + */ ⋮---- -/** Chase params when advanceOrdType is chase. */ +/** + * Set to `true` to use OKX's demo trading functionality + */ ⋮---- -/** algoId(s) of algo order(s) spawned when trigger fires (chase). Empty before trigger. */ +// Default: false. If true, we'll throw errors if any params are undefined ⋮---- -export interface AlgoOrderListItem { - activePx: string; - actualPx: string; - actualSide: string; - actualSz: string; - algoId: string; - attachAlgoOrds?: AttachAlgoOrderDetail[]; - cTime: string; - callbackRatio: string; - callbackSpread: string; - ccy: string; +// Optionally override REST API base URL (e.g. 'https://www.okx.com' or 'https://openapi.okx.com'). +// Note: to use my.okx or app.okx or eea.okx or us.okx, use the "market" parameter +// e.g 'https://eea.okx.com' +⋮---- +// Default: true. whether to try and post-process request exceptions. +⋮---- +/** + * Enable keep alive for REST API requests (via axios). + */ +⋮---- +/** + * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. + * Only relevant if keepAlive is set to true. + * Default: 1000 (defaults comes from https agent) + */ +⋮---- +/** + * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * + * Look in the examples folder for a demonstration on using node's createHmac instead. + */ + +================ +File: src/types/websockets/ws-api-response.ts +================ +import { numberInString } from '../rest/shared.js'; +⋮---- +export interface WSAPICancelOrderResultV5 { + clOrdId: string; + ordId: string; + ts: numberInString; + sCode: string; + subCode?: string; + sMsg: string; +} +⋮---- +export interface WSAPISpreadPlaceOrderResultV5 { clOrdId: string; - instId: string; - instType: string; - lever: string; - moveTriggerPx: string; ordId: string; - ordIdList: string[]; - ordPx: string; - ordType: AlgoOrderType; - posSide: AlgoPositionSide; - pxLimit: string; - pxSpread: string; - pxVar: string; - side: string; - slOrdPx: string; - slTriggerPx: string; - slTriggerPxType: string; - state: AlgoOrderState; - sz: string; - closeFraction: string; - szLimit: string; tag: string; - tdMode: string; - tgtCcy: string; - timeInterval: string; - tpOrdPx: string; - tpTriggerPx: string; - tpTriggerPxType: string; - triggerPx: string; - reduceOnly: string; - triggerPxType: string; - quickMgnType: string; - last: string; - failCode: string; - algoClOrdId: string; - triggerTime: string; - amendPxOnTriggerType: string; - isTradeBorrowMode: boolean; - chaseType?: string; - chaseVal?: string; - maxChaseType?: string; - maxChaseVal?: string; - advanceOrdType?: string; - advChaseParams?: { - chaseType?: string; - chaseVal?: string; - maxChaseType?: string; - maxChaseVal?: string; - }[]; - subAlgoIdList?: string[]; + sCode: numberInString; + subCode?: string; + sMsg: string; } ⋮---- -export interface HistoricAlgoOrder { - activePx: string; - actualPx: string; - actualSide: string; - actualSz: string; - algoClOrdId: string; - algoId: string; - attachAlgoOrds?: AttachAlgoOrderDetail[]; - cTime: string; - callbackRatio: string; - callbackSpread: string; - ccy: string; +export interface WSAPISpreadAmendOrderResultV5 { clOrdId: string; - closeFraction: string; - failCode: string; - instId: string; - instType: string; - last: string; - lever: string; - moveTriggerPx: string; ordId: string; - ordIdList: string[]; - ordPx: string; - ordType: AlgoOrderType; - posSide: AlgoPositionSide; - pxLimit: string; - pxSpread: string; - pxVar: string; - quickMgnType: string; - reduceOnly: string; - side: string; - slOrdPx: string; - slTriggerPx: string; - slTriggerPxType: string; - state: AlgoOrderState; - sz: string; - szLimit: string; - tag: string; - tdMode: string; - tgtCcy: string; - timeInterval: string; - tpOrdPx: string; - tpTriggerPx: string; - tpTriggerPxType: string; - triggerPx: string; - triggerPxType: string; - triggerTime: string; - amendPxOnTriggerType: string; - isTradeBorrowMode: boolean; - chaseType?: string; - chaseVal?: string; - maxChaseType?: string; - maxChaseVal?: string; - advanceOrdType?: string; - advChaseParams?: { - chaseType?: string; - chaseVal?: string; - maxChaseType?: string; - maxChaseVal?: string; - }[]; - subAlgoIdList?: string[]; + reqId: string; + sCode: string; + subCode?: string; + sMsg: string; } ⋮---- -export interface CancelAllAfterResponse { - triggerTime: string; - tag: string; +export interface WSAPISpreadCancelOrderResultV5 { + clOrdId: string; + ordId: string; + sCode: string; + subCode?: string; + sMsg: string; +} +⋮---- +/** + * @see Ws public channel: estimated-price + */ +export type WsEstimatedPriceSettleType = 'settlement' | 'delivery' | 'exercise'; +⋮---- +export interface WsEstimatedPriceData { + instId: string; + instType: string; + settlePx: string; + settleType: WsEstimatedPriceSettleType; ts: string; } ================ -File: src/types/rest/shared.ts +File: src/types/websockets/ws-events.ts ================ -export type numberInString = T; +import { WsChannel } from './ws-request.js'; ⋮---- -export interface APIResponse { - code: '0'; - msg: ''; - data: T; +export interface MessageEventLike { + target: WebSocket; + type: 'message'; + data: string; } ⋮---- -export type AlgoOrderType = - | 'conditional' - | 'oco' - | 'trigger' - | 'move_order_stop' - | 'iceberg' - | 'twap' - | 'chase'; -⋮---- -export type AlgoOrderState = - | 'live' - | 'pause' - | 'partially_effective' - | 'effective' - | 'canceled' - | 'order_failed' - | 'partially_failed'; -⋮---- -export type AlgoPositionSide = 'long' | 'short'; -⋮---- -export type ContractGridDirection = 'long' | 'short' | 'neutral'; -⋮---- -export type GridAlgoSubOrderType = 'live' | 'filled'; -⋮---- -export type InstrumentType = - | 'SPOT' - | 'MARGIN' - | 'SWAP' - | 'FUTURES' - | 'OPTION' - | 'EVENTS'; -⋮---- -export type MarginMode = 'cross' | 'isolated'; -⋮---- -export type OrderSide = 'buy' | 'sell'; -⋮---- -export type OrderType = - | 'market' - | 'limit' - | 'post_only' - | 'fok' - | 'ioc' - | 'optimal_limit_ioc' - | 'mmp' - | 'mmp_and_post_only' - | 'elp' - /** RPI maker (replaces `elp`; ELP alias accepted until 2026-10-31) */ - | 'rpi'; -⋮---- -/** RPI maker (replaces `elp`; ELP alias accepted until 2026-10-31) */ -⋮---- -export type OrderState = - | 'canceled' - | 'live' - | 'partially_filled' - | 'filled' - | 'mmp_canceled'; -⋮---- -export type PositionSide = 'net' | 'long' | 'short'; -⋮---- -export type PriceTriggerType = 'last' | 'index' | 'mark'; +export function isMessageEvent(msg: unknown): msg is MessageEventLike ⋮---- -export interface RFQLeg { - instId: string; - sz: string; - side: OrderSide; - tgtCcy?: string; +export interface WsEvent { + event: + | 'error' + | 'login' + | 'subscribe' + | 'unsubscribe' + | 'channel-conn-count' + | 'notice'; + code?: string; + msg?: string; + connId?: string; + arg?: any; + data?: any; } ⋮---- -export interface RFQQuoteLegExtended { - px: string; - sz: string; - instId: string; - side: string; - fee: string; - feeCcy: string; - tradeId: string; +export interface WsDataEvent { + arg: { + channel: WsChannel; + uid?: string; + instId?: string; + instFamily?: string; + instType?: string; + }; + data: T; } ⋮---- -export type TradeMode = 'cross' | 'isolated' | 'cash' | 'spot_isolated'; -⋮---- -export interface TimestampObject { - ts: numberInString; +export interface WsLoginEvent extends WsEvent { + event: 'login'; } ⋮---- -export interface Pagination { - after?: string; - before?: string; - limit?: string; +export interface WsChannelConnInfoEvent extends WsEvent { + event: 'channel-conn-count'; + channel: string; + connId: string; + connCount: string; } ⋮---- -export type PosMode = 'long_short_mode' | 'net_mode'; -⋮---- -export type AccountLevel = '1' | '2' | '3' | '4'; -⋮---- -export type WithdrawState = - | '-3' - | '-2' - | '-1' - | '0' - | '1' - | '2' - | '4' - | '5' - | '6' - | '8' - | '9' - | '10' - | '12'; +export type WsResponse = WsEvent; ================ -File: src/types/websockets/ws-request.ts +File: src/types/shared.ts ================ -import type { InstrumentType } from '../rest/shared.js'; -⋮---- -export interface WsAuthRequestArg { +export interface APICredentials { apiKey: string; - passphrase: string; - timestamp: string; - sign: string; + apiSecret: string; + apiPass: string; } ⋮---- -export type WsTradeOp = - | 'order' - | 'batch-orders' - | 'cancel-order' - | 'batch-cancel-orders' - | 'amend-order' - | 'batch-amend-order'; +/** + * The API Market represents the OKX Domain that you have signed up for. At this time, there are 4 supported domain groups: + * + * - GLOBAL, otherwise known as "www.okx.com". + * - OPENAPI_GLOBAL, OKX Global REST at openapi.okx.com (same WS as GLOBAL). + * - EEA, otherwise known as "my.okx.com". + * - US, otherwise known as "app.okx.com". + */ +export type APIMarket = + | 'prod' // same as GLOBAL. Kept for some backwards compatibility + // also known as "www.okx.com" or OKX Global: https://www.okx.com/docs-v5/en/#overview-production-trading-services + | 'GLOBAL' + // OKX Global REST at https://openapi.okx.com. WebSocket URLs unchanged (same as GLOBAL). + | 'OPENAPI_GLOBAL' + // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services + | 'EEA' + // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services + | 'US'; ⋮---- -export type WsPrivateChannel = - | 'account' - | 'positions' - | 'balance_and_position' - | 'orders' - | 'orders-algo' - | 'algo-advance' - | 'liquidation-warning' - | 'adl-warning' - | 'account-greeks' - | 'grid-orders-spot' - | 'grid-orders-contract' - | 'grid-orders-moon' - | 'grid-positions' - | 'grid-sub-orders'; +| 'prod' // same as GLOBAL. Kept for some backwards compatibility +// also known as "www.okx.com" or OKX Global: https://www.okx.com/docs-v5/en/#overview-production-trading-services ⋮---- -export type WsPublicKlineChannel = - | 'candle1Y' - | 'candle6M' - | 'candle3M' - | 'candle1M' - | 'candle1W' - | 'candle1D' - | 'candle2D' - | 'candle3D' - | 'candle5D' - | 'candle12H' - | 'candle6H' - | 'candle4H' - | 'candle2H' - | 'candle1H' - | 'candle30m' - | 'candle15m' - | 'candle5m' - | 'candle3m' - | 'candle1m' - | 'candle1s' - | 'candle1Yutc' - | 'candle3Mutc' - | 'candle1Mutc' - | 'candle1Wutc' - | 'candle1Dutc' - | 'candle2Dutc' - | 'candle3Dutc' - | 'candle5Dutc' - | 'candle12Hutc' - | 'candle6Hutc'; -⋮---- -export type WsPublicMarkPriceKlineChannel = - | 'mark-price-candle1Y' - | 'mark-price-candle6M' - | 'mark-price-candle3M' - | 'mark-price-candle1M' - | 'mark-price-candle1W' - | 'mark-price-candle1D' - | 'mark-price-candle2D' - | 'mark-price-candle3D' - | 'mark-price-candle5D' - | 'mark-price-candle12H' - | 'mark-price-candle6H' - | 'mark-price-candle4H' - | 'mark-price-candle2H' - | 'mark-price-candle1H' - | 'mark-price-candle30m' - | 'mark-price-candle15m' - | 'mark-price-candle5m' - | 'mark-price-candle3m' - | 'mark-price-candle1m' - | 'mark-price-candle1Yutc' - | 'mark-price-candle3Mutc' - | 'mark-price-candle1Mutc' - | 'mark-price-candle1Wutc' - | 'mark-price-candle1Dutc' - | 'mark-price-candle2Dutc' - | 'mark-price-candle3Dutc' - | 'mark-price-candle5Dutc' - | 'mark-price-candle12Hutc' - | 'mark-price-candle6Hutc'; -⋮---- -export type WsPublicIndexKlineChannel = - | 'index-candle1Y' - | 'index-candle6M' - | 'index-candle3M' - | 'index-candle1M' - | 'index-candle1W' - | 'index-candle1D' - | 'index-candle2D' - | 'index-candle3D' - | 'index-candle5D' - | 'index-candle12H' - | 'index-candle6H' - | 'index-candle4H index -candle2H' - | 'index-candle1H' - | 'index-candle30m' - | 'index-candle15m' - | 'index-candle5m' - | 'index-candle3m' - | 'index-candle1m' - | 'index-candle1Yutc' - | 'index-candle3Mutc' - | 'index-candle1Mutc' - | 'index-candle1Wutc' - | 'index-candle1Dutc' - | 'index-candle2Dutc' - | 'index-candle3Dutc' - | 'index-candle5Dutc' - | 'index-candle12Hutc' - | 'index-candle6Hutc'; -⋮---- -export type WsPublicOrderBooksChannel = - | 'books' - | 'books5' - | 'bbo-tbt' - | 'books-l2-tbt' - | 'books50-l2-tpt' - /** @deprecated Use `books-rpi`. ELP-only book; retired after 2026-10-31. */ - | 'books-elp' - /** Consolidated organic + RPI depth (replaces books-elp). */ - | 'books-rpi'; -⋮---- -/** @deprecated Use `books-rpi`. ELP-only book; retired after 2026-10-31. */ -⋮---- -/** Consolidated organic + RPI depth (replaces books-elp). */ -⋮---- -export type WsPublicChannel = - | 'instruments' - | 'tickers' - | 'open-interest' - | WsPublicKlineChannel - | WsPublicMarkPriceKlineChannel - | WsPublicIndexKlineChannel - | 'trades' - | 'estimated-price' - | 'mark-price' - | 'price-limit' - | WsPublicOrderBooksChannel - | 'opt-summary' - | 'funding-rate' - | 'index-tickers' - | 'status' - | 'liquidation-orders' - | 'event-contract-markets'; -⋮---- -export type WsBusinessPrivateChannel = - | 'orders-algo' - | 'algo-advance' - | 'deposit-info' - | 'withdrawal-info' - | 'grid-orders-spot' - | 'grid-orders-contract' - | 'grid-orders-moon' - | 'grid-positions' - | 'grid-sub-orders' - | 'algo-recurring-buy'; -⋮---- -export type WsBusinessPublicChannel = - | WsPublicKlineChannel - | WsPublicMarkPriceKlineChannel - | WsPublicIndexKlineChannel; +// OKX Global REST at https://openapi.okx.com. WebSocket URLs unchanged (same as GLOBAL). ⋮---- -export type WsBusinessChannel = - | WsBusinessPrivateChannel - | WsBusinessPublicChannel; +// also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services ⋮---- -export type WsChannel = WsPublicChannel | WsPrivateChannel | WsBusinessChannel; +// also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services + +================ +File: src/websocket-api-client.ts +================ +import { OrderIdRequest } from './types/rest/request/trade.js'; +import { OrderResult } from './types/rest/response/private-trade.js'; +import { WSAPIResponse } from './types/websockets/ws-api.js'; +import { + WSAPIAmendOrderRequestV5, + WSAPIAmendSpreadOrderRequestV5, + WSAPICancelSpreadOrderRequestV5, + WSAPIMassCancelOrdersRequestV5, + WSAPIPlaceOrderRequestV5, + WSAPIPlaceSpreadOrderRequestV5, + WSAPISpreadMassCancelOrdersRequestV5, +} from './types/websockets/ws-api-request.js'; +import { + WSAPICancelOrderResultV5, + WSAPISpreadAmendOrderResultV5, + WSAPISpreadCancelOrderResultV5, + WSAPISpreadPlaceOrderResultV5, +} from './types/websockets/ws-api-response.js'; +import { WSClientConfigurableOptions } from './types/websockets/ws-general.js'; +import { DefaultLogger } from './util/logger.js'; +import { WebsocketClient } from './websocket-client.js'; ⋮---- -/** Used to trigger order actions over websockets (e.g. placing & cancelling orders) */ -export interface WsTradeBaseRequest { - op: WsTradeOp; - id: string; - args: any[]; +/** + * Configurable options specific to only the REST-like WebsocketAPIClient + */ +export interface WSAPIClientConfigurableOptions { + /** + * Default: true + * + * Attach default event listeners, which will console log any high level + * events (opened/reconnecting/reconnected/etc). + * + * If you disable this, you should set your own event listeners + * on the embedded WS Client `wsApiClient.getWSClient().on(....)`. + */ + attachEventListeners: boolean; } ⋮---- -export interface WsBaseRequestArg { - channel: WsChannel; -} +/** + * Default: true + * + * Attach default event listeners, which will console log any high level + * events (opened/reconnecting/reconnected/etc). + * + * If you disable this, you should set your own event listeners + * on the embedded WS Client `wsApiClient.getWSClient().on(....)`. + */ ⋮---- /** + * This is a minimal Websocket API wrapper around the WebsocketClient. It allows you to use the WebSocket API in a promise-driven way, send a request and await the response. * - * Args to be sent with top level requests + * Note: You can also directly use the sendWSAPIRequest() method to make WS API calls, but some + * may find the below methods slightly more intuitive. * + * Refer to the WS API promises example for a more detailed example on using sendWSAPIRequest() directly: + * https://github.com/tiagosiebler/okx-api/blob/master/examples/ws-api-trade-raw.ts */ +export class WebsocketAPIClient ⋮---- -export interface WsPrivateChannelArgTickers extends WsBaseRequestArg { - channel: 'tickers'; - instId: string; -} -⋮---- -export interface WsPrivateChannelArgWithCcy extends WsBaseRequestArg { - channel: 'account' | 'account-greeks' | 'withdrawal-info'; - ccy?: string; -} -⋮---- -/** `ANY` is used by some private subscription args; instruments channel uses `EVENTS` for event contracts. */ -export type WsChannelArgInstType = InstrumentType | 'ANY'; +constructor( + options?: WSClientConfigurableOptions & + Partial, + logger?: DefaultLogger, +) ⋮---- -export interface WsPrivateChannelArgWithInstFamily extends WsBaseRequestArg { - channel: 'positions' | 'orders' | 'orders-algo' | 'liquidation-warning'; - instType: WsChannelArgInstType; - instFamily?: string; - instId?: string; -} +public getWSClient(): WebsocketClient ⋮---- -export interface WsPrivateChannelArgAlgo extends WsBaseRequestArg { - channel: 'algo-advance'; - instType: WsChannelArgInstType; - instId?: string; - algoId?: string; -} +public setTimeOffsetMs(newOffset: number): void ⋮---- -export interface WsPrivateChannelArgBalanceAndPosition - extends WsBaseRequestArg { - channel: 'balance_and_position'; -} +/** + * + * + * OKX WebSocket API Methods + * + * + */ ⋮---- -export interface WsPrivateChannelArgGridOrders extends WsBaseRequestArg { - channel: 'grid-orders-spot' | 'grid-orders-contract' | 'grid-orders-moon'; - instType: 'SPOT' | 'ANY'; - instId?: string; - algoId?: string; -} +/** + * Submit a new order + * + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order + */ +submitNewOrder( + params: WSAPIPlaceOrderRequestV5, +): Promise> ⋮---- -export interface WsPrivateChannelArgGridOther extends WsBaseRequestArg { - channel: 'grid-positions' | 'grid-sub-orders'; - algoId: string; -} +/** + * Submit multiple orders in a batch + * + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-multiple-orders + */ +submitMultipleOrders( + params: WSAPIPlaceOrderRequestV5[], +): Promise> ⋮---- -export interface WsPublicChannelArgInstType extends WsBaseRequestArg { - channel: 'instruments'; - instType: WsChannelArgInstType; -} +/** + * Cancel a single order + * + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-cancel-order + */ +cancelOrder( + params: OrderIdRequest, +): Promise> ⋮---- -export interface WsPublicChannelArgInstId extends WsBaseRequestArg { - channel: - | 'tickers' - | 'open-interest' - | WsPublicKlineChannel - | WsPublicMarkPriceKlineChannel - | WsPublicIndexKlineChannel - | 'trades' - | 'mark-price' - | 'price-limit' - | WsPublicOrderBooksChannel - | 'funding-rate' - | 'index-tickers'; - instId: string; -} +/** + * Cancel multiple orders + * + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-cancel-multiple-orders + */ +cancelMultipleOrders( + params: OrderIdRequest[], +): Promise> ⋮---- -export type WsPublicChannelArgInstIdOrFamily = { - channel: 'estimated-price'; - instType: 'OPTION' | 'FUTURES' | 'SWAP' | 'EVENTS'; -} & ( - | { - instId: string; - } - | { - instFamily: string; - } -); +/** + * Amend a single order + * + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-amend-order + */ +amendOrder( + params: WSAPIAmendOrderRequestV5, +): Promise> ⋮---- -export interface WsPublicChannelArgOptionSummary extends WsBaseRequestArg { - channel: 'opt-summary'; - instFamily: string; -} +/** + * Amend multiple orders + * + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-amend-multiple-orders + */ +amendMultipleOrders( + params: WSAPIAmendOrderRequestV5[], +): Promise> ⋮---- -export interface WsPublicChannelArgStatus extends WsBaseRequestArg { - channel: 'status'; -} +/** + * Mass cancel orders + * + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-mass-cancel-order + */ +massCancelOrders( + params: WSAPIMassCancelOrdersRequestV5, +): Promise> ⋮---- -/** Event contract market status & floor strikes. @see public WS `event-contract-markets` */ -export interface WsPublicChannelArgEventContractMarkets - extends WsBaseRequestArg { - channel: 'event-contract-markets'; - instType: 'EVENTS'; -} +/** + * Amend a spread order + * + * https://www.okx.com/docs-v5/en/#spread-trading-websocket-trade-api-ws-amend-order + */ +amendSpreadOrder( + params: WSAPIAmendSpreadOrderRequestV5, + ): Promise< + WSAPIResponse<[WSAPISpreadAmendOrderResultV5], 'sprd-amend-order'> + > { + return this.wsClient.sendWSAPIRequest( + this.getWSClient().getMarketWsKey('business'), + 'sprd-amend-order', + params, + ); ⋮---- -export type WsChannelSubUnSubRequestArg = - | WsPrivateChannelArgTickers - | WsPrivateChannelArgWithCcy - | WsPrivateChannelArgWithInstFamily - | WsPrivateChannelArgAlgo - | WsPrivateChannelArgBalanceAndPosition - | WsPrivateChannelArgGridOrders - | WsPrivateChannelArgGridOther - | WsPublicChannelArgInstType - | WsPublicChannelArgInstId - | WsPublicChannelArgInstIdOrFamily - | WsPublicChannelArgOptionSummary - | WsPublicChannelArgStatus - | WsPublicChannelArgLiquidationOrders - | WsPublicChannelArgEventContractMarkets; +/** + * Cancel a spread order + * + * https://www.okx.com/docs-v5/en/#spread-trading-websocket-trade-api-ws-cancel-order + */ +cancelSpreadOrder( + params: WSAPICancelSpreadOrderRequestV5, + ): Promise< + WSAPIResponse<[WSAPISpreadCancelOrderResultV5], 'sprd-cancel-order'> + > { + return this.wsClient.sendWSAPIRequest( + this.getWSClient().getMarketWsKey('business'), + 'sprd-cancel-order', + params, + ); +⋮---- +/** + * Mass cancel spread orders + * + * https://www.okx.com/docs-v5/en/#spread-trading-websocket-trade-api-ws-cancel-all-orders + */ +massCancelSpreadOrders( + params: WSAPISpreadMassCancelOrdersRequestV5, +): Promise, 'agent'> - | Omit, 'agent'> - ); - wsUrl?: string; - - /** - * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method - * - * Look in the examples folder for a demonstration on using node's createHmac instead. - */ - customSignMessageFn?: (message: string, secret: string) => Promise; +export interface OrderResult { + clOrdId: string; + ordId: string; + tag: string; + ts: string; + sCode: numberInString; + subCode?: string; + sMsg: string; } ⋮---- -/** - * The API group this client should connect to: - * - market: 'prod' (default: connects to OKX global) https://www.okx.com/docs-v5/en/#overview-production-trading-services - * - market: 'OPENAPI_GLOBAL' // OKX Global REST at https://openapi.okx.com (WS same as GLOBAL) - * - market: 'EEA' // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services - * - market: 'US' // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services - */ -⋮---- -/** - * Set to `true` to use OKX's demo trading functionality - */ -⋮---- -// Disable ping/pong ws heartbeat mechanism (not recommended). -// Not supported for OKX -⋮---- -/** How often to check if the connection is alive */ -⋮---- -/** How long to wait for a pong (heartbeat reply) before assuming the connection is dead */ -⋮---- -/** Delay in milliseconds before respawning the connection */ -⋮---- -/** - * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method - * - * Look in the examples folder for a demonstration on using node's createHmac instead. - */ -⋮---- -export interface WebsocketClientOptions extends WSClientConfigurableOptions { - market: APIMarket; - pongTimeout: number; - pingInterval: number; - reconnectTimeout: number; - authPrivateConnectionsOnConnect: boolean; - authPrivateRequests: boolean; - - /** - * Whether to use native WebSocket ping/pong frames for heartbeats - */ - useNativeHeartbeats: boolean; +export interface CancelledOrderResult { + clOrdId: string; + ordId: string; + sCode: string; + subCode?: string; + sMsg: string; } ⋮---- -/** - * Whether to use native WebSocket ping/pong frames for heartbeats - */ -⋮---- -export type WsEventInternalSrc = 'event' | 'function'; - -================ -File: src/types/rest/request/trade.ts -================ -import { - AlgoOrderState, - AlgoOrderType, - AlgoPositionSide, - InstrumentType, - MarginMode, - numberInString, - OrderSide, - OrderType, - PositionSide, - PriceTriggerType, - TradeMode, -} from '../shared.js'; -⋮---- -export interface AlgoRecentHistoryRequest { - ordType: AlgoOrderType; - algoId?: string; - instType?: InstrumentType; - instId?: string; - after?: string; - before?: string; - limit?: string; +export interface AmendedOrder { + clOrdId: string; + ordId: string; + reqId: string; + sCode: string; + subCode?: string; + sMsg: string; } -⋮---- -export interface AlgoLongHistoryRequest { - ordType: AlgoOrderType; - state?: AlgoOrderState; - algoId?: string; - instType?: InstrumentType; - instId?: string; - after?: string; - before?: string; - limit?: string; +export interface ClosedPositions { + instId: string; + posSide: PositionSide; } ⋮---- -/** - * When amending an attached trailing stop via amend algo / attach block (2026-04-13). - * Only one of newCallbackRatio or newCallbackSpread. - */ -export interface AmendAttachedTrailingStop { - newCallbackRatio?: string; - newCallbackSpread?: string; - newActivePx?: string; +export interface OrderDetails { + instType: string; + instId: string; + ccy: string; + ordId: string; + clOrdId: string; + tag: string; + px: string; + sz: string; + pnl: string; + ordType: OrderType; + side: string; + posSide: PositionSide; + tdMode: string; + accFillSz: string; + fillPx: string; + tradeId: string; + fillSz: string; + fillTime: string; + state: OrderState; + avgPx: string; + lever: string; + tpTriggerPx: string; + tpTriggerPxType: string; + tpOrdPx: string; + slTriggerPx: string; + slTriggerPxType: string; + slOrdPx: string; + attachAlgoOrds?: AttachAlgoOrderDetail[]; + feeCcy: string; + fee: string; + rebateCcy: string; + rebate: string; + tgtCcy: string; + category: string; + outcome?: string; + uTime: string; + cTime: string; } ⋮---- -interface AlgoTriggerOrder { - newTpTriggerPx?: string; - newTpTriggerPxType?: 'last' | 'index' | 'mark'; - newTpOrdPx?: string; - newSlTriggerPx?: string; - newSlTriggerPxType?: 'last' | 'index' | 'mark'; - newSlOrdPx?: string; - newCallbackRatio?: string; - newCallbackSpread?: string; - newActivePx?: string; +export interface OrderListItem { + accFillSz: string; + avgPx: string; + cTime: string; + category: string; + ccy: string; + clOrdId: string; + fee: string; + feeCcy: string; + fillPx: string; + fillSz: string; + fillTime: string; + instId: string; + instType: string; + lever: string; + ordId: string; + ordType: OrderType; + pnl: string; + posSide: PositionSide; + px: string; + pxUsd: string; + pxVol: string; + pxType: string; + rebate: string; + rebateCcy: string; + side: string; + attachAlgoClOrdId: string; + slOrdPx: string; + slTriggerPx: string; + slTriggerPxType: string; + state: OrderState; + stpId: string; + stpMode: string; + sz: string; + tag: string; + tgtCcy: string; + tdMode: string; + source: string; + tpOrdPx: string; + tpTriggerPx: string; + tpTriggerPxType: string; + tradeId: string; + reduceOnly: string; + quickMgnType: string; + algoClOrdId: string; + algoId: string; + uTime: string; + attachAlgoOrds?: AttachAlgoOrderDetail[]; + outcome?: string; } ⋮---- -/** - * TP/SL and trailing (move_order_stop) attached to a parent `order` (2026-04-13: callbackRatio | callbackSpread, activePx). - */ -export interface AttachAlgoOrdRequest { - attachAlgoClOrdId?: string; - tpTriggerPx?: string; - /** Only one of tpTriggerPx and tpTriggerRatio (FUTURES/SWAP). */ - tpTriggerRatio?: string; - tpOrdPx?: string; - tpOrdKind?: 'condition' | 'limit'; - slTriggerPx?: string; - slTriggerRatio?: string; - slOrdPx?: string; - tpTriggerPxType?: 'last' | 'index' | 'mark'; - slTriggerPxType?: 'last' | 'index' | 'mark'; - sz?: string; - amendPxOnTriggerType?: '0' | '1'; - /** - * Trailing stop: one of `callbackRatio` or `callbackSpread` when attached ordType is `move_order_stop`. - * e.g. 0.05 = 5% - */ - callbackRatio?: string; - /** Trailing: price distance (alternative to callbackRatio). */ - callbackSpread?: string; - /** Trailing: activation; omit = activate immediately. */ - activePx?: string; +export interface HistoricOrder { + instType: string; + instId: string; + ccy: string; + ordId: string; + clOrdId: string; + tag: string; + px: string; + pxUsd: string; + pxVol: string; + pxType: string; + sz: string; + ordType: OrderType; + side: string; + posSide: PositionSide; + tdMode: string; + accFillSz: string; + fillPx: string; + tradeId: string; + fillSz: string; + fillTime: string; + state: OrderState; + avgPx: string; + lever: string; + attachAlgoClOrdId: string; + tpTriggerPx: string; + tpTriggerPxType: string; + tpOrdPx: string; + slTriggerPx: string; + slTriggerPxType: string; + slOrdPx: string; + attachAlgoOrds?: AttachAlgoOrderDetail[]; + stpId: string; + stpMode: string; + feeCcy: string; + fee: string; + rebateCcy: string; + source: string; + rebate: string; + tgtCcy: string; + pnl: string; + category: string; + reduceOnly: string; + cancelSource: string; + cancelSourceReason: string; + algoClOrdId: string; + algoId: string; + outcome?: string; + uTime: string; + cTime: string; } ⋮---- -/** Only one of tpTriggerPx and tpTriggerRatio (FUTURES/SWAP). */ -⋮---- -/** - * Trailing stop: one of `callbackRatio` or `callbackSpread` when attached ordType is `move_order_stop`. - * e.g. 0.05 = 5% - */ +export interface OrderFill { + instType: string; + instId: string; + tradeId: string; + ordId: string; + clOrdId: string; + billId: string; + tag: string; + fillPx: string; + fillSz: string; + side: string; + posSide: PositionSide; + execType: string; + feeCcy: string; + fee: string; + ts: string; +} ⋮---- -/** Trailing: price distance (alternative to callbackRatio). */ +export interface AlgoOrderResult { + algoId: string; + algoClOrdId: string; + sCode: string; + sMsg: string; +} ⋮---- -/** Trailing: activation; omit = activate immediately. */ +export interface AmendAlgoOrderResult extends AlgoOrderResult { + reqId: string; +} ⋮---- -export interface AdvChaseParams { +export interface AlgoOrderDetailsResult { + instType: string; + instId: string; + ordId: string; + ordIdList: string[]; + ccy: string; + clOrdId: string; + algoId: string; + attachAlgoOrds?: AttachAlgoOrderDetail[]; + sz: string; + closeFraction: string; + ordType: AlgoOrderType; + side: string; + posSide: AlgoPositionSide; + tdMode: string; + tgtCcy: string; + state: AlgoOrderState; + lever: string; + tpTriggerPx: string; + tpTriggerPxType: string; + tpOrdPx: string; + slTriggerPx: string; + slTriggerPxType: string; + slOrdPx: string; + triggerPx: string; + triggerPxType: string; + ordPx: string; + actualSz: string; + actualPx: string; + actualSide: string; + pxVar: string; + pxSpread: string; + pxLimit: string; + szLimit: string; + tag: string; + timeInterval: string; + callbackRatio: string; + callbackSpread: string; + activePx: string; + moveTriggerPx: string; + reduceOnly: string; + triggerTime: string; + quickMgnType: string; + last: string; + failCode: string; + algoClOrdId: string; + amendPxOnTriggerType: string; + cTime: string; + isTradeBorrowMode: boolean; chaseType?: string; chaseVal?: string; maxChaseType?: string; maxChaseVal?: string; + /** Sub-order type for trigger orders: fok, ioc, chase, or empty. */ + advanceOrdType?: string; + /** Chase params when advanceOrdType is chase. */ + advChaseParams?: { + chaseType?: string; + chaseVal?: string; + maxChaseType?: string; + maxChaseVal?: string; + }[]; + /** algoId(s) of algo order(s) spawned when trigger fires (chase). Empty before trigger. */ + subAlgoIdList?: string[]; } ⋮---- -export interface AdvChaseAmendParams { - newChaseVal?: string; - newMaxChaseVal?: string; -} +/** Sub-order type for trigger orders: fok, ioc, chase, or empty. */ ⋮---- -export interface AlgoOrderRequest { +/** Chase params when advanceOrdType is chase. */ +⋮---- +/** algoId(s) of algo order(s) spawned when trigger fires (chase). Empty before trigger. */ +⋮---- +export interface AlgoOrderListItem { + activePx: string; + actualPx: string; + actualSide: string; + actualSz: string; + algoId: string; + attachAlgoOrds?: AttachAlgoOrderDetail[]; + cTime: string; + callbackRatio: string; + callbackSpread: string; + ccy: string; + clOrdId: string; instId: string; - tdMode: TradeMode; - ccy?: string; - side: OrderSide; - posSide?: AlgoPositionSide; + instType: string; + lever: string; + moveTriggerPx: string; + ordId: string; + ordIdList: string[]; + ordPx: string; ordType: AlgoOrderType; - algoClOrdId?: string; - sz: numberInString; - tag?: string; - reduceOnly?: boolean; - tgtCcy?: string; - tpTriggerPx?: numberInString; - tpTriggerPxType?: PriceTriggerType; - tpOrdPx?: numberInString; - tpOrdKind?: string; - slTriggerPx?: numberInString; - slTriggerPxType?: PriceTriggerType; - slOrdPx?: numberInString; - cxlOnClosePos?: boolean; - triggerPx?: numberInString; - triggerPxType?: PriceTriggerType; - orderPx?: numberInString; + posSide: AlgoPositionSide; + pxLimit: string; + pxSpread: string; + pxVar: string; + side: string; + slOrdPx: string; + slTriggerPx: string; + slTriggerPxType: string; + state: AlgoOrderState; + sz: string; + closeFraction: string; + szLimit: string; + tag: string; + tdMode: string; + tgtCcy: string; + timeInterval: string; + tpOrdPx: string; + tpTriggerPx: string; + tpTriggerPxType: string; + triggerPx: string; + reduceOnly: string; + triggerPxType: string; + quickMgnType: string; + last: string; + failCode: string; + algoClOrdId: string; + triggerTime: string; + amendPxOnTriggerType: string; + isTradeBorrowMode: boolean; chaseType?: string; - chaseVal?: numberInString; + chaseVal?: string; maxChaseType?: string; - maxChaseVal?: numberInString; - callbackRatio?: numberInString; - callbackSpread?: numberInString; - activePx?: numberInString; - pxVar?: numberInString; - pxSpread?: numberInString; - szLimit?: numberInString; - pxLimit?: numberInString; - timeInterval?: string; - quickMgnType?: string; - closeFraction?: numberInString; - advanceOrdType?: 'fok' | 'ioc' | 'chase' | ''; - /** Required when advanceOrdType is `chase` (FUTURES/SWAP trigger). */ - advChaseParams?: AdvChaseParams[]; - attachAlgoOrds?: AttachAlgoOrdRequest[]; + maxChaseVal?: string; + advanceOrdType?: string; + advChaseParams?: { + chaseType?: string; + chaseVal?: string; + maxChaseType?: string; + maxChaseVal?: string; + }[]; + subAlgoIdList?: string[]; } ⋮---- -/** Required when advanceOrdType is `chase` (FUTURES/SWAP trigger). */ -⋮---- -export interface AmendOrderRequest { +export interface HistoricAlgoOrder { + activePx: string; + actualPx: string; + actualSide: string; + actualSz: string; + algoClOrdId: string; + algoId: string; + attachAlgoOrds?: AttachAlgoOrderDetail[]; + cTime: string; + callbackRatio: string; + callbackSpread: string; + ccy: string; + clOrdId: string; + closeFraction: string; + failCode: string; instId: string; - cxlOnFail?: boolean; - ordId?: string; - clOrdId?: string; - reqId?: string; - newSz?: string; - newPx?: string; - /** - * EVENTS: `"1"` for non-`post_only` amends when applicable. - * Ignored since 2026-07-24 (event-contract speed bump removed). - */ - speedBump?: string; - /** RPI taker access. Not inherited on amend - omit = false. Alias: isElpTakerAccess until 2026-10-31. */ - rpiTakerAccess?: boolean; - /** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ - isElpTakerAccess?: boolean; - /** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ - rpiPxRound?: boolean; - /** - * Amend attached trailing stop (or related attach algo) — only one of newCallbackRatio / newCallbackSpread per item (2026-04-13). - */ - attachAlgoOrds?: AmendAttachedTrailingStop[]; + instType: string; + last: string; + lever: string; + moveTriggerPx: string; + ordId: string; + ordIdList: string[]; + ordPx: string; + ordType: AlgoOrderType; + posSide: AlgoPositionSide; + pxLimit: string; + pxSpread: string; + pxVar: string; + quickMgnType: string; + reduceOnly: string; + side: string; + slOrdPx: string; + slTriggerPx: string; + slTriggerPxType: string; + state: AlgoOrderState; + sz: string; + szLimit: string; + tag: string; + tdMode: string; + tgtCcy: string; + timeInterval: string; + tpOrdPx: string; + tpTriggerPx: string; + tpTriggerPxType: string; + triggerPx: string; + triggerPxType: string; + triggerTime: string; + amendPxOnTriggerType: string; + isTradeBorrowMode: boolean; + chaseType?: string; + chaseVal?: string; + maxChaseType?: string; + maxChaseVal?: string; + advanceOrdType?: string; + advChaseParams?: { + chaseType?: string; + chaseVal?: string; + maxChaseType?: string; + maxChaseVal?: string; + }[]; + subAlgoIdList?: string[]; } ⋮---- -/** - * EVENTS: `"1"` for non-`post_only` amends when applicable. - * Ignored since 2026-07-24 (event-contract speed bump removed). - */ +export interface CancelAllAfterResponse { + triggerTime: string; + tag: string; + ts: string; +} + +================ +File: src/types/rest/shared.ts +================ +export type numberInString = T; ⋮---- -/** RPI taker access. Not inherited on amend - omit = false. Alias: isElpTakerAccess until 2026-10-31. */ +export interface APIResponse { + code: '0'; + msg: ''; + data: T; +} ⋮---- -/** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ +export type AlgoOrderType = + | 'conditional' + | 'oco' + | 'trigger' + | 'move_order_stop' + | 'iceberg' + | 'twap' + | 'chase'; ⋮---- -/** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ +export type AlgoOrderState = + | 'live' + | 'pause' + | 'partially_effective' + | 'effective' + | 'canceled' + | 'order_failed' + | 'partially_failed'; ⋮---- -/** - * Amend attached trailing stop (or related attach algo) — only one of newCallbackRatio / newCallbackSpread per item (2026-04-13). - */ +export type AlgoPositionSide = 'long' | 'short'; ⋮---- -export type AlgoOrderDetailsRequest = - | { - algoId: string; - } - | { - algoClOrdId: string; - }; +export type ContractGridDirection = 'long' | 'short' | 'neutral'; ⋮---- -export interface AmendAlgoOrderRequest { - instId: string; - algoId?: string; - algoClOrdId?: string; - cxlOnFail?: boolean; - reqId?: string; - newSz?: string; - newTpTriggerPx?: string; - newTpOrdPx?: string; - newSlTriggerPx?: string; - newSlOrdPx?: string; - newTpTriggerPxType?: 'last' | 'index' | 'mark'; - newSlTriggerPxType?: 'last' | 'index' | 'mark'; - newTriggerPx?: string; - newOrdPx?: string; - newTriggerPxType?: 'last' | 'index' | 'mark'; - /** Amend chase values on a pending trigger+chase order (pre-trigger). */ - advChaseParams?: AdvChaseAmendParams[]; - attachAlgoOrds?: AlgoTriggerOrder[]; -} +export type GridAlgoSubOrderType = 'live' | 'filled'; ⋮---- -/** Amend chase values on a pending trigger+chase order (pre-trigger). */ +export type InstrumentType = + | 'SPOT' + | 'MARGIN' + | 'SWAP' + | 'FUTURES' + | 'OPTION' + | 'EVENTS'; ⋮---- -export interface CancelAlgoOrderRequest { +export type MarginMode = 'cross' | 'isolated'; +⋮---- +export type OrderSide = 'buy' | 'sell'; +⋮---- +export type OrderType = + | 'market' + | 'limit' + | 'post_only' + | 'fok' + | 'ioc' + | 'optimal_limit_ioc' + | 'mmp' + | 'mmp_and_post_only' + | 'elp' + /** RPI maker (replaces `elp`; ELP alias accepted until 2026-10-31) */ + | 'rpi'; +⋮---- +/** RPI maker (replaces `elp`; ELP alias accepted until 2026-10-31) */ +⋮---- +export type OrderState = + | 'canceled' + | 'live' + | 'partially_filled' + | 'filled' + | 'mmp_canceled'; +⋮---- +export type PositionSide = 'net' | 'long' | 'short'; +⋮---- +export type PriceTriggerType = 'last' | 'index' | 'mark'; +⋮---- +export interface RFQLeg { instId: string; - algoId?: string; - algoClOrdId?: string; + sz: string; + side: OrderSide; + tgtCcy?: string; } ⋮---- -export interface ClosePositionRequest { +export interface RFQQuoteLegExtended { + px: string; + sz: string; instId: string; - posSide?: PositionSide; - mgnMode: MarginMode; - ccy?: string; - autoCxl?: boolean; - clOrdId?: string; - tag?: string; + side: string; + fee: string; + feeCcy: string; + tradeId: string; } ⋮---- -export interface FillsHistoryRequest { - instType?: InstrumentType; - uly?: string; - instId?: string; - ordId?: string; +export type TradeMode = 'cross' | 'isolated' | 'cash' | 'spot_isolated'; +⋮---- +export interface TimestampObject { + ts: numberInString; +} +⋮---- +export interface Pagination { after?: string; before?: string; - begin?: string; - end?: string; limit?: string; } ⋮---- -export interface OrderIdRequest { - /** - * REST: use as in trade docs. WebSocket `cancel-order` / `batch-cancel-orders`: deprecated (2026-04-07) — if sent, ignored; use - * `ordId` or `clOrdId`. Optional `instIdCode` may still be used to map the instrument. - */ - instId?: string; - /** - * Where supported, may take precedence over `instId` if both are present. Get instruments to map. - */ - instIdCode?: number; - ordId?: string; - clOrdId?: string; -} -⋮---- -/** - * REST: use as in trade docs. WebSocket `cancel-order` / `batch-cancel-orders`: deprecated (2026-04-07) — if sent, ignored; use - * `ordId` or `clOrdId`. Optional `instIdCode` may still be used to map the instrument. - */ +export type PosMode = 'long_short_mode' | 'net_mode'; ⋮---- -/** - * Where supported, may take precedence over `instId` if both are present. Get instruments to map. - */ +export type AccountLevel = '1' | '2' | '3' | '4'; ⋮---- -export interface OrderHistoryRequest { - instType: InstrumentType; - uly?: string; - instId?: string; - ordType?: OrderType; - state?: string; - category?: string; - after?: string; - before?: string; - begin?: string; - end?: string; - limit?: string; -} +export type WithdrawState = + | '-3' + | '-2' + | '-1' + | '0' + | '1' + | '2' + | '4' + | '5' + | '6' + | '8' + | '9' + | '10' + | '12'; + +================ +File: src/types/websockets/ws-request.ts +================ +import type { InstrumentType } from '../rest/shared.js'; ⋮---- -export interface OrderRequest { - instId: string; - tdMode: TradeMode; - ccy?: string; - clOrdId?: string; - tag?: string; - side: OrderSide; - posSide?: PositionSide; - ordType: OrderType; - /** Quantity to buy or sell */ - sz: numberInString; - px?: string; - /** Place options orders in USD. Only applicable to options. One of px/pxUsd/pxVol must be filled for option orders */ - pxUsd?: string; - /** Place options orders based on implied volatility, where 1 represents 100%. Only applicable to options */ - pxVol?: string; - reduceOnly?: boolean; - /** A spot buy on BTC-USDT with "base_ccy" would mean the QTY (sz) is in USDT */ - tgtCcy?: 'base_ccy' | 'quote_ccy'; - /** - * Maximum acceptable slippage for spot and spot margin market-side orders, where tgtCcy is the received currency (base_ccy for buy, quote_ccy for sell). - * Range: 0 to 0.05 (0% to 5%, inclusive). Up to 2 decimal places, e.g. 0.01 (1%) and 0.0123 (1.23%). Defaults to 0.00% if not specified. - * Only applicable to SPOT and SPOT margin market orders. Cannot be amended on an existing order. - */ - slippagePct?: string; - banAmend?: boolean; - /** Price amendment type: "0" = do not allow amendment, "1" = allow amendment within price limit. Default is "0" */ - pxAmendType?: '0' | '1'; - /** Quote currency used for trading. Only applicable to SPOT. Default is quote currency of instId */ - tradeQuoteCcy?: string; - /** Self trade prevention mode: cancel_maker, cancel_taker, cancel_both. Default is cancel_maker */ - stpMode?: 'cancel_maker' | 'cancel_taker' | 'cancel_both'; - /** - * RPI taker access for limit/market/fok/ioc. Default false. Speedbump when true. - * Alias `isElpTakerAccess` accepted until 2026-10-31. - */ - rpiTakerAccess?: boolean; - /** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ - isElpTakerAccess?: boolean; - /** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ - rpiPxRound?: boolean; - /** - * EVENTS: set to `"1"` for non-`post_only` orders. Error 54086 if missing when required. - * Ignored since 2026-07-24 (event-contract speed bump removed). - */ - speedBump?: string; - /** EVENTS: `yes` or `no`. */ - outcome?: string; - /** Take Profit & Stop Loss params */ - tpTriggerPx?: string; - tpOrdPx?: string; - slTriggerPx?: string; - slOrdPx?: string; - tpTriggerPxType?: PriceTriggerType; - slTriggerPxType?: PriceTriggerType; - /** TP/SL / trailing (attach) when placing the parent order */ - attachAlgoOrds?: AttachAlgoOrdRequest[]; - /** Quick margin type */ - quickMgnType?: 'manual' | 'auto_borrow' | 'auto_repay'; +export interface WsAuthRequestArg { + apiKey: string; + passphrase: string; + timestamp: string; + sign: string; } ⋮---- -/** Quantity to buy or sell */ -⋮---- -/** Place options orders in USD. Only applicable to options. One of px/pxUsd/pxVol must be filled for option orders */ -⋮---- -/** Place options orders based on implied volatility, where 1 represents 100%. Only applicable to options */ +export type WsTradeOp = + | 'order' + | 'batch-orders' + | 'cancel-order' + | 'batch-cancel-orders' + | 'amend-order' + | 'batch-amend-order'; ⋮---- -/** A spot buy on BTC-USDT with "base_ccy" would mean the QTY (sz) is in USDT */ +export type WsPrivateChannel = + | 'account' + | 'positions' + | 'balance_and_position' + | 'orders' + | 'orders-algo' + | 'algo-advance' + | 'liquidation-warning' + | 'adl-warning' + | 'account-greeks' + | 'grid-orders-spot' + | 'grid-orders-contract' + | 'grid-orders-moon' + | 'grid-positions' + | 'grid-sub-orders'; ⋮---- -/** - * Maximum acceptable slippage for spot and spot margin market-side orders, where tgtCcy is the received currency (base_ccy for buy, quote_ccy for sell). - * Range: 0 to 0.05 (0% to 5%, inclusive). Up to 2 decimal places, e.g. 0.01 (1%) and 0.0123 (1.23%). Defaults to 0.00% if not specified. - * Only applicable to SPOT and SPOT margin market orders. Cannot be amended on an existing order. - */ +export type WsPublicKlineChannel = + | 'candle1Y' + | 'candle6M' + | 'candle3M' + | 'candle1M' + | 'candle1W' + | 'candle1D' + | 'candle2D' + | 'candle3D' + | 'candle5D' + | 'candle12H' + | 'candle6H' + | 'candle4H' + | 'candle2H' + | 'candle1H' + | 'candle30m' + | 'candle15m' + | 'candle5m' + | 'candle3m' + | 'candle1m' + | 'candle1s' + | 'candle1Yutc' + | 'candle3Mutc' + | 'candle1Mutc' + | 'candle1Wutc' + | 'candle1Dutc' + | 'candle2Dutc' + | 'candle3Dutc' + | 'candle5Dutc' + | 'candle12Hutc' + | 'candle6Hutc'; ⋮---- -/** Price amendment type: "0" = do not allow amendment, "1" = allow amendment within price limit. Default is "0" */ +export type WsPublicMarkPriceKlineChannel = + | 'mark-price-candle1Y' + | 'mark-price-candle6M' + | 'mark-price-candle3M' + | 'mark-price-candle1M' + | 'mark-price-candle1W' + | 'mark-price-candle1D' + | 'mark-price-candle2D' + | 'mark-price-candle3D' + | 'mark-price-candle5D' + | 'mark-price-candle12H' + | 'mark-price-candle6H' + | 'mark-price-candle4H' + | 'mark-price-candle2H' + | 'mark-price-candle1H' + | 'mark-price-candle30m' + | 'mark-price-candle15m' + | 'mark-price-candle5m' + | 'mark-price-candle3m' + | 'mark-price-candle1m' + | 'mark-price-candle1Yutc' + | 'mark-price-candle3Mutc' + | 'mark-price-candle1Mutc' + | 'mark-price-candle1Wutc' + | 'mark-price-candle1Dutc' + | 'mark-price-candle2Dutc' + | 'mark-price-candle3Dutc' + | 'mark-price-candle5Dutc' + | 'mark-price-candle12Hutc' + | 'mark-price-candle6Hutc'; ⋮---- -/** Quote currency used for trading. Only applicable to SPOT. Default is quote currency of instId */ +export type WsPublicIndexKlineChannel = + | 'index-candle1Y' + | 'index-candle6M' + | 'index-candle3M' + | 'index-candle1M' + | 'index-candle1W' + | 'index-candle1D' + | 'index-candle2D' + | 'index-candle3D' + | 'index-candle5D' + | 'index-candle12H' + | 'index-candle6H' + | 'index-candle4H index -candle2H' + | 'index-candle1H' + | 'index-candle30m' + | 'index-candle15m' + | 'index-candle5m' + | 'index-candle3m' + | 'index-candle1m' + | 'index-candle1Yutc' + | 'index-candle3Mutc' + | 'index-candle1Mutc' + | 'index-candle1Wutc' + | 'index-candle1Dutc' + | 'index-candle2Dutc' + | 'index-candle3Dutc' + | 'index-candle5Dutc' + | 'index-candle12Hutc' + | 'index-candle6Hutc'; ⋮---- -/** Self trade prevention mode: cancel_maker, cancel_taker, cancel_both. Default is cancel_maker */ +export type WsPublicOrderBooksChannel = + | 'books' + | 'books5' + | 'bbo-tbt' + | 'books-l2-tbt' + | 'books50-l2-tpt' + /** @deprecated Use `books-rpi`. ELP-only book; retired after 2026-10-31. */ + | 'books-elp' + /** Consolidated organic + RPI depth (replaces books-elp). */ + | 'books-rpi'; ⋮---- -/** - * RPI taker access for limit/market/fok/ioc. Default false. Speedbump when true. - * Alias `isElpTakerAccess` accepted until 2026-10-31. - */ +/** @deprecated Use `books-rpi`. ELP-only book; retired after 2026-10-31. */ ⋮---- -/** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ +/** Consolidated organic + RPI depth (replaces books-elp). */ ⋮---- -/** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ +export type WsPublicChannel = + | 'instruments' + | 'tickers' + | 'open-interest' + | WsPublicKlineChannel + | WsPublicMarkPriceKlineChannel + | WsPublicIndexKlineChannel + | 'trades' + | 'estimated-price' + | 'mark-price' + | 'price-limit' + | WsPublicOrderBooksChannel + | 'opt-summary' + | 'funding-rate' + | 'index-tickers' + | 'status' + | 'liquidation-orders' + | 'event-contract-markets'; ⋮---- -/** - * EVENTS: set to `"1"` for non-`post_only` orders. Error 54086 if missing when required. - * Ignored since 2026-07-24 (event-contract speed bump removed). - */ -⋮---- -/** EVENTS: `yes` or `no`. */ +export type WsBusinessPrivateChannel = + | 'orders-algo' + | 'algo-advance' + | 'deposit-info' + | 'withdrawal-info' + | 'grid-orders-spot' + | 'grid-orders-contract' + | 'grid-orders-moon' + | 'grid-positions' + | 'grid-sub-orders' + | 'algo-recurring-buy'; ⋮---- -/** Take Profit & Stop Loss params */ +export type WsBusinessPublicChannel = + | WsPublicKlineChannel + | WsPublicMarkPriceKlineChannel + | WsPublicIndexKlineChannel; ⋮---- -/** TP/SL / trailing (attach) when placing the parent order */ +export type WsBusinessChannel = + | WsBusinessPrivateChannel + | WsBusinessPublicChannel; ⋮---- -/** Quick margin type */ +export type WsChannel = WsPublicChannel | WsPrivateChannel | WsBusinessChannel; ⋮---- -export interface GetTransactionDetailsArchiveRequest { - year: string; - quarter: 'Q1' | 'Q2' | 'Q3' | 'Q4'; +/** Used to trigger order actions over websockets (e.g. placing & cancelling orders) */ +export interface WsTradeBaseRequest { + op: WsTradeOp; + id: string; + args: any[]; } ⋮---- -export interface OrderPrecheckRequest { - instId: string; - tdMode: string; - side: string; - posSide?: string; - ordType: string; - sz: string; - px?: string; - reduceOnly?: boolean; - tgtCcy?: string; - /** EVENTS: `yes` / `no`. */ - outcome?: string; - attachAlgoOrds?: AttachAlgoOrdRequest[]; +export interface WsBaseRequestArg { + channel: WsChannel; } ⋮---- -/** EVENTS: `yes` / `no`. */ - -================ -File: src/types/rest/response/public-data.ts -================ -import { InstrumentType, numberInString } from '../shared.js'; +/** + * + * Args to be sent with top level requests + * + */ ⋮---- -export interface Ticker { - instType: InstrumentType; +export interface WsPrivateChannelArgTickers extends WsBaseRequestArg { + channel: 'tickers'; instId: string; - last: numberInString; - lastSz: numberInString; - askPx: numberInString; - askSz: numberInString; - bidPx: numberInString; - bidSz: numberInString; - open24h: numberInString; - high24h: numberInString; - low24h: numberInString; - volCcy24h: numberInString; - vol24h: numberInString; - sodUtc0: numberInString; - sodUtc8: numberInString; - ts: numberInString; } ⋮---- -export interface IndexTicker { - instId: string; - idxPx: string; - high24h: string; - sodUtc0: string; - open24h: string; - low24h: string; - sodUtc8: string; - ts: string; +export interface WsPrivateChannelArgWithCcy extends WsBaseRequestArg { + channel: 'account' | 'account-greeks' | 'withdrawal-info'; + ccy?: string; } ⋮---- -type OBPrice = string; -type OBAssetQty = string; -type OBOrderCount = string; -type OrderBookLevel = [OBPrice, OBAssetQty, '0', OBOrderCount]; +/** `ANY` is used by some private subscription args; instruments channel uses `EVENTS` for event contracts. */ +export type WsChannelArgInstType = InstrumentType | 'ANY'; ⋮---- -export interface OrderBook { - asks: OrderBookLevel[]; - bids: OrderBookLevel[]; - ts: string; +export interface WsPrivateChannelArgWithInstFamily extends WsBaseRequestArg { + channel: 'positions' | 'orders' | 'orders-algo' | 'liquidation-warning'; + instType: WsChannelArgInstType; + instFamily?: string; + instId?: string; } ⋮---- -/** RPI consolidated book level: [price, totalQty, nonRpiQty, count] */ -type OrderBookRpiLevel = [string, string, string, string]; -⋮---- -export interface OrderBookRpi { - asks: OrderBookRpiLevel[]; - bids: OrderBookRpiLevel[]; - ts: string; - seqId: number; +export interface WsPrivateChannelArgAlgo extends WsBaseRequestArg { + channel: 'algo-advance'; + instType: WsChannelArgInstType; + instId?: string; + algoId?: string; } ⋮---- -type timestamp = string; -type openPrice = string; -type highPrice = string; -type lowPrice = string; -type closePrice = string; -type vol = string; -type volCcy = string; -type volCcyQuote = string; -type confirm = string; -⋮---- -export type Candle = [ - timestamp, - openPrice, - highPrice, - lowPrice, - closePrice, - vol, - volCcy, - volCcyQuote, - confirm, -]; +export interface WsPrivateChannelArgBalanceAndPosition + extends WsBaseRequestArg { + channel: 'balance_and_position'; +} ⋮---- -export type CandleNoVolume = [ - timestamp, - openPrice, - highPrice, - lowPrice, - closePrice, -]; +export interface WsPrivateChannelArgGridOrders extends WsBaseRequestArg { + channel: 'grid-orders-spot' | 'grid-orders-contract' | 'grid-orders-moon'; + instType: 'SPOT' | 'ANY'; + instId?: string; + algoId?: string; +} ⋮---- -export interface Trade { - instId: string; - side: string; - sz: string; - px: string; - tradeId: string; - ts: string; - source?: string; +export interface WsPrivateChannelArgGridOther extends WsBaseRequestArg { + channel: 'grid-positions' | 'grid-sub-orders'; + algoId: string; } ⋮---- -export interface InstrumentUpcomingParamChange { - param: 'tickSz' | 'minSz' | 'maxMktSz' | string; - newValue: string; - effTime: string; +export interface WsPublicChannelArgInstType extends WsBaseRequestArg { + channel: 'instruments'; + instType: WsChannelArgInstType; } ⋮---- -export interface Instrument { - instType: InstrumentType; - /** Series id for EVENTS, e.g. BTC-ABOVE-DAILY. */ - seriesId?: string; +export interface WsPublicChannelArgInstId extends WsBaseRequestArg { + channel: + | 'tickers' + | 'open-interest' + | WsPublicKlineChannel + | WsPublicMarkPriceKlineChannel + | WsPublicIndexKlineChannel + | 'trades' + | 'mark-price' + | 'price-limit' + | WsPublicOrderBooksChannel + | 'funding-rate' + | 'index-tickers'; instId: string; - uly: string; - instFamily: string; - category: string; - baseCcy: string; - quoteCcy: string; - settleCcy: string; - ctVal: string; - ctMult: string; - ctValCcy: string; - optType: string; - stk: string; - listTime: string; - contTdSwTime?: string; // Continuous trading switch time. The switch time from call auction/prequote to continuous trading. Unix timestamp format in milliseconds. - preMktSwTime?: string; // The time a pre-market instrument switches to normal trading, Unix ms. Applicable to pre-market SWAP and Pre-market X-Perp FUTURES. - expTime: string; - lever: string; - tickSz: string; - lotSz: string; - minSz: string; - ctType: string; - /** - * FUTURES contract label (deprecated — prefer `expTime` for delivery time; removal planned). - * Includes `this_five_years` / `next_five_years` (X-Perps / 5Y-style contracts). - */ - alias: string; - /** - * Instrument status: live, suspend, rebase (SWAP only), post_only (SWAP only), preopen, test, expired, settling (EVENTS), … - */ - state: string; - openType?: string; // Open type: fix_price (fix price opening), pre_quote (pre-quote), call_auction (call auction). Only applicable to SPOT/MARGIN. - maxLmtSz: string; - maxLmtAmt?: string; // Max USD amount for a single limit order - maxMktSz: string; - maxMktAmt?: string; // Max USD amount for a single market order. Only applicable to SPOT/MARGIN. - maxTwapSz: string; - maxIcebergSz: string; - maxTriggerSz: string; - maxStopSz: string; - /** - * e.g. `normal`, `pre_market` (incl. Pre-market X-Perp FUTURES), `rebase_contract`, `xperp` (after Pre-market X-Perp converts). - */ - ruleType: string; - auctionEndTime: string; - futureSettlement?: boolean; // Whether daily settlement for expiry feature is enabled. Applicable to FUTURES cross. - tradeQuoteCcyList?: string[]; // List of quote currencies available for trading, e.g. ["USD", "USDC"] - instIdCode?: number; // Instrument ID code. For simple binary encoding, must use instIdCode instead of instId. - /** - * Asset category of the instrument's base asset (first segment of `instId`). E.g. BTC-USDT-SWAP → category of BTC. - * 1: Crypto, 3: Stocks, 4: Commodities, 5: Forex, 6: Bonds, "": not available - */ - instCategory?: string; - posLmtAmt?: string; // Maximum position value (USD) for this instrument at the user level. Applicable to SWAP/FUTURES. - posLmtPct?: string; // Maximum position ratio (e.g., 30 for 30%) a user may hold relative to platform's current total position value. Applicable to SWAP/FUTURES. - longPosRemainingQuota?: string; - shortPosRemainingQuota?: string; - maxPlatOILmt?: string; // Platform-wide maximum position value (USD) for this instrument. Applicable to SWAP/FUTURES. - groupId?: string; // Instrument trading fee group ID - /** Minimum spacing between RPI bid and RPI ask, in organic price levels. Default 4; 0 for Event Contracts. */ - rpiMinLevel?: string; - /** Minimum distance from opposite-side organic best price for RPI spacing, in bps. */ - rpiMinPxBand?: string; - upcChg?: InstrumentUpcomingParamChange[]; } ⋮---- -/** Series id for EVENTS, e.g. BTC-ABOVE-DAILY. */ -⋮---- -contTdSwTime?: string; // Continuous trading switch time. The switch time from call auction/prequote to continuous trading. Unix timestamp format in milliseconds. -preMktSwTime?: string; // The time a pre-market instrument switches to normal trading, Unix ms. Applicable to pre-market SWAP and Pre-market X-Perp FUTURES. +export type WsPublicChannelArgInstIdOrFamily = { + channel: 'estimated-price'; + instType: 'OPTION' | 'FUTURES' | 'SWAP' | 'EVENTS'; +} & ( + | { + instId: string; + } + | { + instFamily: string; + } +); ⋮---- -/** - * FUTURES contract label (deprecated — prefer `expTime` for delivery time; removal planned). - * Includes `this_five_years` / `next_five_years` (X-Perps / 5Y-style contracts). - */ +export interface WsPublicChannelArgOptionSummary extends WsBaseRequestArg { + channel: 'opt-summary'; + instFamily: string; +} ⋮---- -/** - * Instrument status: live, suspend, rebase (SWAP only), post_only (SWAP only), preopen, test, expired, settling (EVENTS), … +export interface WsPublicChannelArgStatus extends WsBaseRequestArg { + channel: 'status'; +} +⋮---- +export interface WsPublicChannelArgLiquidationOrders extends WsBaseRequestArg { + channel: 'liquidation-orders'; + instType: 'SWAP' | 'FUTURES'; +} +⋮---- +/** Event contract market status & floor strikes. @see public WS `event-contract-markets` */ +export interface WsPublicChannelArgEventContractMarkets + extends WsBaseRequestArg { + channel: 'event-contract-markets'; + instType: 'EVENTS'; +} +⋮---- +export type WsChannelSubUnSubRequestArg = + | WsPrivateChannelArgTickers + | WsPrivateChannelArgWithCcy + | WsPrivateChannelArgWithInstFamily + | WsPrivateChannelArgAlgo + | WsPrivateChannelArgBalanceAndPosition + | WsPrivateChannelArgGridOrders + | WsPrivateChannelArgGridOther + | WsPublicChannelArgInstType + | WsPublicChannelArgInstId + | WsPublicChannelArgInstIdOrFamily + | WsPublicChannelArgOptionSummary + | WsPublicChannelArgStatus + | WsPublicChannelArgLiquidationOrders + | WsPublicChannelArgEventContractMarkets; + +================ +File: src/types/websockets/ws-api-request.ts +================ +import type { + AmendAttachedTrailingStop, + AttachAlgoOrdRequest, +} from '../rest/request/trade.js'; +import { + numberInString, + OrderSide, + OrderType, + PositionSide, + TradeMode, +} from '../rest/shared.js'; +⋮---- +export interface WSAPIPlaceOrderRequestV5 { + /** Instrument ID. Deprecated March 2026; use instIdCode for lower latency. */ + instId?: string; + /** Instrument ID code. Takes precedence over instId if both provided. Use Get instruments to map. */ + instIdCode?: number; + tdMode: TradeMode; + ccy?: string; + clOrdId?: string; + tag?: string; + side: OrderSide; + posSide?: PositionSide; + ordType: OrderType; + /** Quantity to buy or sell */ + sz: numberInString; + px?: numberInString; + pxUsd?: numberInString; + pxVol?: numberInString; + reduceOnly?: boolean; + /** A spot buy on BTC-USDT with "base_ccy" would mean the QTY (sz) is in USDT */ + tgtCcy?: 'base_ccy' | 'quote_ccy'; + /** + * Maximum acceptable slippage for spot and spot margin market-side orders, where tgtCcy is the received currency (base_ccy for buy, quote_ccy for sell). + * Range: 0 to 0.05 (0% to 5%, inclusive). Up to 2 decimal places, e.g. 0.01 (1%) and 0.0123 (1.23%). Defaults to 0.00% if not specified. + * Only applicable to SPOT and SPOT margin market orders. Cannot be amended on an existing order. + */ + slippagePct?: string; + banAmend?: boolean; + tradeQuoteCcy?: string; + stpMode?: 'cancel_maker' | 'cancel_taker' | 'cancel_both'; + /** + * RPI taker access for limit/market/fok/ioc. Default false. + * Alias `isElpTakerAccess` accepted until 2026-10-31. */ + rpiTakerAccess?: boolean; + /** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ + isElpTakerAccess?: boolean; + /** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ + rpiPxRound?: boolean; + /** EVENTS: `"1"` for non-`post_only` orders when required (error 54086 if missing). Ignored since 2026-07-24. */ + speedBump?: string; + /** EVENTS: `yes` or `no`. */ + outcome?: string; + attachAlgoOrds?: AttachAlgoOrdRequest[]; +} ⋮---- -openType?: string; // Open type: fix_price (fix price opening), pre_quote (pre-quote), call_auction (call auction). Only applicable to SPOT/MARGIN. +/** Instrument ID. Deprecated March 2026; use instIdCode for lower latency. */ ⋮---- -maxLmtAmt?: string; // Max USD amount for a single limit order +/** Instrument ID code. Takes precedence over instId if both provided. Use Get instruments to map. */ ⋮---- -maxMktAmt?: string; // Max USD amount for a single market order. Only applicable to SPOT/MARGIN. +/** Quantity to buy or sell */ +⋮---- +/** A spot buy on BTC-USDT with "base_ccy" would mean the QTY (sz) is in USDT */ ⋮---- /** - * e.g. `normal`, `pre_market` (incl. Pre-market X-Perp FUTURES), `rebase_contract`, `xperp` (after Pre-market X-Perp converts). + * Maximum acceptable slippage for spot and spot margin market-side orders, where tgtCcy is the received currency (base_ccy for buy, quote_ccy for sell). + * Range: 0 to 0.05 (0% to 5%, inclusive). Up to 2 decimal places, e.g. 0.01 (1%) and 0.0123 (1.23%). Defaults to 0.00% if not specified. + * Only applicable to SPOT and SPOT margin market orders. Cannot be amended on an existing order. */ ⋮---- -futureSettlement?: boolean; // Whether daily settlement for expiry feature is enabled. Applicable to FUTURES cross. -tradeQuoteCcyList?: string[]; // List of quote currencies available for trading, e.g. ["USD", "USDC"] -instIdCode?: number; // Instrument ID code. For simple binary encoding, must use instIdCode instead of instId. /** - * Asset category of the instrument's base asset (first segment of `instId`). E.g. BTC-USDT-SWAP → category of BTC. - * 1: Crypto, 3: Stocks, 4: Commodities, 5: Forex, 6: Bonds, "": not available + * RPI taker access for limit/market/fok/ioc. Default false. + * Alias `isElpTakerAccess` accepted until 2026-10-31. */ ⋮---- -posLmtAmt?: string; // Maximum position value (USD) for this instrument at the user level. Applicable to SWAP/FUTURES. -posLmtPct?: string; // Maximum position ratio (e.g., 30 for 30%) a user may hold relative to platform's current total position value. Applicable to SWAP/FUTURES. +/** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ ⋮---- -maxPlatOILmt?: string; // Platform-wide maximum position value (USD) for this instrument. Applicable to SWAP/FUTURES. -groupId?: string; // Instrument trading fee group ID -/** Minimum spacing between RPI bid and RPI ask, in organic price levels. Default 4; 0 for Event Contracts. */ +/** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ ⋮---- -/** Minimum distance from opposite-side organic best price for RPI spacing, in bps. */ +/** EVENTS: `"1"` for non-`post_only` orders when required (error 54086 if missing). Ignored since 2026-07-24. */ ⋮---- -export interface EconomicCalendarData { - calendarId: string; - date: string; - region: string; - category: string; - event: string; - refDate: string; - actual: string; - previous: string; - forecast: string; - dateSpan: string; - importance: string; - uTime: string; - prevInitial: string; - ccy: string; - unit: string; -} +/** EVENTS: `yes` or `no`. */ ⋮---- -export interface UnitConvertData { - type: '1' | '2'; - instId: string; - px: string; - sz: string; - unit: 'coin' | 'usds'; +export interface WSAPIAmendOrderRequestV5 { + /** + * If set, ignored for `amend-order` / `batch-amend-orders` — use `ordId`/`clOrdId` to identify the order. + * Map codes via Get instruments as needed. + */ + instId?: string; + /** Use Get instruments to map. */ + instIdCode?: number; + cxlOnFail?: boolean; + ordId?: string; + clOrdId?: string; + reqId?: string; + newSz?: string; + newPx?: string; + newPxUsd?: string; + newPxVol?: string; + /** Ignored since 2026-07-24 (event-contract speed bump removed). */ + speedBump?: string; + /** RPI taker access. Not inherited on amend - omit = false. */ + rpiTakerAccess?: boolean; + /** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ + isElpTakerAccess?: boolean; + /** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ + rpiPxRound?: boolean; + attachAlgoOrds?: AmendAttachedTrailingStop[]; } ⋮---- /** - * @see GET /api/v5/public/funding-rate - * `instType` is `SWAP` (perp) or `FUTURES` (X-Perp) when applicable. - */ -export interface PublicFundingRate { - instType: string; - instId: string; - method: string; - formulaType: string; - fundingRate: string; - nextFundingRate: string; - fundingTime: string; - nextFundingTime: string; - minFundingRate: string; - maxFundingRate: string; - interestRate: string; - impactValue: string; - settState: string; - settFundingRate: string; - premium: string; - ts: string; -} + * If set, ignored for `amend-order` / `batch-amend-orders` — use `ordId`/`clOrdId` to identify the order. + * Map codes via Get instruments as needed. + */ ⋮---- -export interface InsuranceFundDetail { - ccy?: string; - bal?: string; - amt?: string; - type?: string; - maxBal?: string; - maxBalTs?: string; - decRate?: string; - adlType?: string; - adlBal?: string; - adlRecBal?: string; - /** @deprecated Returns "" per 2026-06-09 changelog */ - adlRate?: string; - /** @deprecated Returns "" per 2026-06-09 changelog */ - adlRecRate?: string; -} +/** Use Get instruments to map. */ ⋮---- -/** @deprecated Returns "" per 2026-06-09 changelog */ +/** Ignored since 2026-07-24 (event-contract speed bump removed). */ ⋮---- -/** @deprecated Returns "" per 2026-06-09 changelog */ +/** RPI taker access. Not inherited on amend - omit = false. */ ⋮---- -export interface InsuranceFund { - instType?: string; - details: InsuranceFundDetail[]; -} +/** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ ⋮---- -export interface FundingRateHistory { - /** Perpetual (`SWAP`) or X-Perp (`FUTURES`). */ +/** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ +⋮---- +export interface WSAPIMassCancelOrdersRequestV5 { instType: string; - instId: string; - fundingRate: string; - realizedRate: string; - fundingTime: string; - method: string; - formulaType?: string; + instFamily: string; + lockInterval?: string; } ⋮---- -/** Perpetual (`SWAP`) or X-Perp (`FUTURES`). */ -⋮---- -export interface SystemTime { - ts: string; -} -⋮---- -/** - * @see GET /api/v5/public/estimated-price - */ -export interface EstimatedDeliveryExercisePrice { - instType: string; - instId: string; - settlePx: string; - ts: string; +export interface WSAPIPlaceSpreadOrderRequestV5 { + sprdId: string; + clOrdId?: string; + tag?: string; + side: OrderSide; + ordType: OrderType; + sz: numberInString; + px?: numberInString; } ⋮---- -export interface OptionsTradeInfo { - instId: string; - tradeId: string; - px: string; - sz: string; - side: 'buy' | 'sell'; - ts: string; +export interface WSAPIAmendSpreadOrderRequestV5 { + ordId?: string; + clOrdId?: string; + reqId?: string; + newSz?: string; + newPx?: string; } ⋮---- -export interface OptionTrade { - vol24h: string; - optType: 'C' | 'P'; - tradeInfo: OptionsTradeInfo[]; +export interface WSAPICancelSpreadOrderRequestV5 { + ordId?: string; + clOrdId?: string; } ⋮---- -export interface OptionTrades { - instId: string; - instFamily: string; - tradeId: string; - px: string; - sz: string; - side: 'buy' | 'sell'; - optType: 'C' | 'P'; - fillVol: string; - fwdPx: string; - idxPx: string; - markPx: string; - ts: string; +export interface WSAPISpreadMassCancelOrdersRequestV5 { + sprdId?: string; } + +================ +File: src/types/websockets/ws-general.ts +================ +import type { ClientRequestArgs } from 'http'; +import WebSocket from 'isomorphic-ws'; ⋮---- -export interface Announcement { - annType: string; - pTime: string; // The actual time the announcement was first published. Unix timestamp format in milliseconds, e.g. 1597026383085 - businessPTime: string; // The time displayed on the announcement page for user reference. Unix timestamp format in milliseconds, e.g. 1597026383085 - title: string; - url: string; +import { RestClientOptions } from '../rest/client.js'; +import { APICredentials, APIMarket } from '../shared.js'; +⋮---- +export interface WSClientConfigurableOptions { + accounts?: APICredentials[]; + + /** + * The API group this client should connect to: + * - market: 'prod' (default: connects to OKX global) https://www.okx.com/docs-v5/en/#overview-production-trading-services + * - market: 'OPENAPI_GLOBAL' // OKX Global REST at https://openapi.okx.com (WS same as GLOBAL) + * - market: 'EEA' // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services + * - market: 'US' // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services + */ + market?: APIMarket; + + /** + * Set to `true` to use OKX's demo trading functionality + */ + demoTrading?: boolean; + + // Disable ping/pong ws heartbeat mechanism (not recommended). + // Not supported for OKX + disableHeartbeat?: boolean; + + /** How often to check if the connection is alive */ + pingInterval?: number; + + /** How long to wait for a pong (heartbeat reply) before assuming the connection is dead */ + pongTimeout?: number; + + /** Delay in milliseconds before respawning the connection */ + reconnectTimeout?: number; + + requestOptions?: RestClientOptions; + + wsOptions?: { + protocols?: string[]; + agent?: any; + } & ( + | Omit, 'agent'> + | Omit, 'agent'> + ); + wsUrl?: string; + + /** + * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * + * Look in the examples folder for a demonstration on using node's createHmac instead. + */ + customSignMessageFn?: (message: string, secret: string) => Promise; } ⋮---- -pTime: string; // The actual time the announcement was first published. Unix timestamp format in milliseconds, e.g. 1597026383085 -businessPTime: string; // The time displayed on the announcement page for user reference. Unix timestamp format in milliseconds, e.g. 1597026383085 +/** + * The API group this client should connect to: + * - market: 'prod' (default: connects to OKX global) https://www.okx.com/docs-v5/en/#overview-production-trading-services + * - market: 'OPENAPI_GLOBAL' // OKX Global REST at https://openapi.okx.com (WS same as GLOBAL) + * - market: 'EEA' // also known as "my.okx.com" https://my.okx.com/docs-v5/en/#overview-production-trading-services + * - market: 'US' // also known as "app.okx.com" https://app.okx.com/docs-v5/en/#overview-production-trading-services + */ ⋮---- -/** Public borrow history record (GET /api/v5/finance/savings/lending-rate-history) */ -export interface PublicBorrowHistoryRecord { - ccy: string; // Currency, e.g. BTC - amt: string; // Lending amount (deprecated) - rate: string; // Annual borrowing interest rate - lendingRate: string; // Annual lending interest rate - ts: string; // Unix timestamp format in milliseconds -} +/** + * Set to `true` to use OKX's demo trading functionality + */ ⋮---- -ccy: string; // Currency, e.g. BTC -amt: string; // Lending amount (deprecated) -rate: string; // Annual borrowing interest rate -lendingRate: string; // Annual lending interest rate -ts: string; // Unix timestamp format in milliseconds +// Disable ping/pong ws heartbeat mechanism (not recommended). +// Not supported for OKX ⋮---- -export interface BasicInterestRate { - ccy: string; // Currency - rate: string; // Daily borrowing rate - quota: string; // Max borrow -} +/** How often to check if the connection is alive */ ⋮---- -ccy: string; // Currency -rate: string; // Daily borrowing rate -quota: string; // Max borrow +/** How long to wait for a pong (heartbeat reply) before assuming the connection is dead */ ⋮---- -export interface VIPInterestInfo { - level: string; // VIP Level, e.g. VIP1 - loanQuotaCoef: string; // Loan quota coefficient. Loan quota = quota * level - irDiscount: string; // Interest rate discount (Deprecated) -} +/** Delay in milliseconds before respawning the connection */ ⋮---- -level: string; // VIP Level, e.g. VIP1 -loanQuotaCoef: string; // Loan quota coefficient. Loan quota = quota * level -irDiscount: string; // Interest rate discount (Deprecated) +/** + * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * + * Look in the examples folder for a demonstration on using node's createHmac instead. + */ ⋮---- -export interface RegularUserInterestInfo { - level: string; // Regular user Level, e.g. Lv1 - loanQuotaCoef: string; // Loan quota coefficient. Loan quota = quota * level - irDiscount: string; // Interest rate discount (Deprecated) +export interface WebsocketClientOptions extends WSClientConfigurableOptions { + market: APIMarket; + pongTimeout: number; + pingInterval: number; + reconnectTimeout: number; + authPrivateConnectionsOnConnect: boolean; + authPrivateRequests: boolean; + + /** + * Whether to use native WebSocket ping/pong frames for heartbeats + */ + useNativeHeartbeats: boolean; } ⋮---- -level: string; // Regular user Level, e.g. Lv1 -loanQuotaCoef: string; // Loan quota coefficient. Loan quota = quota * level -irDiscount: string; // Interest rate discount (Deprecated) +/** + * Whether to use native WebSocket ping/pong frames for heartbeats + */ ⋮---- -export interface ConfigCcyItem { - ccy: string; // Currency - rate: string; // Daily rate -} +export type WsEventInternalSrc = 'event' | 'function'; + +================ +File: src/index.ts +================ +// Top level REST types ⋮---- -ccy: string; // Currency -rate: string; // Daily rate +// REST/request ⋮---- -export interface LoanQuotaConfig { - ccy: string; // Currency - stgyType: string; // Strategy type: 0=general strategy, 1=delta neutral strategy. If only 0 is returned, loan quota is shared between strategies - quota: string; // Loan quota in absolute value - level: string; // VIP level -} +// REST/response ⋮---- -ccy: string; // Currency -stgyType: string; // Strategy type: 0=general strategy, 1=delta neutral strategy. If only 0 is returned, loan quota is shared between strategies -quota: string; // Loan quota in absolute value -level: string; // VIP level +// + +================ +File: src/types/rest/request/trade.ts +================ +import { + AlgoOrderState, + AlgoOrderType, + AlgoPositionSide, + InstrumentType, + MarginMode, + numberInString, + OrderSide, + OrderType, + PositionSide, + PriceTriggerType, + TradeMode, +} from '../shared.js'; ⋮---- -export interface InterestRateAndLoanQuota { - basic: BasicInterestRate[]; - vip: VIPInterestInfo[]; - regular: RegularUserInterestInfo[]; - configCcyList: ConfigCcyItem[]; // Currencies that have loan quota configured using customized absolute value - config: LoanQuotaConfig[]; // The currency details of loan quota configured using customized absolute value +export interface AlgoRecentHistoryRequest { + ordType: AlgoOrderType; + algoId?: string; + instType?: InstrumentType; + instId?: string; + after?: string; + before?: string; + limit?: string; } ⋮---- -configCcyList: ConfigCcyItem[]; // Currencies that have loan quota configured using customized absolute value -config: LoanQuotaConfig[]; // The currency details of loan quota configured using customized absolute value +export interface AlgoLongHistoryRequest { + ordType: AlgoOrderType; + state?: AlgoOrderState; + algoId?: string; + instType?: InstrumentType; + instId?: string; + after?: string; + before?: string; + limit?: string; +} ⋮---- /** - * @see GET /api/v5/public/market-data-history + * When amending an attached trailing stop via amend algo / attach block (2026-04-13). + * Only one of newCallbackRatio or newCallbackSpread. */ -export interface MarketDataHistoryFileGroup { - dateTs: string; - filename: string; - sizeMB: string; - url: string; +export interface AmendAttachedTrailingStop { + newCallbackRatio?: string; + newCallbackSpread?: string; + newActivePx?: string; } ⋮---- -export interface MarketDataHistoryGroupDetail { - instId: string; - instFamily: string; - instType: string; - dateRangeStart: string; - dateRangeEnd: string; - groupSizeMB: string; - groupDetails: MarketDataHistoryFileGroup[]; +interface AlgoTriggerOrder { + newTpTriggerPx?: string; + newTpTriggerPxType?: 'last' | 'index' | 'mark'; + newTpOrdPx?: string; + newSlTriggerPx?: string; + newSlTriggerPxType?: 'last' | 'index' | 'mark'; + newSlOrdPx?: string; + newCallbackRatio?: string; + newCallbackSpread?: string; + newActivePx?: string; } ⋮---- -export interface MarketDataHistoryResult { - dateAggrType: string; - details: MarketDataHistoryGroupDetail[]; - totalSizeMB: string; - ts: string; +/** + * TP/SL and trailing (move_order_stop) attached to a parent `order` (2026-04-13: callbackRatio | callbackSpread, activePx). + */ +export interface AttachAlgoOrdRequest { + attachAlgoClOrdId?: string; + tpTriggerPx?: string; + /** Only one of tpTriggerPx and tpTriggerRatio (FUTURES/SWAP). */ + tpTriggerRatio?: string; + tpOrdPx?: string; + tpOrdKind?: 'condition' | 'limit'; + slTriggerPx?: string; + slTriggerRatio?: string; + slOrdPx?: string; + tpTriggerPxType?: 'last' | 'index' | 'mark'; + slTriggerPxType?: 'last' | 'index' | 'mark'; + sz?: string; + amendPxOnTriggerType?: '0' | '1'; + /** + * Trailing stop: one of `callbackRatio` or `callbackSpread` when attached ordType is `move_order_stop`. + * e.g. 0.05 = 5% + */ + callbackRatio?: string; + /** Trailing: price distance (alternative to callbackRatio). */ + callbackSpread?: string; + /** Trailing: activation; omit = activate immediately. */ + activePx?: string; } ⋮---- -/** @see GET /api/v5/finance/staking-defi/eth/product-info */ -export interface EthStakingProductInfo { - fastRedemptionDailyLimit: string; - rate: string; - redemptDays: string; - minAmt: string; +/** Only one of tpTriggerPx and tpTriggerRatio (FUTURES/SWAP). */ +⋮---- +/** + * Trailing stop: one of `callbackRatio` or `callbackSpread` when attached ordType is `move_order_stop`. + * e.g. 0.05 = 5% + */ +⋮---- +/** Trailing: price distance (alternative to callbackRatio). */ +⋮---- +/** Trailing: activation; omit = activate immediately. */ +⋮---- +export interface AdvChaseParams { + chaseType?: string; + chaseVal?: string; + maxChaseType?: string; + maxChaseVal?: string; } ⋮---- -/** @see GET /api/v5/finance/staking-defi/sol/product-info */ -export interface SolStakingProductInfo { - fastRedemptionAvail: string; - fastRedemptionDailyLimit: string; - rate: string; - redemptDays: string; - minAmt: string; +export interface AdvChaseAmendParams { + newChaseVal?: string; + newMaxChaseVal?: string; } ⋮---- -/** - * @see GET /api/v5/public/event-contract/series - */ -export interface EventContractSettlement { - method: string; - closeEarly: boolean; - srcName: string; - underlying: string; +export interface AlgoOrderRequest { + instId: string; + tdMode: TradeMode; + ccy?: string; + side: OrderSide; + posSide?: AlgoPositionSide; + ordType: AlgoOrderType; + algoClOrdId?: string; + sz: numberInString; + tag?: string; + reduceOnly?: boolean; + tgtCcy?: string; + tpTriggerPx?: numberInString; + tpTriggerPxType?: PriceTriggerType; + tpOrdPx?: numberInString; + tpOrdKind?: string; + slTriggerPx?: numberInString; + slTriggerPxType?: PriceTriggerType; + slOrdPx?: numberInString; + cxlOnClosePos?: boolean; + triggerPx?: numberInString; + triggerPxType?: PriceTriggerType; + orderPx?: numberInString; + chaseType?: string; + chaseVal?: numberInString; + maxChaseType?: string; + maxChaseVal?: numberInString; + callbackRatio?: numberInString; + callbackSpread?: numberInString; + activePx?: numberInString; + pxVar?: numberInString; + pxSpread?: numberInString; + szLimit?: numberInString; + pxLimit?: numberInString; + timeInterval?: string; + quickMgnType?: string; + closeFraction?: numberInString; + advanceOrdType?: 'fok' | 'ioc' | 'chase' | ''; + /** Required when advanceOrdType is `chase` (FUTURES/SWAP trigger). */ + advChaseParams?: AdvChaseParams[]; + attachAlgoOrds?: AttachAlgoOrdRequest[]; } ⋮---- -export interface EventContractSeries { - seriesId: string; - freq: string; - title: string; - category: string; - settlement: EventContractSettlement; +/** Required when advanceOrdType is `chase` (FUTURES/SWAP trigger). */ +⋮---- +export interface AmendOrderRequest { + instId: string; + cxlOnFail?: boolean; + ordId?: string; + clOrdId?: string; + reqId?: string; + newSz?: string; + newPx?: string; + /** + * EVENTS: `"1"` for non-`post_only` amends when applicable. + * Ignored since 2026-07-24 (event-contract speed bump removed). + */ + speedBump?: string; + /** RPI taker access. Not inherited on amend - omit = false. Alias: isElpTakerAccess until 2026-10-31. */ + rpiTakerAccess?: boolean; + /** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ + isElpTakerAccess?: boolean; + /** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ + rpiPxRound?: boolean; + /** + * Amend attached trailing stop (or related attach algo) — only one of newCallbackRatio / newCallbackSpread per item (2026-04-13). + */ + attachAlgoOrds?: AmendAttachedTrailingStop[]; } ⋮---- /** - * @see GET /api/v5/public/event-contract/events - */ -export interface EventContractEvent { - seriesId: string; - eventId: string; - expTime: string; - state: string; - fixTime?: string; -} + * EVENTS: `"1"` for non-`post_only` amends when applicable. + * Ignored since 2026-07-24 (event-contract speed bump removed). + */ +⋮---- +/** RPI taker access. Not inherited on amend - omit = false. Alias: isElpTakerAccess until 2026-10-31. */ +⋮---- +/** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ +⋮---- +/** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ ⋮---- /** - * @see GET /api/v5/public/event-contract/markets - */ -export interface EventContractMarket { - seriesId: string; - eventId: string; + * Amend attached trailing stop (or related attach algo) — only one of newCallbackRatio / newCallbackSpread per item (2026-04-13). + */ +⋮---- +export type AlgoOrderDetailsRequest = + | { + algoId: string; + } + | { + algoClOrdId: string; + }; +⋮---- +export interface AmendAlgoOrderRequest { instId: string; - listTime: string; - expTime: string; - state: string; - fixTime: string; - outcome: string; - floorStrike: string; - /** Max expiration value for YES on `between` method. "INF" = no upper bound. "" for non-between. */ - capStrike?: string; - /** Hit direction when method is `hit`: up | dn | "". */ - hitDir?: string; - settleValue: string; - disputed: boolean; + algoId?: string; + algoClOrdId?: string; + cxlOnFail?: boolean; + reqId?: string; + newSz?: string; + newTpTriggerPx?: string; + newTpOrdPx?: string; + newSlTriggerPx?: string; + newSlOrdPx?: string; + newTpTriggerPxType?: 'last' | 'index' | 'mark'; + newSlTriggerPxType?: 'last' | 'index' | 'mark'; + newTriggerPx?: string; + newOrdPx?: string; + newTriggerPxType?: 'last' | 'index' | 'mark'; + /** Amend chase values on a pending trigger+chase order (pre-trigger). */ + advChaseParams?: AdvChaseAmendParams[]; + attachAlgoOrds?: AlgoTriggerOrder[]; } ⋮---- -/** Max expiration value for YES on `between` method. "INF" = no upper bound. "" for non-between. */ +/** Amend chase values on a pending trigger+chase order (pre-trigger). */ ⋮---- -/** Hit direction when method is `hit`: up | dn | "". */ +export interface CancelAlgoOrderRequest { + instId: string; + algoId?: string; + algoClOrdId?: string; +} ⋮---- -export interface MmInstrumentType { +export interface ClosePositionRequest { instId: string; - instType: string; - /** A | B-Crypto | B-TradFi */ - pairType: string; + posSide?: PositionSide; + mgnMode: MarginMode; + ccy?: string; + autoCxl?: boolean; + clOrdId?: string; + tag?: string; } ⋮---- -/** A | B-Crypto | B-TradFi */ +export interface FillsHistoryRequest { + instType?: InstrumentType; + uly?: string; + instId?: string; + ordId?: string; + after?: string; + before?: string; + begin?: string; + end?: string; + limit?: string; +} +⋮---- +export interface OrderIdRequest { + /** + * REST: use as in trade docs. WebSocket `cancel-order` / `batch-cancel-orders`: deprecated (2026-04-07) — if sent, ignored; use + * `ordId` or `clOrdId`. Optional `instIdCode` may still be used to map the instrument. + */ + instId?: string; + /** + * Where supported, may take precedence over `instId` if both are present. Get instruments to map. + */ + instIdCode?: number; + ordId?: string; + clOrdId?: string; +} +⋮---- +/** + * REST: use as in trade docs. WebSocket `cancel-order` / `batch-cancel-orders`: deprecated (2026-04-07) — if sent, ignored; use + * `ordId` or `clOrdId`. Optional `instIdCode` may still be used to map the instrument. + */ +⋮---- +/** + * Where supported, may take precedence over `instId` if both are present. Get instruments to map. + */ +⋮---- +export interface OrderHistoryRequest { + instType: InstrumentType; + uly?: string; + instId?: string; + ordType?: OrderType; + state?: string; + category?: string; + after?: string; + before?: string; + begin?: string; + end?: string; + limit?: string; +} +⋮---- +export interface OrderRequest { + instId: string; + tdMode: TradeMode; + ccy?: string; + clOrdId?: string; + tag?: string; + side: OrderSide; + posSide?: PositionSide; + ordType: OrderType; + /** Quantity to buy or sell */ + sz: numberInString; + px?: string; + /** Place options orders in USD. Only applicable to options. One of px/pxUsd/pxVol must be filled for option orders */ + pxUsd?: string; + /** Place options orders based on implied volatility, where 1 represents 100%. Only applicable to options */ + pxVol?: string; + reduceOnly?: boolean; + /** A spot buy on BTC-USDT with "base_ccy" would mean the QTY (sz) is in USDT */ + tgtCcy?: 'base_ccy' | 'quote_ccy'; + /** + * Maximum acceptable slippage for spot and spot margin market-side orders, where tgtCcy is the received currency (base_ccy for buy, quote_ccy for sell). + * Range: 0 to 0.05 (0% to 5%, inclusive). Up to 2 decimal places, e.g. 0.01 (1%) and 0.0123 (1.23%). Defaults to 0.00% if not specified. + * Only applicable to SPOT and SPOT margin market orders. Cannot be amended on an existing order. + */ + slippagePct?: string; + banAmend?: boolean; + /** Price amendment type: "0" = do not allow amendment, "1" = allow amendment within price limit. Default is "0" */ + pxAmendType?: '0' | '1'; + /** Quote currency used for trading. Only applicable to SPOT. Default is quote currency of instId */ + tradeQuoteCcy?: string; + /** Self trade prevention mode: cancel_maker, cancel_taker, cancel_both. Default is cancel_maker */ + stpMode?: 'cancel_maker' | 'cancel_taker' | 'cancel_both'; + /** + * RPI taker access for limit/market/fok/ioc. Default false. Speedbump when true. + * Alias `isElpTakerAccess` accepted until 2026-10-31. + */ + rpiTakerAccess?: boolean; + /** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ + isElpTakerAccess?: boolean; + /** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ + rpiPxRound?: boolean; + /** + * EVENTS: set to `"1"` for non-`post_only` orders. Error 54086 if missing when required. + * Ignored since 2026-07-24 (event-contract speed bump removed). + */ + speedBump?: string; + /** EVENTS: `yes` or `no`. */ + outcome?: string; + /** Take Profit & Stop Loss params */ + tpTriggerPx?: string; + tpOrdPx?: string; + slTriggerPx?: string; + slOrdPx?: string; + tpTriggerPxType?: PriceTriggerType; + slTriggerPxType?: PriceTriggerType; + /** TP/SL / trailing (attach) when placing the parent order */ + attachAlgoOrds?: AttachAlgoOrdRequest[]; + /** Quick margin type */ + quickMgnType?: 'manual' | 'auto_borrow' | 'auto_repay'; +} +⋮---- +/** Quantity to buy or sell */ +⋮---- +/** Place options orders in USD. Only applicable to options. One of px/pxUsd/pxVol must be filled for option orders */ +⋮---- +/** Place options orders based on implied volatility, where 1 represents 100%. Only applicable to options */ +⋮---- +/** A spot buy on BTC-USDT with "base_ccy" would mean the QTY (sz) is in USDT */ +⋮---- +/** + * Maximum acceptable slippage for spot and spot margin market-side orders, where tgtCcy is the received currency (base_ccy for buy, quote_ccy for sell). + * Range: 0 to 0.05 (0% to 5%, inclusive). Up to 2 decimal places, e.g. 0.01 (1%) and 0.0123 (1.23%). Defaults to 0.00% if not specified. + * Only applicable to SPOT and SPOT margin market orders. Cannot be amended on an existing order. + */ +⋮---- +/** Price amendment type: "0" = do not allow amendment, "1" = allow amendment within price limit. Default is "0" */ +⋮---- +/** Quote currency used for trading. Only applicable to SPOT. Default is quote currency of instId */ +⋮---- +/** Self trade prevention mode: cancel_maker, cancel_taker, cancel_both. Default is cancel_maker */ +⋮---- +/** + * RPI taker access for limit/market/fok/ioc. Default false. Speedbump when true. + * Alias `isElpTakerAccess` accepted until 2026-10-31. + */ +⋮---- +/** @deprecated Use `rpiTakerAccess`. Alias until 2026-10-31. */ +⋮---- +/** RPI maker spacing: auto-round price when true. Only for ordType rpi. */ +⋮---- +/** + * EVENTS: set to `"1"` for non-`post_only` orders. Error 54086 if missing when required. + * Ignored since 2026-07-24 (event-contract speed bump removed). + */ +⋮---- +/** EVENTS: `yes` or `no`. */ +⋮---- +/** Take Profit & Stop Loss params */ +⋮---- +/** TP/SL / trailing (attach) when placing the parent order */ +⋮---- +/** Quick margin type */ +⋮---- +export interface GetTransactionDetailsArchiveRequest { + year: string; + quarter: 'Q1' | 'Q2' | 'Q3' | 'Q4'; +} +⋮---- +export interface OrderPrecheckRequest { + instId: string; + tdMode: string; + side: string; + posSide?: string; + ordType: string; + sz: string; + px?: string; + reduceOnly?: boolean; + tgtCcy?: string; + /** EVENTS: `yes` / `no`. */ + outcome?: string; + attachAlgoOrds?: AttachAlgoOrdRequest[]; +} +⋮---- +/** EVENTS: `yes` / `no`. */ ================ -File: README.md +File: src/types/rest/response/public-data.ts ================ -# Node.js & Typescript OKX (OKEX) API & WebSocket SDK - -[![E2E Tests](https://github.com/sieblyio/okx-api/actions/workflows/e2etest.yml/badge.svg?branch=master)](https://github.com/sieblyio/okx-api/actions/workflows/e2etest.yml) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/sieblyio/okx-api) -[![npm downloads](https://img.shields.io/npm/dt/okx-api)][1] -[![npm version](https://img.shields.io/npm/v/okx-api)][1] -[![npm size](https://img.shields.io/bundlephobia/min/okx-api/latest)][1] -[![last commit](https://img.shields.io/github/last-commit/sieblyio/okx-api)][1] -[![CodeFactor](https://www.codefactor.io/repository/github/sieblyio/okx-api/badge)](https://www.codefactor.io/repository/github/sieblyio/okx-api) - -

- - - - SDK Logo - - -

- -[1]: https://www.npmjs.com/package/okx-api - -> [!TIP] -> Upcoming change: As part of the [Siebly.io](https://siebly.io/?ref=ghokx) brand, this SDK is now hosted under our [Siebly.io GitHub organisation](https://github.com/sieblyio). The migration is seamless and requires no user changes. - -Complete, updated & performant Node.js SDK for the OKX(OKEX) APIs and WebSockets: - -- Complete integration with OKX REST APIs, WebSockets & WebSocket APIs. -- TypeScript support (with type declarations for most API requests & responses). -- Over 100 end-to-end tests making real API calls & WebSocket connections, validating any changes before they reach npm. -- Supports all available OKX regions: - - OKX Global (www.okx.com), by default. - - OKX EEA (my.okx.com), by setting `market: 'EEA'`. - - OKX US (app.okx.com), by setting `market: 'US'`. -- Actively maintained with a modern, promise-driven interface. -- Robust WebSocket integration - - Configurable connection heartbeats (automatically detect failing connections). - - Automatic reconnect then resubscribe workflows. - - Automatic authentication and heartbeat handling. -- Supports WebSocket API in all supported regions & product groups: - - Use the WebsocketClient's event-driven `sendWSAPIRequest()` method, or; - - Use the WebsocketAPIClient for a REST-like experience. - - Use the WebSocket API like a REST API! - - Automatic routing to business vs private WebSocket endpoints. - - End to end types. - - See [examples/ws-api-client.ts](./examples/ws-api-client.ts) for a demonstration. -- Browser support (via webpack bundle - see "Browser Usage" below). -- QuickStart Guide: https://siebly.io/sdk/okx/javascript - -## Table of Contents - -- [Installation](#installation) -- [Issues & Discussion](#issues--discussion) -- [Related Projects](#related-projects) -- [Documentation](#documentation) -- [Contributions & Thanks](#contributions--thanks) -- [Structure](#structure) -- [Usage](#usage) - - [REST Client](#rest-client) - - [Requests & Responses](#requests--responses) - - [Example](#example) - - [WebSockets](#websockets) - - [Sending Orders via WebSockets](#sending-orders-via-websockets) - - [Receiving Realtime Data](#receiving-realtime-data) - - [Public Events](#public-events) - - [Private Events](#private-events) -- [Browser/Frontend Usage](#browserfrontend-usage) - - [Import](#import) - - [Webpack](#webpack) -- [Use with LLMs & AI](#use-with-llms--ai) -- [Contributions & Pull Requests](#contributions--pull-requests) -- [Used By](#used-by) -- [Star History](#star-history) - -## Installation - -```bash -npm install okx-api -``` - -## Issues & Discussion - -- Issues? Check the [issues tab](https://github.com/sieblyio/okx-api/issues). -- Discuss & collaborate with other node devs? Join our [Node.js Algo Traders](https://t.me/nodetraders) engineering community on telegram. -- Follow our announcement channel for real-time updates on [X/Twitter](https://x.com/sieblyio) - - - -## Related Projects - -Check out our JavaScript/TypeScript/Node.js SDKs & Projects: - -- Visit our website: [https://Siebly.io](https://siebly.io/?ref=gh) -- Try our REST API & WebSocket SDKs published on npmjs: - - [Bybit Node.js SDK: bybit-api](https://www.npmjs.com/package/bybit-api) - - [Kraken Node.js SDK: @siebly/kraken-api](https://www.npmjs.com/package/@siebly/kraken-api) - - [OKX Node.js SDK: okx-api](https://www.npmjs.com/package/okx-api) - - [Binance Node.js SDK: binance](https://www.npmjs.com/package/binance) - - [Gate (gate.com) Node.js SDK: gateio-api](https://www.npmjs.com/package/gateio-api) - - [Bitget Node.js SDK: bitget-api](https://www.npmjs.com/package/bitget-api) - - [Kucoin Node.js SDK: kucoin-api](https://www.npmjs.com/package/kucoin-api) - - [Coinbase Node.js SDK: coinbase-api](https://www.npmjs.com/package/coinbase-api) - - [Bitmart Node.js SDK: bitmart-api](https://www.npmjs.com/package/bitmart-api) -- Try my misc utilities: - - [OrderBooks Node.js: orderbooks](https://www.npmjs.com/package/orderbooks) - - [Crypto Exchange Account State Cache: accountstate](https://www.npmjs.com/package/accountstate) -- Check out my examples: - - [awesome-crypto-examples Node.js](https://github.com/tiagosiebler/awesome-crypto-examples) - - -## Documentation - -Most methods accept JS objects. These can be populated using parameters specified by okx's API documentation, or check the type definition in the rest-client class methods. - -- [RestClient](src/rest-client.ts) -- [OKX API Documentation](https://www.okx.com/docs-v5/en/#rest-api) -- [REST Endpoint Function List](./docs/endpointFunctionList.md) - -## Contributions & Thanks - -Support my efforts to make algo trading accessible to all - register with my referral links: - -- [Bybit](https://www.bybit.com/en-US/register?affiliate_id=9410&language=en-US&group_id=0&group_type=1) -- [Binance](https://www.binance.com/en/register?ref=20983262) -- [OKX](https://www.okx.com/join/18504944) - -For more ways to give thanks & support my efforts, visit [Contributions & Thanks](https://github.com/tiagosiebler/awesome-crypto-examples/wiki/Contributions-&-Thanks)! - -## Structure - -This project uses typescript. Resources are stored in 3 key structures: - -- [src](./src) - the whole connector written in typescript -- [lib](./lib) - the javascript version of the project (compiled from typescript). This should not be edited directly, as it will be overwritten with each release. This is also the version published to npm. -- [dist](./dist) - the packed bundle of the project for use in browser environments (manual, using webpack). -- [examples](./examples) - some implementation examples & demonstrations. Contributions are welcome! - ---- - -## Usage - -Create API credentials at okx - -- [OKX/account/API](https://www.okx.com/account/my-api) - -## REST Client - -### Requests & Responses - -- If your IDE doesn't have IntelliSense, check the [rest-client.ts](./src/rest-client.ts) for a list of methods, params & return types. -- Requests follow the same ordering and format as the categories in the [API docs](https://www.okx.com/docs-v5/en/#rest-api). -- Responses are parsed automatically for less nesting. Error responses are thrown in full: - - If the response looks successful (HTTP 200 and "code" in the response body === "0"), only the `data` property is directly (without the `code`, `data` & `msg` properties). - - If the response looks like an error (HTTP error OR the "code" property in the response does not equal "0"), the full response is thrown (including `code` and `msg` properties). See the interface for [APIResponse](./src/types/rest/shared.ts). - -### Example - -```ts -import { RestClient } from 'okx-api'; - -const client = new RestClient({ - apiKey: 'apiKeyHere', - apiSecret: 'apiSecretHere', - apiPass: 'apiPassHere', - // For Global users (www.okx.com), you don't need to set the market. - // It will use global by default. - // Not needed: market: 'GLOBAL', - - // For EEA users (my.okx.com), set market to "EEA": - // market: 'EEA', - - // For US users (app.okx.com), set market to "US": - // market: 'US', -}); - -// Submit a buy and sell market order -(async () => { - try { - const allBalances = await client.getBalance(); - console.log('All balances: ', allBalances); - - const buyResult = await client.submitOrder({ - instId: 'BTC-USDT', - ordType: 'market', - side: 'buy', - sz: '0.1', - tdMode: 'cash', - tgtCcy: 'base_ccy', - }); - console.log('buy order result: ', buyResult); - - const sellResult = await client.submitOrder({ - instId: 'BTC-USDT', - ordType: 'market', - side: 'sell', - sz: '0.1', - tdMode: 'cash', - tgtCcy: 'base_ccy', - }); - console.log('Sell order result: ', sellResult); - } catch (e) { - console.error('request failed: ', e); - } -})(); -``` - -## WebSockets - -This connector includes a high-performance Node.js, TypeScript & JavaScript WebSocket client for the OKX public & private WebSocket, including the OKX WebSocket API for order placement. API credentials are optional unless private streams will be used (such as account order updates). - -- If your IDE doesn't have IntelliSense, check the [websocket-client.ts](./src/websocket-client.ts) for a list of methods, params & return types. -- When subscribing to channels, only the "args" should be passed as an object or array when calling the websocket client subcribe() function: [API docs](https://www.okx.com/docs-v5/en/#websocket-api-subscribe). -- TypeScript recommended (but it is not required) for a richer experience: - ![typescript-subscribe](./docs/images/subscribe-with-typescript.gif) -- The ws client will automatically open connections as needed when subscribing to a channel. -- If the connection is lost for any reason, the ws client will detect this (via the connection heartbeats). It will then: - - Automatically teardown the dead connection. - - Automatically respawn a fresh connection. - - Automatically reauthenticate, if using private channels. - - Automatically resubscribe to previously subscribed topics. - - Resume producing events as before, without extra handling needed in your logic. -- The ws client will automatically authenticate if accounts are provided and a private channel is subscribed to. -- Up to 100 accounts are supported on the private connection, as per the [API docs](https://www.okx.com/docs-v5/en/#websocket-api-login). Authentication is automatic if accounts are provided. -- For examples in using the websocket client, check the examples in the repo: - - Private channels (account data): [examples/ws-private.ts](./examples/ws-private.ts) - - Public chanels (market data): [examples/ws-public.ts](./examples/ws-public.ts) - - These examples are written in TypeScript, so can be executed with ts-node for easy testing: - `ts-node examples/ws-private.ts` - - Or convert them to javascript: - - Change the `import { ... } from 'okx-api'` to `const { ... } = require('okx-api');` - - Rename the file to `ws-private.js` - - And execute with node: `node examples/ws-private.js` - -### Sending orders via WebSockets - -OKX supports some order management capabilities via a persisted WebSocket connection. This SDK supports this with two convenient approaches. - -The recommended route is to use the dedicated WebsocketAPIClient class, included with this SDK: - -- Dedicated functions for every available WebSocket API operation -- Fully typed requests and responses -- Asynchronous promisified wrapper around WS API commands. - -It looks & feels like a REST API client, but uses WebSockets, via the WebsocketClient's sendWSAPIRequest method (which you can use directly if you prefer). - -A simple example is below but for a more thorough example, check the example here: [./examples/ws-api-client.ts](./examples/ws-api-client.ts). - -```typescript -import { WebsocketAPIClient } from 'okx-api'; -// or if you prefer require: -// const { WebsocketAPIClient } = require("okx-api"); - -// For private events, all 3 of the following are required (per account): -const API_KEY = process.env.API_KEY_COM; -const API_SECRET = process.env.API_SECRET_COM; -const API_PASSPHRASE = process.env.API_PASSPHRASE_COM; - -// If running from CLI in unix, you can pass env vars as such: -// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts - -const wsClient = new WebsocketAPIClient({ - // For Global users (www.okx.com), you don't need to set the market. - // It will use global by default. - // Not needed: market: 'GLOBAL', - - // For EEA users (my.okx.com), set market to "EEA": - // market: 'EEA', - - // For US users (app.okx.com), set market to "US": - // market: 'US', - - accounts: [ - { - apiKey: API_KEY, - apiSecret: API_SECRET, - apiPass: API_PASSPHRASE, - }, - ], -}); - -async function start() { - // Optional: prepare the WebSocket API connection in advance. - // This happens automatically but you can do this early before making any API calls, to prevent delays from a cold start. - // await wsClient.connectWSAPI(); - +import { InstrumentType, numberInString } from '../shared.js'; +⋮---- +export interface Ticker { + instType: InstrumentType; + instId: string; + last: numberInString; + lastSz: numberInString; + askPx: numberInString; + askSz: numberInString; + bidPx: numberInString; + bidSz: numberInString; + open24h: numberInString; + high24h: numberInString; + low24h: numberInString; + volCcy24h: numberInString; + vol24h: numberInString; + sodUtc0: numberInString; + sodUtc8: numberInString; + ts: numberInString; +} +⋮---- +export interface IndexTicker { + instId: string; + idxPx: string; + high24h: string; + sodUtc0: string; + open24h: string; + low24h: string; + sodUtc8: string; + ts: string; +} +⋮---- +type OBPrice = string; +type OBAssetQty = string; +type OBOrderCount = string; +type OrderBookLevel = [OBPrice, OBAssetQty, '0', OBOrderCount]; +⋮---- +export interface OrderBook { + asks: OrderBookLevel[]; + bids: OrderBookLevel[]; + ts: string; +} +⋮---- +/** RPI consolidated book level: [price, totalQty, nonRpiQty, count] */ +type OrderBookRpiLevel = [string, string, string, string]; +⋮---- +export interface OrderBookRpi { + asks: OrderBookRpiLevel[]; + bids: OrderBookRpiLevel[]; + ts: string; + seqId: number; +} +⋮---- +type timestamp = string; +type openPrice = string; +type highPrice = string; +type lowPrice = string; +type closePrice = string; +type vol = string; +type volCcy = string; +type volCcyQuote = string; +type confirm = string; +⋮---- +export type Candle = [ + timestamp, + openPrice, + highPrice, + lowPrice, + closePrice, + vol, + volCcy, + volCcyQuote, + confirm, +]; +⋮---- +export type CandleNoVolume = [ + timestamp, + openPrice, + highPrice, + lowPrice, + closePrice, +]; +⋮---- +export interface Trade { + instId: string; + side: string; + sz: string; + px: string; + tradeId: string; + ts: string; + source?: string; +} +⋮---- +export interface InstrumentUpcomingParamChange { + param: 'tickSz' | 'minSz' | 'maxMktSz' | string; + newValue: string; + effTime: string; +} +⋮---- +export interface Instrument { + instType: InstrumentType; + /** Series id for EVENTS, e.g. BTC-ABOVE-DAILY. */ + seriesId?: string; + instId: string; + uly: string; + instFamily: string; + category: string; + baseCcy: string; + quoteCcy: string; + settleCcy: string; + ctVal: string; + ctMult: string; + ctValCcy: string; + optType: string; + stk: string; + listTime: string; + contTdSwTime?: string; // Continuous trading switch time. The switch time from call auction/prequote to continuous trading. Unix timestamp format in milliseconds. + preMktSwTime?: string; // The time a pre-market instrument switches to normal trading, Unix ms. Applicable to pre-market SWAP and Pre-market X-Perp FUTURES. + expTime: string; + lever: string; + tickSz: string; + lotSz: string; + minSz: string; + ctType: string; /** - * OKX's WebSocket API be used like a REST API, through this SDK's WebsocketAPIClient. The WebsocketAPIClient is a utility class wrapped around WebsocketClient's sendWSAPIRequest() capabilities. - * - * Each request sent via the WebsocketAPIClient will automatically: - * - route via the active WS API connection - * - return a Promise, which automatically resolves/rejects when a matching response is received + * FUTURES contract label (deprecated — prefer `expTime` for delivery time; removal planned). + * Includes `this_five_years` / `next_five_years` (X-Perps / 5Y-style contracts). */ - + alias: string; /** - * Place Order - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order + * Instrument status: live, suspend, rebase (SWAP only), post_only (SWAP only), preopen, test, expired, settling (EVENTS), … */ - try { - const res = await wsClient.submitNewOrder({ - instId: 'BTC-USDT', - tdMode: 'cash', - side: 'buy', - ordType: 'market', - sz: '100', - }); - /** - const res = { - id: '2', - op: 'order', - code: '1', - msg: '', - data: [ - { - tag: '159881cb7207BCDE', - ts: '1753714603721', - ordId: '', - clOrdId: '', - sCode: '51008', - sMsg: 'Order failed. Insufficient USDT balance in account.' - } - ], - inTime: '1753714603720755', - outTime: '1753714603721942', - wsKey: 'prodPrivate', - isWSAPIResponse: false - } - - const res = { - id: '2', - op: 'order', - code: '1', - msg: '', - data: [ - { - tag: '159881cb7207BCDE', - ts: '1753714567149', - ordId: '', - clOrdId: '', - sCode: '51010', - sMsg: "You can't complete this request under your current account mode." - } - ], - inTime: '1753714567149196', - outTime: '1753714567149913', - wsKey: 'prodPrivate', - isWSAPIResponse: false - } - */ - - console.log(new Date(), 'WS API "submitNewOrder()" result: ', res); - } catch (e) { - console.error(new Date(), 'Exception with WS API "submitNewOrder()": ', e); - } - + state: string; + openType?: string; // Open type: fix_price (fix price opening), pre_quote (pre-quote), call_auction (call auction). Only applicable to SPOT/MARGIN. + maxLmtSz: string; + maxLmtAmt?: string; // Max USD amount for a single limit order + maxMktSz: string; + maxMktAmt?: string; // Max USD amount for a single market order. Only applicable to SPOT/MARGIN. + maxTwapSz: string; + maxIcebergSz: string; + maxTriggerSz: string; + maxStopSz: string; /** - * Submit multiple orders in a batch - * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-multiple-orders + * e.g. `normal`, `pre_market` (incl. Pre-market X-Perp FUTURES), `rebase_contract`, `xperp` (after Pre-market X-Perp converts). */ - try { - const res = await wsClient.submitMultipleOrders([ - { - instId: 'BTC-USDT', - tdMode: 'cash', - side: 'buy', - ordType: 'market', - sz: '100', - }, - { - instId: 'BTC-USDT', - tdMode: 'cash', - side: 'buy', - ordType: 'market', - sz: '50', - }, - ]); - console.log(new Date(), 'WS API "submitMultipleOrders()" result: ', res); - } catch (e) { - console.error( - new Date(), - 'Exception with WS API "submitMultipleOrders()": ', - e, - ); - } + ruleType: string; + auctionEndTime: string; + futureSettlement?: boolean; // Whether daily settlement for expiry feature is enabled. Applicable to FUTURES cross. + tradeQuoteCcyList?: string[]; // List of quote currencies available for trading, e.g. ["USD", "USDC"] + instIdCode?: number; // Instrument ID code. For simple binary encoding, must use instIdCode instead of instId. + /** + * Asset category of the instrument's base asset (first segment of `instId`). E.g. BTC-USDT-SWAP → category of BTC. + * 1: Crypto, 3: Stocks, 4: Commodities, 5: Forex, 6: Bonds, "": not available + */ + instCategory?: string; + posLmtAmt?: string; // Maximum position value (USD) for this instrument at the user level. Applicable to SWAP/FUTURES. + posLmtPct?: string; // Maximum position ratio (e.g., 30 for 30%) a user may hold relative to platform's current total position value. Applicable to SWAP/FUTURES. + longPosRemainingQuota?: string; + shortPosRemainingQuota?: string; + maxPlatOILmt?: string; // Platform-wide maximum position value (USD) for this instrument. Applicable to SWAP/FUTURES. + groupId?: string; // Instrument trading fee group ID + /** Minimum spacing between RPI bid and RPI ask, in organic price levels. Default 4; 0 for Event Contracts. */ + rpiMinLevel?: string; + /** Minimum distance from opposite-side organic best price for RPI spacing, in bps. */ + rpiMinPxBand?: string; + upcChg?: InstrumentUpcomingParamChange[]; +} +⋮---- +/** Series id for EVENTS, e.g. BTC-ABOVE-DAILY. */ +⋮---- +contTdSwTime?: string; // Continuous trading switch time. The switch time from call auction/prequote to continuous trading. Unix timestamp format in milliseconds. +preMktSwTime?: string; // The time a pre-market instrument switches to normal trading, Unix ms. Applicable to pre-market SWAP and Pre-market X-Perp FUTURES. +⋮---- +/** + * FUTURES contract label (deprecated — prefer `expTime` for delivery time; removal planned). + * Includes `this_five_years` / `next_five_years` (X-Perps / 5Y-style contracts). + */ +⋮---- +/** + * Instrument status: live, suspend, rebase (SWAP only), post_only (SWAP only), preopen, test, expired, settling (EVENTS), … + */ +⋮---- +openType?: string; // Open type: fix_price (fix price opening), pre_quote (pre-quote), call_auction (call auction). Only applicable to SPOT/MARGIN. +⋮---- +maxLmtAmt?: string; // Max USD amount for a single limit order +⋮---- +maxMktAmt?: string; // Max USD amount for a single market order. Only applicable to SPOT/MARGIN. +⋮---- +/** + * e.g. `normal`, `pre_market` (incl. Pre-market X-Perp FUTURES), `rebase_contract`, `xperp` (after Pre-market X-Perp converts). + */ +⋮---- +futureSettlement?: boolean; // Whether daily settlement for expiry feature is enabled. Applicable to FUTURES cross. +tradeQuoteCcyList?: string[]; // List of quote currencies available for trading, e.g. ["USD", "USDC"] +instIdCode?: number; // Instrument ID code. For simple binary encoding, must use instIdCode instead of instId. +/** + * Asset category of the instrument's base asset (first segment of `instId`). E.g. BTC-USDT-SWAP → category of BTC. + * 1: Crypto, 3: Stocks, 4: Commodities, 5: Forex, 6: Bonds, "": not available + */ +⋮---- +posLmtAmt?: string; // Maximum position value (USD) for this instrument at the user level. Applicable to SWAP/FUTURES. +posLmtPct?: string; // Maximum position ratio (e.g., 30 for 30%) a user may hold relative to platform's current total position value. Applicable to SWAP/FUTURES. +⋮---- +maxPlatOILmt?: string; // Platform-wide maximum position value (USD) for this instrument. Applicable to SWAP/FUTURES. +groupId?: string; // Instrument trading fee group ID +/** Minimum spacing between RPI bid and RPI ask, in organic price levels. Default 4; 0 for Event Contracts. */ +⋮---- +/** Minimum distance from opposite-side organic best price for RPI spacing, in bps. */ +⋮---- +export interface EconomicCalendarData { + calendarId: string; + date: string; + region: string; + category: string; + event: string; + refDate: string; + actual: string; + previous: string; + forecast: string; + dateSpan: string; + importance: string; + uTime: string; + prevInitial: string; + ccy: string; + unit: string; +} +⋮---- +export interface UnitConvertData { + type: '1' | '2'; + instId: string; + px: string; + sz: string; + unit: 'coin' | 'usds'; +} +⋮---- +/** + * @see GET /api/v5/public/funding-rate + * `instType` is `SWAP` (perp) or `FUTURES` (X-Perp) when applicable. + */ +export interface PublicFundingRate { + instType: string; + instId: string; + method: string; + formulaType: string; + fundingRate: string; + nextFundingRate: string; + fundingTime: string; + nextFundingTime: string; + minFundingRate: string; + maxFundingRate: string; + interestRate: string; + impactValue: string; + settState: string; + settFundingRate: string; + premium: string; + ts: string; +} +⋮---- +export interface InsuranceFundDetail { + ccy?: string; + bal?: string; + amt?: string; + type?: string; + maxBal?: string; + maxBalTs?: string; + decRate?: string; + adlType?: string; + adlBal?: string; + adlRecBal?: string; + /** @deprecated Returns "" per 2026-06-09 changelog */ + adlRate?: string; + /** @deprecated Returns "" per 2026-06-09 changelog */ + adlRecRate?: string; +} +⋮---- +/** @deprecated Returns "" per 2026-06-09 changelog */ +⋮---- +/** @deprecated Returns "" per 2026-06-09 changelog */ +⋮---- +export interface InsuranceFund { + instType?: string; + details: InsuranceFundDetail[]; +} +⋮---- +export interface FundingRateHistory { + /** Perpetual (`SWAP`) or X-Perp (`FUTURES`). */ + instType: string; + instId: string; + fundingRate: string; + realizedRate: string; + fundingTime: string; + method: string; + formulaType?: string; +} +⋮---- +/** Perpetual (`SWAP`) or X-Perp (`FUTURES`). */ +⋮---- +export interface SystemTime { + ts: string; +} +⋮---- +/** + * @see GET /api/v5/public/estimated-price + */ +export interface EstimatedDeliveryExercisePrice { + instType: string; + instId: string; + settlePx: string; + ts: string; +} +⋮---- +export interface OptionsTradeInfo { + instId: string; + tradeId: string; + px: string; + sz: string; + side: 'buy' | 'sell'; + ts: string; +} +⋮---- +export interface OptionTrade { + vol24h: string; + optType: 'C' | 'P'; + tradeInfo: OptionsTradeInfo[]; +} +⋮---- +export interface OptionTrades { + instId: string; + instFamily: string; + tradeId: string; + px: string; + sz: string; + side: 'buy' | 'sell'; + optType: 'C' | 'P'; + fillVol: string; + fwdPx: string; + idxPx: string; + markPx: string; + ts: string; +} +⋮---- +export interface Announcement { + annType: string; + pTime: string; // The actual time the announcement was first published. Unix timestamp format in milliseconds, e.g. 1597026383085 + businessPTime: string; // The time displayed on the announcement page for user reference. Unix timestamp format in milliseconds, e.g. 1597026383085 + title: string; + url: string; +} +⋮---- +pTime: string; // The actual time the announcement was first published. Unix timestamp format in milliseconds, e.g. 1597026383085 +businessPTime: string; // The time displayed on the announcement page for user reference. Unix timestamp format in milliseconds, e.g. 1597026383085 +⋮---- +/** Public borrow history record (GET /api/v5/finance/savings/lending-rate-history) */ +export interface PublicBorrowHistoryRecord { + ccy: string; // Currency, e.g. BTC + amt: string; // Lending amount (deprecated) + rate: string; // Annual borrowing interest rate + lendingRate: string; // Annual lending interest rate + ts: string; // Unix timestamp format in milliseconds +} +⋮---- +ccy: string; // Currency, e.g. BTC +amt: string; // Lending amount (deprecated) +rate: string; // Annual borrowing interest rate +lendingRate: string; // Annual lending interest rate +ts: string; // Unix timestamp format in milliseconds +⋮---- +export interface BasicInterestRate { + ccy: string; // Currency + rate: string; // Daily borrowing rate + quota: string; // Max borrow +} +⋮---- +ccy: string; // Currency +rate: string; // Daily borrowing rate +quota: string; // Max borrow +⋮---- +export interface VIPInterestInfo { + level: string; // VIP Level, e.g. VIP1 + loanQuotaCoef: string; // Loan quota coefficient. Loan quota = quota * level + irDiscount: string; // Interest rate discount (Deprecated) +} +⋮---- +level: string; // VIP Level, e.g. VIP1 +loanQuotaCoef: string; // Loan quota coefficient. Loan quota = quota * level +irDiscount: string; // Interest rate discount (Deprecated) +⋮---- +export interface RegularUserInterestInfo { + level: string; // Regular user Level, e.g. Lv1 + loanQuotaCoef: string; // Loan quota coefficient. Loan quota = quota * level + irDiscount: string; // Interest rate discount (Deprecated) +} +⋮---- +level: string; // Regular user Level, e.g. Lv1 +loanQuotaCoef: string; // Loan quota coefficient. Loan quota = quota * level +irDiscount: string; // Interest rate discount (Deprecated) +⋮---- +export interface ConfigCcyItem { + ccy: string; // Currency + rate: string; // Daily rate +} +⋮---- +ccy: string; // Currency +rate: string; // Daily rate +⋮---- +export interface LoanQuotaConfig { + ccy: string; // Currency + stgyType: string; // Strategy type: 0=general strategy, 1=delta neutral strategy. If only 0 is returned, loan quota is shared between strategies + quota: string; // Loan quota in absolute value + level: string; // VIP level +} +⋮---- +ccy: string; // Currency +stgyType: string; // Strategy type: 0=general strategy, 1=delta neutral strategy. If only 0 is returned, loan quota is shared between strategies +quota: string; // Loan quota in absolute value +level: string; // VIP level +⋮---- +export interface InterestRateAndLoanQuota { + basic: BasicInterestRate[]; + vip: VIPInterestInfo[]; + regular: RegularUserInterestInfo[]; + configCcyList: ConfigCcyItem[]; // Currencies that have loan quota configured using customized absolute value + config: LoanQuotaConfig[]; // The currency details of loan quota configured using customized absolute value +} +⋮---- +configCcyList: ConfigCcyItem[]; // Currencies that have loan quota configured using customized absolute value +config: LoanQuotaConfig[]; // The currency details of loan quota configured using customized absolute value +⋮---- +/** + * @see GET /api/v5/public/market-data-history + */ +export interface MarketDataHistoryFileGroup { + dateTs: string; + filename: string; + sizeMB: string; + url: string; +} +⋮---- +export interface MarketDataHistoryGroupDetail { + instId: string; + instFamily: string; + instType: string; + dateRangeStart: string; + dateRangeEnd: string; + groupSizeMB: string; + groupDetails: MarketDataHistoryFileGroup[]; +} +⋮---- +export interface MarketDataHistoryResult { + dateAggrType: string; + details: MarketDataHistoryGroupDetail[]; + totalSizeMB: string; + ts: string; +} +⋮---- +/** @see GET /api/v5/finance/staking-defi/eth/product-info */ +export interface EthStakingProductInfo { + fastRedemptionDailyLimit: string; + rate: string; + redemptDays: string; + minAmt: string; +} +⋮---- +/** @see GET /api/v5/finance/staking-defi/sol/product-info */ +export interface SolStakingProductInfo { + fastRedemptionAvail: string; + fastRedemptionDailyLimit: string; + rate: string; + redemptDays: string; + minAmt: string; +} +⋮---- +/** + * @see GET /api/v5/public/event-contract/series + */ +export interface EventContractSettlement { + method: string; + closeEarly: boolean; + srcName: string; + underlying: string; } - -start(); -``` - -### Receiving realtime data - -The below example demonstrates connecting as a consumer, to receive WebSocket events from OKX, using the included WebsocketClient: - -```javascript -import { WebsocketClient } from 'okx-api'; -// or if you prefer require: -// const { WebsocketClient } = require("okx-api"); - -// For private events, all 3 of the following are required (per account): -const API_KEY = process.env.API_KEY_COM; -const API_SECRET = process.env.API_SECRET_COM; -const API_PASSPHRASE = process.env.API_PASSPHRASE_COM; - -// If running from CLI in unix, you can pass env vars as such: -// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts - -// Note the single quotes, preventing special characters such as $ from being incorrectly passed - -const wsClient = new WebsocketClient({ - // For Global users (www.okx.com), you don't need to set the market. - // It will use global by default. - // Not needed: market: 'GLOBAL', - - // For EEA users (my.okx.com), set market to "EEA": - // market: 'EEA', - - // For US users (app.okx.com), set market to "US": - // market: 'US', - - accounts: [ - // For private topics, include one or more accounts in an array. Otherwise only public topics will work - { - apiKey: API_KEY, - apiSecret: API_SECRET, - apiPass: API_PASSPHRASE, - }, - // { - // apiKey: 'yourApiKeyHere', - // apiSecret: 'yourApiSecretHere', - // apiPass: 'yourApiPassHere', - // }, - // { - // apiKey: 'anotherAccountKey', - // apiSecret: 'anotherAccountSecret', - // apiPass: 'anotherAccountPass', - // }, - ], -}); - -// Raw data will arrive on the 'update' event -wsClient.on('update', (data) => { - console.log('ws update (raw data received)', JSON.stringify(data)); -}); - -wsClient.on('open', (data) => { - console.log('connection opened open:', data.wsKey); -}); - -// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event -wsClient.on('response', (data) => { - // console.log('ws response: ', JSON.stringify(data, null, 2)); - console.log('ws response: ', JSON.stringify(data)); -}); - -wsClient.on('reconnect', ({ wsKey }) => { - console.log('ws automatically reconnecting.... ', wsKey); -}); -wsClient.on('reconnected', (data) => { - console.log('ws has reconnected ', data?.wsKey); -}); -wsClient.on('exception', (data) => { - console.error('ws exception: ', data); -}); - +⋮---- +export interface EventContractSeries { + seriesId: string; + freq: string; + title: string; + category: string; + settlement: EventContractSettlement; +} +⋮---- /** - * Simply call subscribe to request the channels that you're interested in. - * - * If authentication is required, the WSClient will automatically authenticate with the available credentials. + * @see GET /api/v5/public/event-contract/events */ - -// Subscribe one event at a time: -wsClient.subscribe({ - channel: 'account', -}); - -// OR, combine multiple subscription events into one request using an array instead of an object: -wsClient.subscribe([ - { - channel: 'account', - }, - { - channel: 'positions', - instType: 'ANY', - }, -]); - -// Public topics, for comparison. These do not require authentication / api keys: -wsClient.subscribe([ - { - channel: 'instruments', - instType: 'SPOT', - }, - { - channel: 'instruments', - instType: 'FUTURES', - }, - { - channel: 'tickers', - instId: 'LTC-BTC', - }, -]); -``` - -#### Public Events - -See [examples/ws-public.ts](./examples/ws-public.ts) for a full example: - -![typescript-events-public](./docs/images/subscribe-events-public.gif) - -#### Private Events - -See [examples/ws-private.ts](./examples/ws-private.ts) for a full example: - -![typescript-events](./docs/images/subscribe-events.gif) - -## Browser/Frontend Usage - -### Import - -This is the "modern" way, allowing the package to be directly imported into frontend projects with full typescript support. - -1. Install these dependencies - ```sh - npm install crypto-browserify stream-browserify - ``` -2. Add this to your `tsconfig.json` - ```json - { - "compilerOptions": { - "paths": { - "crypto": [ - "./node_modules/crypto-browserify" - ], - "stream": [ - "./node_modules/stream-browserify" - ] - } - ``` -3. Declare this in the global context of your application (ex: in polyfills for angular) - ```js - (window as any).global = window; - ``` - -### Webpack - -This is the "old" way of using this package on webpages. This will build a minified js bundle that can be pulled in using a script tag on a website. - -Build a bundle using webpack: - -- `npm install` -- `npm build` -- `npm pack` - -The bundle can be found in `dist/`. Altough usage should be largely consistent, smaller differences will exist. Documentation is still TODO. - -## Use with LLMs & AI - -This SDK includes a bundled `llms.txt` file in the root of the repository. If you're developing with LLMs, use the included `llms.txt` with your LLM - it will significantly improve the LLMs understanding of how to correctly use this SDK. - -This file contains AI optimised structure of all the functions in this package, and their parameters for easier use with any learning models or artificial intelligence. - ---- - - - -### Contributions & Thanks - -Have my projects helped you? Share the love, there are many ways you can show your thanks: - -- Star & share my projects. -- Are my projects useful? Sponsor me on Github and support my effort to maintain & improve them: https://github.com/sponsors/tiagosiebler -- Have an interesting project? Get in touch & invite me to it. -- Or buy me all the coffee: - - ETH(ERC20): `0xA3Bda8BecaB4DCdA539Dc16F9C54a592553Be06C` -- Sign up with my referral links: - - OKX (receive a 20% fee discount!): https://www.okx.com/join/42013004 - - Binance (receive a 20% fee discount!): https://accounts.binance.com/register?ref=OKFFGIJJ - - HyperLiquid (receive a 4% fee discount!): https://app.hyperliquid.xyz/join/SDK - - Gate: https://www.gate.io/signup/NODESDKS?ref_type=103 - - - - -## Contributions & Pull Requests - -Contributions are encouraged, I will review any incoming pull requests. See the issues tab for todo items. - -## Used By - -The following represents some of the known public projects that use this SDK on GitHub: - -[![Repository Users Preview Image](https://dependents.info/sieblyio/okx-api/image)](https://github.com/sieblyio/okx-api/network/dependents) - - - -## Star History - -[![Star History Chart](https://api.star-history.com/svg?repos=tiagosiebler/bybit-api,sieblyio/okx-api,tiagosiebler/binance,tiagosiebler/bitget-api,tiagosiebler/bitmart-api,tiagosiebler/gateio-api,tiagosiebler/kucoin-api,tiagosiebler/coinbase-api,tiagosiebler/orderbooks,tiagosiebler/accountstate,tiagosiebler/awesome-crypto-examples&type=Date)](https://star-history.com/#tiagosiebler/bybit-api&sieblyio/okx-api&tiagosiebler/binance&tiagosiebler/bitget-api&tiagosiebler/bitmart-api&tiagosiebler/gateio-api&tiagosiebler/kucoin-api&tiagosiebler/coinbase-api&tiagosiebler/orderbooks&tiagosiebler/accountstate&tiagosiebler/awesome-crypto-examples&Date) - - +export interface EventContractEvent { + seriesId: string; + eventId: string; + expTime: string; + state: string; + fixTime?: string; +} +⋮---- +/** + * @see GET /api/v5/public/event-contract/markets + */ +export interface EventContractMarket { + seriesId: string; + eventId: string; + instId: string; + listTime: string; + expTime: string; + state: string; + fixTime: string; + outcome: string; + floorStrike: string; + /** Max expiration value for YES on `between` method. "INF" = no upper bound. "" for non-between. */ + capStrike?: string; + /** Hit direction when method is `hit`: up | dn | "". */ + hitDir?: string; + settleValue: string; + disputed: boolean; +} +⋮---- +/** Max expiration value for YES on `between` method. "INF" = no upper bound. "" for non-between. */ +⋮---- +/** Hit direction when method is `hit`: up | dn | "". */ +⋮---- +export interface MmInstrumentType { + instId: string; + instType: string; + /** A | B-Crypto | B-TradFi */ + pairType: string; +} +⋮---- +/** A | B-Crypto | B-TradFi */ +⋮---- +export interface DeltaHedgeCurrency { + ccy: string; + hedgeCcy: string[]; +} ================ File: src/types/rest/response/private-account.ts @@ -11600,6 +11002,7 @@ import { Announcement, Candle, CandleNoVolume, + DeltaHedgeCurrency, EconomicCalendarData, EstimatedDeliveryExercisePrice, EthStakingProductInfo, @@ -12959,6 +12362,10 @@ getMmInstrumentTypes(params?: { instId?: string; }): Promise ⋮---- +getDeltaHedgeCurrencies(params?: { + ccy?: string; +}): Promise +⋮---- getUnitConvert(params: UnitConvertRequest): Promise ⋮---- getOptionTickBands(params: { @@ -13524,92 +12931,703 @@ getGlpHistoricalPerformance( * @see https://www.okx.com/docs-v5/en/ (2026-05-08 release) * */ -⋮---- -getAffiliatePerformanceSummary( - params?: GetAffiliatePerformanceSummaryRequest, -): Promise -⋮---- -getInviteeDetail(params: GetInviteeDetailRequest): Promise -⋮---- -getAffiliateInviteeList( - params?: GetAffiliateInviteeListRequest, -): Promise -⋮---- -getAffiliateLinkList( - params?: GetAffiliateLinkListRequest, -): Promise -⋮---- -getAffiliateCoInviterLinkList( - params?: GetAffiliateCoInviterLinkListRequest, -): Promise -⋮---- -getAffiliateSubAffiliateList( - params?: GetAffiliateSubAffiliateListRequest, -): Promise -⋮---- -getAffiliateRebateInfo(params: -⋮---- -/** - * - * Status endpoints (public) - * +⋮---- +getAffiliatePerformanceSummary( + params?: GetAffiliatePerformanceSummaryRequest, +): Promise +⋮---- +getInviteeDetail(params: GetInviteeDetailRequest): Promise +⋮---- +getAffiliateInviteeList( + params?: GetAffiliateInviteeListRequest, +): Promise +⋮---- +getAffiliateLinkList( + params?: GetAffiliateLinkListRequest, +): Promise +⋮---- +getAffiliateCoInviterLinkList( + params?: GetAffiliateCoInviterLinkListRequest, +): Promise +⋮---- +getAffiliateSubAffiliateList( + params?: GetAffiliateSubAffiliateListRequest, +): Promise +⋮---- +getAffiliateRebateInfo(params: +⋮---- +/** + * + * Status endpoints (public) + * + */ +⋮---- +getSystemStatus(params: { + state?: 'scheduled' | 'ongoing' | 'pre_open' | 'completed' | 'canceled'; +}): Promise +⋮---- +/** + * + * Announcement endpoints + * + */ +⋮---- +getAnnouncements(params?: { annType?: string; page?: string }): Promise< + { + totalPage: string; + details: Announcement[]; + }[] + > { + return this.get('/api/v5/support/announcements', params); +⋮---- +getAnnouncementTypes(): Promise< + { + annType: string; + annTypeDesc: string; + }[] + > { + return this.get('/api/v5/support/announcement-types'); +⋮---- +/** + * + * Broker endpoints (private) + * + */ +⋮---- +createSubAccount(params: { + subAcct: string; + label?: string; + clientIP?: string; + mainAcct: string; +}): Promise +⋮---- +deleteSubAccount(params: +⋮---- +createSubAccountAPIKey(params: { + subAcct: string; + label: string; + passphrase: string; + ip?: string; + perm?: string; +}): Promise + +================ +File: README.md +================ +# Node.js & Typescript OKX (OKEX) API & WebSocket SDK + +[![E2E Tests](https://github.com/sieblyio/okx-api/actions/workflows/e2etest.yml/badge.svg?branch=master)](https://github.com/sieblyio/okx-api/actions/workflows/e2etest.yml) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/sieblyio/okx-api) +[![npm downloads](https://img.shields.io/npm/dt/okx-api)][1] +[![npm version](https://img.shields.io/npm/v/okx-api)][1] +[![npm size](https://img.shields.io/bundlephobia/min/okx-api/latest)][1] +[![last commit](https://img.shields.io/github/last-commit/sieblyio/okx-api)][1] +[![CodeFactor](https://www.codefactor.io/repository/github/sieblyio/okx-api/badge)](https://www.codefactor.io/repository/github/sieblyio/okx-api) + +

+ + + + SDK Logo + + +

+ +[1]: https://www.npmjs.com/package/okx-api + +> [!TIP] +> Upcoming change: As part of the [Siebly.io](https://siebly.io/?ref=ghokx) brand, this SDK is now hosted under our [Siebly.io GitHub organisation](https://github.com/sieblyio). The migration is seamless and requires no user changes. + +Complete, updated & performant Node.js SDK for the OKX(OKEX) APIs and WebSockets: + +- Complete integration with OKX REST APIs, WebSockets & WebSocket APIs. +- TypeScript support (with type declarations for most API requests & responses). +- Over 100 end-to-end tests making real API calls & WebSocket connections, validating any changes before they reach npm. +- Supports all available OKX regions: + - OKX Global (www.okx.com), by default. + - OKX EEA (my.okx.com), by setting `market: 'EEA'`. + - OKX US (app.okx.com), by setting `market: 'US'`. +- Actively maintained with a modern, promise-driven interface. +- Robust WebSocket integration + - Configurable connection heartbeats (automatically detect failing connections). + - Automatic reconnect then resubscribe workflows. + - Automatic authentication and heartbeat handling. +- Supports WebSocket API in all supported regions & product groups: + - Use the WebsocketClient's event-driven `sendWSAPIRequest()` method, or; + - Use the WebsocketAPIClient for a REST-like experience. + - Use the WebSocket API like a REST API! + - Automatic routing to business vs private WebSocket endpoints. + - End to end types. + - See [examples/ws-api-client.ts](./examples/ws-api-client.ts) for a demonstration. +- Browser support (via webpack bundle - see "Browser Usage" below). +- QuickStart Guide: https://siebly.io/sdk/okx/javascript +- OKX JavaScript Tutorial: https://siebly.io/sdk/okx/javascript/tutorial + +## Table of Contents + +- [Installation](#installation) +- [Issues & Discussion](#issues--discussion) +- [Related Projects](#related-projects) +- [Documentation](#documentation) +- [Contributions & Thanks](#contributions--thanks) +- [Structure](#structure) +- [Usage](#usage) + - [REST Client](#rest-client) + - [Requests & Responses](#requests--responses) + - [Example](#example) + - [WebSockets](#websockets) + - [Sending Orders via WebSockets](#sending-orders-via-websockets) + - [Receiving Realtime Data](#receiving-realtime-data) + - [Public Events](#public-events) + - [Private Events](#private-events) +- [Browser/Frontend Usage](#browserfrontend-usage) + - [Import](#import) + - [Webpack](#webpack) +- [Use with LLMs & AI](#use-with-llms--ai) +- [Contributions & Pull Requests](#contributions--pull-requests) +- [Used By](#used-by) +- [Star History](#star-history) + +## Installation + +```bash +npm install okx-api +``` + +## Issues & Discussion + +- Issues? Check the [issues tab](https://github.com/sieblyio/okx-api/issues). +- Discuss & collaborate with other node devs? Join our [Node.js Algo Traders](https://t.me/nodetraders) engineering community on telegram. +- Follow our announcement channel for real-time updates on [X/Twitter](https://x.com/sieblyio) + + + +## Related Projects + +Check out our JavaScript/TypeScript/Node.js SDKs & Projects: + +- Visit our website: [https://Siebly.io](https://siebly.io/) +- Try our REST API & WebSocket SDKs published on npmjs: + - [Bybit JavaScript SDK: bybit-api](https://www.npmjs.com/package/bybit-api) + - [Kraken JavaScript SDK: @siebly/kraken-api](https://www.npmjs.com/package/@siebly/kraken-api) + - [OKX JavaScript SDK: okx-api](https://www.npmjs.com/package/okx-api) + - [Binance JavaScript SDK: binance](https://www.npmjs.com/package/binance) + - [Gate (gate.com) JavaScript SDK: gateio-api](https://www.npmjs.com/package/gateio-api) + - [Bitget JavaScript SDK: bitget-api](https://www.npmjs.com/package/bitget-api) + - [Kucoin JavaScript SDK: kucoin-api](https://www.npmjs.com/package/kucoin-api) + - [Coinbase JavaScript SDK: coinbase-api](https://www.npmjs.com/package/coinbase-api) + - [HTX JavaScript SDK: @siebly/htx-api](https://www.npmjs.com/package/@siebly/htx-api) +- Try my misc utilities: + - [OrderBooks Node.js: orderbooks](https://www.npmjs.com/package/orderbooks) + - [Crypto Exchange Account State Cache: accountstate](https://www.npmjs.com/package/accountstate) +- Check out my examples: + - [awesome-crypto-examples Node.js](https://github.com/sieblyio/awesome-crypto-examples) + + +## Documentation + +Most methods accept JS objects. These can be populated using parameters specified by okx's API documentation, or check the type definition in the rest-client class methods. + +- [RestClient](src/rest-client.ts) +- [OKX API Documentation](https://www.okx.com/docs-v5/en/#rest-api) +- [REST Endpoint Function List](./docs/endpointFunctionList.md) + +## Contributions & Thanks + +Support my efforts to make algo trading accessible to all - register with my referral links: + +- [Bybit](https://www.bybit.com/en-US/register?affiliate_id=9410&language=en-US&group_id=0&group_type=1) +- [Binance](https://www.binance.com/en/register?ref=20983262) +- [OKX](https://www.okx.com/join/18504944) + +For more ways to give thanks & support my efforts, visit [Contributions & Thanks](https://github.com/sieblyio/awesome-crypto-examples/wiki/Contributions-&-Thanks)! + +## Structure + +This project uses typescript. Resources are stored in 3 key structures: + +- [src](./src) - the whole connector written in typescript +- [lib](./lib) - the javascript version of the project (compiled from typescript). This should not be edited directly, as it will be overwritten with each release. This is also the version published to npm. +- [dist](./dist) - the packed bundle of the project for use in browser environments (manual, using webpack). +- [examples](./examples) - some implementation examples & demonstrations. Contributions are welcome! + +--- + +## Usage + +Create API credentials at okx + +- [OKX/account/API](https://www.okx.com/account/my-api) + +## REST Client + +### Requests & Responses + +- If your IDE doesn't have IntelliSense, check the [rest-client.ts](./src/rest-client.ts) for a list of methods, params & return types. +- Requests follow the same ordering and format as the categories in the [API docs](https://www.okx.com/docs-v5/en/#rest-api). +- Responses are parsed automatically for less nesting. Error responses are thrown in full: + - If the response looks successful (HTTP 200 and "code" in the response body === "0"), only the `data` property is directly (without the `code`, `data` & `msg` properties). + - If the response looks like an error (HTTP error OR the "code" property in the response does not equal "0"), the full response is thrown (including `code` and `msg` properties). See the interface for [APIResponse](./src/types/rest/shared.ts). + +### Example + +```ts +import { RestClient } from 'okx-api'; + +const client = new RestClient({ + apiKey: 'apiKeyHere', + apiSecret: 'apiSecretHere', + apiPass: 'apiPassHere', + // For Global users (www.okx.com), you don't need to set the market. + // It will use global by default. + // Not needed: market: 'GLOBAL', + + // For EEA users (my.okx.com), set market to "EEA": + // market: 'EEA', + + // For US users (app.okx.com), set market to "US": + // market: 'US', +}); + +// Submit a buy and sell market order +(async () => { + try { + const allBalances = await client.getBalance(); + console.log('All balances: ', allBalances); + + const buyResult = await client.submitOrder({ + instId: 'BTC-USDT', + ordType: 'market', + side: 'buy', + sz: '0.1', + tdMode: 'cash', + tgtCcy: 'base_ccy', + }); + console.log('buy order result: ', buyResult); + + const sellResult = await client.submitOrder({ + instId: 'BTC-USDT', + ordType: 'market', + side: 'sell', + sz: '0.1', + tdMode: 'cash', + tgtCcy: 'base_ccy', + }); + console.log('Sell order result: ', sellResult); + } catch (e) { + console.error('request failed: ', e); + } +})(); +``` + +## WebSockets + +This connector includes a high-performance Node.js, TypeScript & JavaScript WebSocket client for the OKX public & private WebSocket, including the OKX WebSocket API for order placement. API credentials are optional unless private streams will be used (such as account order updates). + +- If your IDE doesn't have IntelliSense, check the [websocket-client.ts](./src/websocket-client.ts) for a list of methods, params & return types. +- When subscribing to channels, only the "args" should be passed as an object or array when calling the websocket client subcribe() function: [API docs](https://www.okx.com/docs-v5/en/#websocket-api-subscribe). +- TypeScript recommended (but it is not required) for a richer experience: + ![typescript-subscribe](./docs/images/subscribe-with-typescript.gif) +- The ws client will automatically open connections as needed when subscribing to a channel. +- If the connection is lost for any reason, the ws client will detect this (via the connection heartbeats). It will then: + - Automatically teardown the dead connection. + - Automatically respawn a fresh connection. + - Automatically reauthenticate, if using private channels. + - Automatically resubscribe to previously subscribed topics. + - Resume producing events as before, without extra handling needed in your logic. +- The ws client will automatically authenticate if accounts are provided and a private channel is subscribed to. +- Up to 100 accounts are supported on the private connection, as per the [API docs](https://www.okx.com/docs-v5/en/#websocket-api-login). Authentication is automatic if accounts are provided. +- For examples in using the websocket client, check the examples in the repo: + - Private channels (account data): [examples/ws-private.ts](./examples/ws-private.ts) + - Public chanels (market data): [examples/ws-public.ts](./examples/ws-public.ts) + - These examples are written in TypeScript, so can be executed with ts-node for easy testing: + `ts-node examples/ws-private.ts` + - Or convert them to javascript: + - Change the `import { ... } from 'okx-api'` to `const { ... } = require('okx-api');` + - Rename the file to `ws-private.js` + - And execute with node: `node examples/ws-private.js` + +### Sending orders via WebSockets + +OKX supports some order management capabilities via a persisted WebSocket connection. This SDK supports this with two convenient approaches. + +The recommended route is to use the dedicated WebsocketAPIClient class, included with this SDK: + +- Dedicated functions for every available WebSocket API operation +- Fully typed requests and responses +- Asynchronous promisified wrapper around WS API commands. + +It looks & feels like a REST API client, but uses WebSockets, via the WebsocketClient's sendWSAPIRequest method (which you can use directly if you prefer). + +A simple example is below but for a more thorough example, check the example here: [./examples/ws-api-client.ts](./examples/ws-api-client.ts). + +```typescript +import { WebsocketAPIClient } from 'okx-api'; +// or if you prefer require: +// const { WebsocketAPIClient } = require("okx-api"); + +// For private events, all 3 of the following are required (per account): +const API_KEY = process.env.API_KEY_COM; +const API_SECRET = process.env.API_SECRET_COM; +const API_PASSPHRASE = process.env.API_PASSPHRASE_COM; + +// If running from CLI in unix, you can pass env vars as such: +// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts + +const wsClient = new WebsocketAPIClient({ + // For Global users (www.okx.com), you don't need to set the market. + // It will use global by default. + // Not needed: market: 'GLOBAL', + + // For EEA users (my.okx.com), set market to "EEA": + // market: 'EEA', + + // For US users (app.okx.com), set market to "US": + // market: 'US', + + accounts: [ + { + apiKey: API_KEY, + apiSecret: API_SECRET, + apiPass: API_PASSPHRASE, + }, + ], +}); + +async function start() { + // Optional: prepare the WebSocket API connection in advance. + // This happens automatically but you can do this early before making any API calls, to prevent delays from a cold start. + // await wsClient.connectWSAPI(); + + /** + * OKX's WebSocket API be used like a REST API, through this SDK's WebsocketAPIClient. The WebsocketAPIClient is a utility class wrapped around WebsocketClient's sendWSAPIRequest() capabilities. + * + * Each request sent via the WebsocketAPIClient will automatically: + * - route via the active WS API connection + * - return a Promise, which automatically resolves/rejects when a matching response is received + */ + + /** + * Place Order + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-order */ -⋮---- -getSystemStatus(params: { - state?: 'scheduled' | 'ongoing' | 'pre_open' | 'completed' | 'canceled'; -}): Promise -⋮---- -/** - * - * Announcement endpoints - * + try { + const res = await wsClient.submitNewOrder({ + instId: 'BTC-USDT', + tdMode: 'cash', + side: 'buy', + ordType: 'market', + sz: '100', + }); + /** + const res = { + id: '2', + op: 'order', + code: '1', + msg: '', + data: [ + { + tag: '159881cb7207BCDE', + ts: '1753714603721', + ordId: '', + clOrdId: '', + sCode: '51008', + sMsg: 'Order failed. Insufficient USDT balance in account.' + } + ], + inTime: '1753714603720755', + outTime: '1753714603721942', + wsKey: 'prodPrivate', + isWSAPIResponse: false + } + + const res = { + id: '2', + op: 'order', + code: '1', + msg: '', + data: [ + { + tag: '159881cb7207BCDE', + ts: '1753714567149', + ordId: '', + clOrdId: '', + sCode: '51010', + sMsg: "You can't complete this request under your current account mode." + } + ], + inTime: '1753714567149196', + outTime: '1753714567149913', + wsKey: 'prodPrivate', + isWSAPIResponse: false + } + */ + + console.log(new Date(), 'WS API "submitNewOrder()" result: ', res); + } catch (e) { + console.error(new Date(), 'Exception with WS API "submitNewOrder()": ', e); + } + + /** + * Submit multiple orders in a batch + * https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-place-multiple-orders */ -⋮---- -getAnnouncements(params?: { annType?: string; page?: string }): Promise< - { - totalPage: string; - details: Announcement[]; - }[] - > { - return this.get('/api/v5/support/announcements', params); -⋮---- -getAnnouncementTypes(): Promise< + try { + const res = await wsClient.submitMultipleOrders([ + { + instId: 'BTC-USDT', + tdMode: 'cash', + side: 'buy', + ordType: 'market', + sz: '100', + }, + { + instId: 'BTC-USDT', + tdMode: 'cash', + side: 'buy', + ordType: 'market', + sz: '50', + }, + ]); + console.log(new Date(), 'WS API "submitMultipleOrders()" result: ', res); + } catch (e) { + console.error( + new Date(), + 'Exception with WS API "submitMultipleOrders()": ', + e, + ); + } +} + +start(); +``` + +### Receiving realtime data + +The below example demonstrates connecting as a consumer, to receive WebSocket events from OKX, using the included WebsocketClient: + +```javascript +import { WebsocketClient } from 'okx-api'; +// or if you prefer require: +// const { WebsocketClient } = require("okx-api"); + +// For private events, all 3 of the following are required (per account): +const API_KEY = process.env.API_KEY_COM; +const API_SECRET = process.env.API_SECRET_COM; +const API_PASSPHRASE = process.env.API_PASSPHRASE_COM; + +// If running from CLI in unix, you can pass env vars as such: +// API_KEY_COM='lkm12n3-2ba3-1mxf-fn13-lkm12n3a' API_SECRET_COM='035B2B9637E1BDFFEE2646BFBDDB8CE4' API_PASSPHRASE_COM='ComplexPa$$!23$5^' ts-node examples/ws-private.ts + +// Note the single quotes, preventing special characters such as $ from being incorrectly passed + +const wsClient = new WebsocketClient({ + // For Global users (www.okx.com), you don't need to set the market. + // It will use global by default. + // Not needed: market: 'GLOBAL', + + // For EEA users (my.okx.com), set market to "EEA": + // market: 'EEA', + + // For US users (app.okx.com), set market to "US": + // market: 'US', + + accounts: [ + // For private topics, include one or more accounts in an array. Otherwise only public topics will work { - annType: string; - annTypeDesc: string; - }[] - > { - return this.get('/api/v5/support/announcement-types'); -⋮---- + apiKey: API_KEY, + apiSecret: API_SECRET, + apiPass: API_PASSPHRASE, + }, + // { + // apiKey: 'yourApiKeyHere', + // apiSecret: 'yourApiSecretHere', + // apiPass: 'yourApiPassHere', + // }, + // { + // apiKey: 'anotherAccountKey', + // apiSecret: 'anotherAccountSecret', + // apiPass: 'anotherAccountPass', + // }, + ], +}); + +// Raw data will arrive on the 'update' event +wsClient.on('update', (data) => { + console.log('ws update (raw data received)', JSON.stringify(data)); +}); + +wsClient.on('open', (data) => { + console.log('connection opened open:', data.wsKey); +}); + +// Replies (e.g. authenticating or subscribing to channels) will arrive on the 'response' event +wsClient.on('response', (data) => { + // console.log('ws response: ', JSON.stringify(data, null, 2)); + console.log('ws response: ', JSON.stringify(data)); +}); + +wsClient.on('reconnect', ({ wsKey }) => { + console.log('ws automatically reconnecting.... ', wsKey); +}); +wsClient.on('reconnected', (data) => { + console.log('ws has reconnected ', data?.wsKey); +}); +wsClient.on('exception', (data) => { + console.error('ws exception: ', data); +}); + /** - * - * Broker endpoints (private) - * - */ -⋮---- -createSubAccount(params: { - subAcct: string; - label?: string; - clientIP?: string; - mainAcct: string; -}): Promise -⋮---- -deleteSubAccount(params: -⋮---- -createSubAccountAPIKey(params: { - subAcct: string; - label: string; - passphrase: string; - ip?: string; - perm?: string; -}): Promise + * Simply call subscribe to request the channels that you're interested in. + * + * If authentication is required, the WSClient will automatically authenticate with the available credentials. + */ + +// Subscribe one event at a time: +wsClient.subscribe({ + channel: 'account', +}); + +// OR, combine multiple subscription events into one request using an array instead of an object: +wsClient.subscribe([ + { + channel: 'account', + }, + { + channel: 'positions', + instType: 'ANY', + }, +]); + +// Public topics, for comparison. These do not require authentication / api keys: +wsClient.subscribe([ + { + channel: 'instruments', + instType: 'SPOT', + }, + { + channel: 'instruments', + instType: 'FUTURES', + }, + { + channel: 'tickers', + instId: 'LTC-BTC', + }, +]); +``` + +#### Public Events + +See [examples/ws-public.ts](./examples/ws-public.ts) for a full example: + +![typescript-events-public](./docs/images/subscribe-events-public.gif) + +#### Private Events + +See [examples/ws-private.ts](./examples/ws-private.ts) for a full example: + +![typescript-events](./docs/images/subscribe-events.gif) + +## Browser/Frontend Usage + +### Import + +This is the "modern" way, allowing the package to be directly imported into frontend projects with full typescript support. + +1. Install these dependencies + ```sh + npm install crypto-browserify stream-browserify + ``` +2. Add this to your `tsconfig.json` + ```json + { + "compilerOptions": { + "paths": { + "crypto": [ + "./node_modules/crypto-browserify" + ], + "stream": [ + "./node_modules/stream-browserify" + ] + } + ``` +3. Declare this in the global context of your application (ex: in polyfills for angular) + ```js + (window as any).global = window; + ``` + +### Webpack + +This is the "old" way of using this package on webpages. This will build a minified js bundle that can be pulled in using a script tag on a website. + +Build a bundle using webpack: + +- `npm install` +- `npm build` +- `npm pack` + +The bundle can be found in `dist/`. Altough usage should be largely consistent, smaller differences will exist. Documentation is still TODO. + +## Use with LLMs & AI + +This SDK includes a bundled `llms.txt` file in the root of the repository. If you're developing with LLMs, use the included `llms.txt` with your LLM - it will significantly improve the LLMs understanding of how to correctly use this SDK. + +This file contains AI optimised structure of all the functions in this package, and their parameters for easier use with any learning models or artificial intelligence. + +--- + + + +### Contributions & Thanks + +Have my projects helped you? Share the love, there are many ways you can show your thanks: + +- Star & share my projects. +- Are my projects useful? Sponsor me on Github and support my effort to maintain & improve them: https://github.com/sponsors/tiagosiebler +- Have an interesting project? Get in touch & invite me to it. +- Or buy me all the coffee: + - ETH(ERC20): `0xA3Bda8BecaB4DCdA539Dc16F9C54a592553Be06C` +- Sign up with my referral links: + - OKX (receive a 20% fee discount!): https://www.okx.com/join/42013004 + - Binance (receive a 20% fee discount!): https://accounts.binance.com/register?ref=OKFFGIJJ + - HyperLiquid (receive a 4% fee discount!): https://app.hyperliquid.xyz/join/SIEBLY + - Gate: https://www.gate.io/signup/NODESDKS?ref_type=103 + + + + +## Contributions & Pull Requests + +Contributions are encouraged, I will review any incoming pull requests. See the issues tab for todo items. + +## Used By + +The following represents some of the known public projects that use this SDK on GitHub: + +[![Repository Users Preview Image](https://dependents.info/sieblyio/okx-api/image)](https://github.com/sieblyio/okx-api/network/dependents) + + + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=sieblyio/bybit-api,sieblyio/okx-api,sieblyio/binance,sieblyio/bitget-api,sieblyio/bitmart-api,sieblyio/gateio-api,sieblyio/kucoin-api,sieblyio/coinbase-api,sieblyio/orderbooks,sieblyio/accountstate,sieblyio/awesome-crypto-examples&type=Date)](https://star-history.com/#sieblyio/bybit-api&sieblyio/okx-api&sieblyio/binance&sieblyio/bitget-api&sieblyio/bitmart-api&sieblyio/gateio-api&sieblyio/kucoin-api&sieblyio/coinbase-api&sieblyio/orderbooks&sieblyio/accountstate&sieblyio/awesome-crypto-examples&Date) + + ================ File: package.json ================ { "name": "okx-api", - "version": "3.2.2", + "version": "3.2.4", "description": "Complete Node.js SDK for OKX's REST APIs and WebSockets, with TypeScript & end-to-end tests", "scripts": { "test": "jest", @@ -13643,9 +13661,9 @@ File: package.json "author": "Tiago Siebler (https://siebly.io)", "contributors": [], "dependencies": { - "@types/ws": "^8.18.1", - "axios": "^1.13.2", - "isomorphic-ws": "^5.0.0", + "@types/ws": "8.18.1", + "axios": "1.18.1", + "isomorphic-ws": "5.0.0", "ws": "8.21.1" }, "devDependencies": { @@ -13667,6 +13685,14 @@ File: package.json "webpack": "^5.74.0", "webpack-cli": "^4.10.0" }, + "overrides": { + "brace-expansion@<2": "1.1.18", + "brace-expansion@>=2 <3": "2.1.4", + "brace-expansion@>=5 <6": "5.0.9", + "fast-uri@>=3 <4": "3.1.5", + "js-yaml@>=3 <4": "3.15.1", + "js-yaml@>=4 <5": "4.3.1" + }, "keywords": [ "okx", "okx api", @@ -13700,7 +13726,7 @@ File: package.json "bugs": { "url": "https://github.com/sieblyio/okx-api/issues" }, - "homepage": "https://github.com/sieblyio/okx-api#readme" + "homepage": "https://siebly.io/sdk/okx/javascript" } diff --git a/package-lock.json b/package-lock.json index 78c788b..6638da5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "okx-api", - "version": "3.2.3", + "version": "3.2.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "okx-api", - "version": "3.2.3", + "version": "3.2.4", "license": "MIT", "dependencies": { "@types/ws": "8.18.1", diff --git a/package.json b/package.json index a45abbe..878cece 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "okx-api", - "version": "3.2.3", + "version": "3.2.4", "description": "Complete Node.js SDK for OKX's REST APIs and WebSockets, with TypeScript & end-to-end tests", "scripts": { "test": "jest", diff --git a/src/rest-client.ts b/src/rest-client.ts index f14199b..9d7110d 100644 --- a/src/rest-client.ts +++ b/src/rest-client.ts @@ -369,6 +369,7 @@ import { Announcement, Candle, CandleNoVolume, + DeltaHedgeCurrency, EconomicCalendarData, EstimatedDeliveryExercisePrice, EthStakingProductInfo, @@ -2333,6 +2334,12 @@ export class RestClient extends BaseRestClient { return this.get('/api/v5/public/mm-instrument-types', params); } + getDeltaHedgeCurrencies(params?: { + ccy?: string; + }): Promise { + return this.get('/api/v5/public/delta-hedge-currencies', params); + } + getUnitConvert(params: UnitConvertRequest): Promise { return this.get('/api/v5/public/convert-contract-coin', params); } diff --git a/src/types/rest/response/public-data.ts b/src/types/rest/response/public-data.ts index ecfb785..fc3747b 100644 --- a/src/types/rest/response/public-data.ts +++ b/src/types/rest/response/public-data.ts @@ -447,3 +447,8 @@ export interface MmInstrumentType { /** A | B-Crypto | B-TradFi */ pairType: string; } + +export interface DeltaHedgeCurrency { + ccy: string; + hedgeCcy: string[]; +}