OKX · API Hands-On
Creating, querying and stopping an OKX grid bot through the v5 API
OKX's grid bots have a set of endpoints of their own. They all sit under /api/v5/tradingBot/grid/, separate from the regular order endpoint /api/v5/trade/order. To create a grid you send POST /api/v5/tradingBot/grid/order-algo: set algoOrdType to grid (spot grid) or contract_grid (a futures grid, which the docs call “Contract grid”), then give the upper price of the range maxPx, the lower price minPx, the number of grids gridNum and the amount to invest. A successful request returns an algoId (the algo order ID), and everything afterwards, whether checking state, amending parameters or stopping, runs on that ID.
To stop, send POST /api/v5/tradingBot/grid/stop-order-algo, where stopType is required: on a spot grid, 1 sells the base currency and 2 keeps it; on a futures grid, 1 closes everything at market and 2 stops without closing the position. Whether a grid is starting, running, waiting for a signal or already stopped is in the state field returned by three GET endpoints: the pending list, the history list and the details endpoint.
OKX grid trading API endpoints and their rate limits
This group sits in the Grid Trading section of the API docs, under Order Book Trading in the left-hand menu. The 13 endpoints in the table below are the ones you need for creating, querying, amending and stopping, and each is limited to 20 requests per 2 seconds. The create and instant-trigger endpoints are counted per User ID + Instrument ID, so the same account gets a fresh allowance on each trading pair; the other 11 are counted per User ID only, so every grid in the account shares it. The same section of the docs also has endpoints for calculating a margin adjustment, adjusting margin and adding to the investment.
| Endpoint | What it does | Applies to | Rate limit rule |
|---|---|---|---|
| POST /api/v5/tradingBot/grid/order-algo | Create a grid | Spot, futures | User ID + Instrument ID |
| POST /api/v5/tradingBot/grid/amend-algo-basic-param | Change the range and grid count | Spot, futures | User ID |
| POST /api/v5/tradingBot/grid/amend-order-algo | Change take-profit, stop-loss and stop conditions | Spot, futures | User ID |
| POST /api/v5/tradingBot/grid/stop-order-algo | Stop grids, up to 10 per request | Spot, futures | User ID |
| POST /api/v5/tradingBot/grid/close-position | Close the position of a grid that stopped without closing | Futures | User ID |
| POST /api/v5/tradingBot/grid/cancel-close-order | Cancel a grid's close order | Futures | User ID |
| POST /api/v5/tradingBot/grid/order-instant-trigger | Trigger a grid immediately | Spot, futures | User ID + Instrument ID |
| GET /api/v5/tradingBot/grid/orders-algo-pending | List of pending grids | Spot, futures | User ID |
| GET /api/v5/tradingBot/grid/orders-algo-history | List of past grids | Spot, futures | User ID |
| GET /api/v5/tradingBot/grid/orders-algo-details | Details of a single grid | Spot, futures | User ID |
| GET /api/v5/tradingBot/grid/sub-orders | Sub-orders the grid has placed | Spot, futures | User ID |
| GET /api/v5/tradingBot/grid/positions | Grid positions | Futures | User ID |
| POST /api/v5/tradingBot/grid/withdraw-income | Withdraw profit | Spot | User ID |
All of these are private endpoints that need a request signed with your API key; build the headers the way the signing instructions in the official API docs describe. If you have never placed a regular order through the API, start with OKX API Quant Starter: Create a Demo Key, Place and Cancel Your First Order.
Request parameters for creating a grid
Spot and futures grids share these parameters:
| Parameter | Required | Meaning and values |
|---|---|---|
| instId | Yes | Instrument ID; the docs' spot example uses BTC-USDT and the futures example BTC-USDT-SWAP |
| algoOrdType | Yes | grid: spot grid; contract_grid: futures grid |
| maxPx / minPx | Yes | Upper price / lower price of the range |
| gridNum | Yes | Number of grids |
| runType | No | Grid type, 1: arithmetic, 2: geometric; arithmetic if omitted |
| tpTriggerPx / slTriggerPx | No | Take-profit trigger price / stop-loss trigger price |
| algoClOrdId | No | Your own algo ID: letters and numbers, case-sensitive, up to 32 characters |
| tag | No | Order tag |
| triggerParams | No | Start and stop conditions, covered in the next section |
Spot and futures each add a few of their own:
| Parameter | Used for | Meaning and values |
|---|---|---|
| quoteSz | Spot | Amount of quote currency to invest; at least one of quoteSz and baseSz is needed |
| baseSz | Spot | Amount of base currency to invest; at least one of baseSz and quoteSz is needed |
| tradeQuoteCcy | Spot | Quote currency used for trading; if left out, the quote currency of instId is used |
| sz | Futures, required | Margin to invest, in USDT |
| direction | Futures, required | long, short or neutral |
| lever | Futures, required | Leverage |
| basePos | Futures | Whether to open a position when the bot starts; default false. A neutral contract grid should omit this parameter |
| tpRatio / slRatio | Futures | Take-profit ratio / stop-loss ratio; 0.1 stands for 10% |
In the docs, every one of these parameters is typed String except basePos, which is Boolean, and triggerParams, which is an array of objects. So the request body reads "gridNum": "10", and prices, amounts and leverage go in quotes the same way. Lead traders have one more parameter, profitSharingRatio (the profit-sharing ratio), which only accepts 0, 0.1, 0.2 or 0.3.
Take the docs' spot example, drop the trigger condition, and you have the simplest possible spot grid:
POST /api/v5/tradingBot/grid/order-algo
{
"instId": "BTC-USDT",
"algoOrdType": "grid",
"maxPx": "5000",
"minPx": "400",
"gridNum": "10",
"runType": "1",
"quoteSz": "25"
}
For a futures grid, swap quoteSz for sz and add the two required fields, direction and leverage. This one is adapted from the docs' example in the same way:
POST /api/v5/tradingBot/grid/order-algo
{
"instId": "BTC-USDT-SWAP",
"algoOrdType": "contract_grid",
"maxPx": "5000",
"minPx": "400",
"gridNum": "10",
"runType": "1",
"sz": "200",
"direction": "long",
"lever": "2"
}
Both examples keep the docs' runType of 1, an arithmetic grid. 5000, 400, 25 and 200 are demo values from the docs, not parameter suggestions; before sending a real request, replace them with a range and amounts you have set from the current market. For how to choose the range and grid count, see OKX Grid Bot Settings: Range, Grid Count, Funds Per Grid.
When the response comes back, check the outer code first, then the sCode of each item in data: 0 means success, and the algoId in the same item is this grid's algo order ID, so store it right away. If sCode isn't 0, the reason is in sMsg. If you sent an algoClOrdId, the response carries a field of the same name that you can reconcile against your local records.
Setting a grid's start and stop conditions with triggerParams
triggerParams is an array, with one condition per item. triggerAction is start (start the grid) or stop (stop the grid); triggerStrategy is instant (trigger immediately, the default), price (trigger on price) or rsi (trigger on the RSI indicator). Any item can also take delaySeconds, the number of seconds to wait after the action is triggered.
| triggerStrategy | Fields to send with it | Values |
|---|---|---|
| instant | None | — |
| price | triggerPx | Trigger price |
| rsi | timeframe | Candlestick interval: 3m, 5m, 15m, 30m, 1H, 4H, 1D |
| rsi | thold | Threshold, an integer from 1 to 100 |
| rsi | triggerCond | cross_up (crosses up), cross_down (crosses down), above, below, cross |
| rsi | timePeriod | Period; the value the docs give is 14 |
A stop condition can also carry stopType, which only takes effect when triggerAction is stop: on spot, 1 sells the base currency and 2 doesn't; on futures, 1 stops and closes the position and 2 stops without closing it.
The docs' futures example uses two conditions: a start that fires when the 14-period RSI on 30-minute candles crosses the threshold of 10, and a stop that fires when price reaches 1000 with stopType 2, so the position stays open after the stop.
"triggerParams":[
{
"triggerAction":"start",
"triggerStrategy":"rsi",
"timeframe":"30m",
"thold":"10",
"triggerCond":"cross",
"timePeriod":"14"
},
{
"triggerAction":"stop",
"triggerStrategy":"price",
"triggerPx":"1000",
"stopType":"2"
}
]
The pending list has a dedicated state for this, pending_signal (waiting for the trigger). To make a grid trigger immediately, call POST /api/v5/tradingBot/grid/order-instant-trigger with just the algoId; on a spot grid you can also pass topUpAmt in the same call to add to the investment.
Checking a grid's running state and stop reason through the API
Three endpoints report state. algoOrdType is required on all of them, and one call covers one type only, grid or contract_grid. An account running both spot and futures grids has to query once for each.
- Pending list
GET /api/v5/tradingBot/grid/orders-algo-pending?algoOrdType=grid: can be filtered byalgoId,instIdandinstType(SPOT, MARGIN, FUTURES, SWAP);limitis 100 at most and also 100 by default; pagination usesafter/before, which take analgoId. - History list
GET /api/v5/tradingBot/grid/orders-algo-history: same parameters, and the onlystateit returns isstopped. - Details
GET /api/v5/tradingBot/grid/orders-algo-details?algoId=…&algoOrdType=grid: both parameters are required, and it returns more fields than the lists do.
| state | Meaning | Returned by |
|---|---|---|
| starting | Starting | Pending list, details |
| running | Running | Pending list, details |
| stopping | Stopping | Pending list, details |
| pending_signal | Waiting for the trigger | Pending list |
| no_close_position | Stopped without closing the position; futures grids only | Pending list, details |
| stopped | Stopped | History list, details |
For a grid that has stopped, the reason is in cancelType: 0 none, 1 stopped manually, 2 stopped by take-profit, 3 stopped by stop-loss, 4 stopped by risk control, 5 stopped at delivery, 6 stopped by signal. Spot grids also have stopResult: 0 default, 1 the market sell of the coins succeeded, -1 the market sell failed. If you saw the stop in the app and want to match it against what the interface says, read OKX Grid Bot Stopped? First Work Out Which Kind of Stop It Is.
Among the extra fields on the details endpoint, the ones a script can put to use are runPx (price at launch), singleAmt (buy or sell amount per grid), activeOrdNum (number of live sub-orders) and tradeNum (number of fills). Spot grids also return curBaseSz / curQuoteSz (base and quote currency currently held) and profit (profit currently available to withdraw, in the quote currency). arbitrageNum (number of grid arbitrages), along with the futures grid fields liqPx (estimated liquidation price), actualLever (actual leverage) and availEq (available margin), is in the details and in the list endpoints as well. The time fields cTime and uTime are millisecond timestamps. The pending list, history list and details endpoints all return runType with the same values as the create request, so a 1 or 2 in a query result is read the same way.
To see exactly which orders a grid has placed, use GET /api/v5/tradingBot/grid/sub-orders. algoId, algoOrdType and type are all required; set type to live for unfilled orders or filled for filled ones, and paginate with the sub-order's ordId. For a futures grid's positions, use GET /api/v5/tradingBot/grid/positions, where algoOrdType can only be contract_grid.
stopType 1 sells or closes at market, stopType 2 keeps the coins or position
The stop endpoint takes an array as its request body and stops up to 10 grids per call. In each item, algoId, instId, algoOrdType and stopType are all required. The docs' example:
POST /api/v5/tradingBot/grid/stop-order-algo
[
{
"algoId":"448965992920907776",
"instId":"BTC-USDT",
"stopType":"1",
"algoOrdType":"grid"
}
]
| Grid type | stopType = 1 | stopType = 2 |
|---|---|---|
| Spot grid (grid) | Sell base currency | Keep base currency |
| Futures grid (contract_grid) | Market Close All positions | Keep positions |
With 1 on a spot grid, the base currency is sold at market; afterwards, check stopResult in the history list or the details. If it's -1 (the market sell failed), look in your trading account to see whether the coins are still there, then decide how to sell them yourself. If you only want the open orders gone and the coins kept for now, send 2.
With 2 on a futures grid, there is one more step. Put the stopType values next to the description of the close-position endpoint: a futures grid stopped with 2 is in no_close_position (stopped without closing the position), it still shows up in the pending list, and POST /api/v5/tradingBot/grid/close-position only accepts grids in that state. When closing, mktClose set to true closes everything at market; false is a partial close, and then both sz (in contracts) and px have to be sent. A partial close returns the close order's ordId (empty for a full market close); if you no longer want that order once it's placed, cancel it with POST /api/v5/tradingBot/grid/cancel-close-order, passing algoId and ordId.
OKX's Help Center FAQ on futures grid bots also states that a bot that has stopped can't be restarted and can't take any further investment; to keep going, close the position and create a new one. Both the spot and the futures FAQ in the Help Center note that a lead trader stopping manually can only choose to sell at market (spot) or close everything at market (futures).
Changing the range, adding funds and withdrawing profit while a grid runs
To change the range and grid count, use POST /api/v5/tradingBot/grid/amend-algo-basic-param. algoId, minPx, maxPx and gridNum are all required, so even if you only want a different grid count you have to send the range again unchanged. A futures grid can also pass topupAmount; leave it out or send "0" and the extra investment the change needs is added automatically. In the response, requiredTopupAmount is the amount this change needs topped up, and futures grids also get maxTopupAmount (the maximum top-up amount).
The Help Center's spot and futures FAQs describe editing parameters on a running bot the same way: after a core parameter changes, the bot cancels its existing orders and places new ones based on the new parameters and its current assets, with no need to stop first, and it may buy or sell at market along the way; the order group is reset, and grid profit that hasn't been withdrawn is reinvested. On a futures grid, if the market is moving sharply during the change and the bot holds few assets, the per-grid amount can work out to 0, and the bot then stops automatically.
The docs list several error codes for this endpoint:
| Error code | HTTP status | Error message in the docs |
|---|---|---|
| 51000 | 400 | Parameter {param} error. This would also be returned when a grid bot does not support the parameter |
| 51346 | 400 | Upper limit must be greater than the lower limit price. |
| 55123 | 400 | There is insufficient balance for transfer. |
| 55124 | 200 | Due to market fluctuations, your investment amount is insufficient to apply these modifications. |
| 55186 | 200 | Due to market fluctuations, your investment amount is too large to apply these modifications. |
55124 and 55186 come back with HTTP status 200. A script that only checks the status code will treat the change as successful, so always read code in the response body.
Take-profit, stop-loss and stop conditions are changed with POST /api/v5/tradingBot/grid/amend-order-algo, where algoId and instId are required. The parameter table says at least one of slTriggerPx and tpTriggerPx has to be sent, and that an empty string "" cancels the corresponding trigger price; tpRatio and slRatio only apply to futures grids, and "" cancels them too. The endpoint also has topUpAmt (the added investment), which applies to spot grids only. To replace the stop condition, send a new triggerParams in the same request, written the same way as at creation.
Profit on a spot grid is withdrawn with POST /api/v5/tradingBot/grid/withdraw-income. It takes only algoId, and the profit it returns is the amount withdrawn this time. You can check profit on the details endpoint (profit currently available to withdraw) beforehand. The Help Center's spot grid bot FAQ explains that grid profit isn't necessarily all withdrawable: part of it may already have gone into changed bot settings, added investment or profit reinvestment, or been withdrawn manually earlier, and part may be held back for later orders and for rounding differences that can't be withdrawn.
stopType 1 where you meant 2 and it sells the coins or closes everything at market, and what has already filled can't be undone. Sources: the Grid Trading section of the OKX API v5 docs, which the request examples are adapted from (the prices and amounts are its demo values and don't represent any account), and the OKX Help Center's spot grid bot FAQ and futures grid bot FAQ. This article is not investment advice. Only use money you can afford to lose entirely, and take responsibility for your own trading decisions.