---
name: okx-cex-bot
description: Manage Grid bots (spot/contract/coin-margined) and DCA Martingale bots (Spot DCA 现货马丁 / Contract DCA 合约马丁) on OKX. Covers create, stop, amend, monitor P&L, TP/SL, margin/investment adjustment, and AI-recommended parameters. Requires API credentials. Not for regular orders (okx-cex-trade), market data (okx-cex-market), or account info (okx-cex-portfolio).
license: MIT
metadata:
  author: okx
  version: "1.4.6"
  homepage: "https://www.okx.com"
  agent:
    emoji: "🤖"
    requires:
      bins: ["okx"]
    install:
      - id: npm
        kind: node
        package: "@okx_ai/okx-trade-cli@1.4.6"
        bins: ["okx"]
        label: "Install okx CLI (npm)"
---

# OKX CEX Bot Trading

Grid and DCA (Spot & Contract Martingale) bot management on OKX. All bots are **native OKX server-side** — they run on OKX and do not require a local process.

## Preflight

Before running any command, follow [`../_shared/preflight.md`](../_shared/preflight.md).
Use `metadata.version` from this file's frontmatter as the reference for Step 2.

## Prerequisites

```bash
npm install -g @okx_ai/okx-trade-cli
okx config init   # select site -> follow browser OAuth flow
```

> **Security**: NEVER accept credentials in chat. Guide users to `okx config init` for setup.

## Credential & Profile Check

**Run before every authenticated command.** The auth method is detected during [preflight](../_shared/preflight.md) Step 2 and remembered for the session.

### Step A — Verify credentials

Run **both** commands — the `apiKey` field from `okx auth status --json` is the auth-binary's internal state and is always `false` regardless of whether `~/.okx/config.toml` has an API-key profile. `okx config show --json` is the only authoritative source for API-key presence.

```bash
okx config show --json      # reveals API-key profiles (TOML config)
okx auth status --json      # reveals OAuth session state (auth-binary state)
```

Apply **in this order** — first match wins:

- `config show --json` has any profile with a non-empty `api_key` field → **API Key mode**. Proceed to Step B.
- No API-key profile **AND** `auth status --json` returns `"status":"logged_in"` → **OAuth mode**. Proceed to Step B.
- No API-key profile **AND** `"status":"pending"` — login is in progress, wait for it to complete.
- No API-key profile **AND** `"status":"not_logged_in"` — stop, load `okx-cex-auth` skill and follow login steps, wait for completion.

### Step B — Confirm trading mode

Resolution:
1. User intent is clear ("real"/"实盘"/"live" → live; "test"/"模拟"/"demo" → demo) → use it, inform user
2. No explicit declaration → check conversation context for previous choice → reuse if found
3. Nothing found → ask: "Live (实盘) or Demo (模拟盘)?" — wait before proceeding

**How to apply the mode depends on auth method (detected in Step A):**

| Auth method | Live (实盘) | Demo (模拟盘) |
|---|---|---|
| **API Key** | `--profile <live-profile>` | `--profile <demo-profile>` |
| **OAuth** | *(no flag needed, live is default)* | `--demo` |

- **API Key users**: run `okx config show --json` to discover available profile names and their `demo` settings.
- **OAuth users**: omit flags for live; add `--demo` for simulated trading.

**After every command**: append `[mode: live]` or `[mode: demo]`

### Handling 401 Errors

**Authentication error** (error contains "401", "Session expired", or "Run `okx auth login` first"):
1. Stop immediately
2. Load `okx-cex-auth` skill and follow re-authentication steps
3. Retry original command

## Skill Routing

| Need | Skill |
|---|---|
| Market data, prices, depth | `okx-cex-market` |
| Account balance, positions, fees | `okx-cex-portfolio` |
| Regular spot/swap/futures orders | `okx-cex-trade` |
| **Grid / DCA bots** | **`okx-cex-bot` (this skill)** |

## Command Index

### Grid Bot

| Command | Type | Description |
|---|---|---|
| `okx bot grid create` | WRITE | Create a grid bot (spot or contract) |
| `okx bot grid amend` | WRITE | Amend price range, grid count, or TP/SL of a running grid bot |
| `okx bot grid stop` | WRITE | Stop a grid bot |
| `okx bot grid positions` | READ | Query open contract-grid positions (liquidation price, margin ratio, unrealized PnL) |
| `okx bot grid liquidate-price` | READ | Estimate liquidation price for a contract-grid bot |
| `okx bot grid close-position` | WRITE | Close remaining position after bot stopped with stopType=2 |
| `okx bot grid orders` | READ | List active or history grid bots |
| `okx bot grid details` | READ | Grid bot details + PnL |
| `okx bot grid sub-orders` | READ | Individual grid fills or pending orders |

### DCA Bot (Spot & Contract)

| Command | Type | Description |
|---|---|---|
| `okx bot dca create` | WRITE | Create a DCA (Martingale) bot (spot or contract) |
| `okx bot dca stop` | WRITE | Stop a DCA bot (spot or contract) |
| `okx bot dca orders` | READ | List active or history DCA bots (default: contract_dca) |
| `okx bot dca details` | READ | DCA bot details + PnL |
| `okx bot dca sub-orders` | READ | DCA cycles and orders within a cycle |

## Operation Flow

### Step 1 — Identify bot type and action

Parse user request → determine module (Grid / DCA) and action (create / stop / list / details).

### Step 2 — Execute

**READ commands** (orders, details, sub-orders): run immediately after profile confirmation.

**WRITE commands** (create, amend, stop): confirm key parameters with user once before executing.

### Step 3 — Verify after writes

- After create → run the corresponding `orders` command to confirm active
- After amend → run `bot grid details` to confirm updated config
- After stop → run `orders --history` to confirm stopped

## Key Rules

- **Never auto-transfer funds.** If balance is insufficient for bot creation, report the shortfall (current available vs required) and ask the user how to proceed: (1) transfer funds manually, (2) reduce size, or (3) cancel.
- **`algoId`** is the bot's algo order ID (from create or list output). It is NOT a normal `ordId`. Never fabricate — always obtain from a prior command.
- **`algoOrdType`** for grid must match the bot's actual type. Always use the value from `bot grid orders` — do not infer from user description alone. Mismatch causes error `50016`.
- When operating on existing bots, **always list first** to get correct IDs, unless the user provides them explicitly.
- **TP/SL constraints**: `tpTriggerPx`/`tpRatio` and `slTriggerPx`/`slRatio` are mutually exclusive pairs.

## CLI Command Reference

### Grid Bot — Create

```bash
okx bot grid create --instId <id> --algoOrdType <type> \
  --maxPx <px> --minPx <px> --gridNum <n> \
  [--runType <1|2>] \
  [--quoteSz <n>] [--baseSz <n>] \
  [--direction <long|short|neutral>] [--lever <n>] [--sz <n>] \
  [--basePos] [--no-basePos] \
  [--tpTriggerPx <px>] [--slTriggerPx <px>] [--tpRatio <ratio>] [--slRatio <ratio>] \
  [--algoClOrdId <id>] [--json]
```

| Param | Required | Default | Description |
|---|---|---|---|
| `--instId` | Yes | - | Instrument (e.g., `BTC-USDT` for spot, `BTC-USDT-SWAP` for USDT-M contract, `BTC-USD-SWAP` for coin-M contract) |
| `--algoOrdType` | Yes | - | `grid` (spot grid) or `contract_grid` (contract grid, including coin-margined) |
| `--maxPx` | Yes | - | Upper price boundary |
| `--minPx` | Yes | - | Lower price boundary |
| `--gridNum` | Yes | - | Grid levels (2–100) |
| `--runType` | No | `1` | `1`=arithmetic spacing, `2`=geometric spacing |
| `--quoteSz` | Cond. | - | USDT investment — spot grid only (provide `quoteSz` or `baseSz`) |
| `--baseSz` | Cond. | - | Base currency investment — spot grid only |
| `--direction` | Cond. | - | `long`, `short`, or `neutral` — required for contract grid |
| `--lever` | Cond. | - | Leverage (e.g., `5`) — contract grid only |
| `--sz` | Cond. | - | Investment margin in USDT (USDT-M) or coin (coin-M) — contract grid only |
| `--basePos` / `--no-basePos` | No | `true` | Open a base position at creation — contract grid only (ignored for neutral). Use `--no-basePos` to disable |
| `--tpTriggerPx` | No | - | Take-profit trigger price (mutually exclusive with `--tpRatio`) |
| `--slTriggerPx` | No | - | Stop-loss trigger price (mutually exclusive with `--slRatio`) |
| `--tpRatio` | No | - | Take-profit ratio — contract grid only (mutually exclusive with `--tpTriggerPx`) |
| `--slRatio` | No | - | Stop-loss ratio — contract grid only (mutually exclusive with `--slTriggerPx`) |
| `--algoClOrdId` | No | - | Client-defined algo order ID (1-32 alphanumeric). Unique per user, enables idempotent creation |

---

### Grid Bot — Amend

```bash
okx bot grid amend --algoId <id> \
  [--maxPx <px> --minPx <px> --gridNum <n>] \
  [--instId <id>] \
  [--tpTriggerPx <px>] [--slTriggerPx <px>] \
  [--tpRatio <ratio>] [--slRatio <ratio>] \
  [--topUpAmt <n>] [--json]
```

Supports two modes that can be combined in one call:

**Price-range mode** — triggered when `--maxPx` is provided:

| Param | Required | Description |
|---|---|---|
| `--algoId` | Yes | Grid bot algo order ID |
| `--maxPx` | Yes | New upper price boundary |
| `--minPx` | Yes (with maxPx) | New lower price boundary |
| `--gridNum` | Yes (with maxPx) | New grid count (integer) |
| `--topUpAmt` | No | Extra margin to add (contract grid only; omit to auto-use minimum required) |

**TP/SL mode** — triggered when at least one TP/SL param is provided; `--instId` is also required:

| Param | Required | Description |
|---|---|---|
| `--instId` | Yes | Instrument ID (e.g., `BTC-USDT`) |
| `--tpTriggerPx` | No | Take-profit trigger price (absolute). Pass `-1` to clear |
| `--slTriggerPx` | No | Stop-loss trigger price (absolute). Pass `-1` to clear |
| `--tpRatio` | No | Take-profit ratio (e.g., `0.1` = 10%). Contract grid only. Pass `-1` to clear |
| `--slRatio` | No | Stop-loss ratio (e.g., `0.1` = 10%). Contract grid only. Pass `-1` to clear |
| `--topUpAmt` | No | Extra margin to add (contract grid only) |

> **Note**: `tpTriggerPx`/`tpRatio` are mutually exclusive. Same for `slTriggerPx`/`slRatio`.

---

### Grid Bot — Stop

```bash
okx bot grid stop --algoId <id> --algoOrdType <type> --instId <id> \
  [--stopType <1|2>] [--json]
```

> **`--algoId`** and **`--algoOrdType`** must come from `bot grid orders` output. The `algoOrdType` must match the bot's actual type — do not guess.

**Workflow:**
1. Run `bot grid details --algoId <id> --algoOrdType <type>` and check the `state` field.
2. If `state=running`: call stop with `--stopType 1` (default, clean exit) or `--stopType 2` (keep assets).
3. If `state=no_close_position` (user previously stopped with stopType=2): call stop again with `--stopType 1` to close the remaining open position.

| `--stopType` | Spot grid | Contract grid |
|---|---|---|
| `1` (default) | Sells all base assets back to quote | Market-closes all open positions |
| `2` | Keeps base assets as-is | Cancels grid orders, leaves position open |

---

### Grid Bot — Positions

```bash
okx bot grid positions --algoId <id> --algoOrdType contract_grid [--json]
```

Returns open contract-grid positions: liquidation price (`liqPx`), margin ratio (`mgnRatio`), and unrealized PnL (`upl`). Only applicable to `contract_grid` bots.

---

### Grid Bot — Liquidation Price

```bash
okx bot grid liquidate-price --instId <id> --sz <margin> --lever <leverage> \
  --maxPx <px> --minPx <px> --gridNum <n> --direction <long|short|neutral> \
  [--runType <1|2>] [--triggerStrategy <instant|price|rsi|webhook>] [--json]
```

Estimates the liquidation price for a contract-grid bot. Use before creating a bot to assess liquidation risk. The estimate needs the **full intended config** — the backend requires `instId`, `sz`, `lever`, the grid range (`maxPx`/`minPx`/`gridNum`) and `direction` (use `neutral` for a neutral bot); omitting any of them fails fast with the list of what's missing. `runType` defaults to `1` (arithmetic; `2`=geometric) and `triggerStrategy` is optional.

---

### Grid Bot — Close Position

```bash
okx bot grid close-position --algoId <id> (--mktClose | --no-mktClose) [--sz <size>] [--px <price>] [--json]
```

Closes the remaining open position of a contract-grid bot that was stopped with `stopType='2'`. The close mode is **required** (no default, because it moves funds): pass `--mktClose` for a market close (immediate), or `--no-mktClose --sz <size> --px <price>` for a limit close order. Omitting both is rejected.

---

### Grid Bot — List Orders

```bash
okx bot grid orders --algoOrdType <type> [--instId <id>] [--algoId <id>] [--history] [--json]
```

| Param | Required | Default | Description |
|---|---|---|---|
| `--algoOrdType` | Yes | - | `grid` (spot), `contract_grid` (contract), or `moon_grid` (moon) |
| `--instId` | No | - | Filter by instrument |
| `--algoId` | No | - | Filter by algo order ID. NOT a normal trade order ID |
| `--history` | No | false | Show completed/stopped bots instead of active |

---

### Grid Bot — Details

```bash
okx bot grid details --algoOrdType <type> --algoId <id> [--json]
```

Returns: bot config, current PnL (`pnlRatio`), grid range, number of grids, state, position info.

---

### Grid Bot — Sub-Orders

```bash
okx bot grid sub-orders --algoOrdType <type> --algoId <id> [--pending] [--groupId <id>] [--after <id>] [--before <id>] [--limit <n>] [--json]
```

| Flag | Effect |
|---|---|
| *(default)* | Filled sub-orders (executed grid trades) |
| `--pending` | Pending grid orders currently on the book. (Works in demo mode. `--live` is a deprecated alias and cannot be combined with `--demo`.) |
| `--groupId` | Filter to one buy-sell pair (shared groupId) |
| `--after` | Pagination cursor — records older than this id |
| `--before` | Pagination cursor — records newer than this id |
| `--limit` | Max records to return (default 100) |

---

### DCA Bot — Create (Spot & Contract)

```bash
okx bot dca create --algoOrdType <spot_dca|contract_dca> --instId <id> --direction <long|short> \
  --initOrdAmt <n> --maxSafetyOrds <n> --tpPct <ratio> \
  [--lever <n>] [--safetyOrdAmt <n>] [--pxSteps <ratio>] [--pxStepsMult <mult>] [--volMult <mult>] \
  [--slPct <ratio>] [--slMode <limit|market>] [--allowReinvest] \
  [--triggerStrategy <instant|price|rsi>] [--triggerPx <price>] \
  [--triggerCond <cross_up|cross_down>] [--thold <threshold>] [--timeframe <timeframe>] [--timePeriod <period>] \
  [--algoClOrdId <id>] [--reserveFunds <true|false>] [--tradeQuoteCcy <ccy>] [--json]
```

| Param | Required | Default | Description |
|---|---|---|---|
| `--algoOrdType` | Yes | - | `spot_dca` (Spot DCA) or `contract_dca` (Contract DCA) |
| `--instId` | Yes | - | Instrument (e.g., `BTC-USDT` for spot, `BTC-USDT-SWAP` for contract) |
| `--lever` | Cond. | - | Leverage multiplier (e.g., `3`). Required for `contract_dca` |
| `--direction` | Yes | - | `long` or `short`. `spot_dca` must be `long` |
| `--initOrdAmt` | Yes | - | Initial order amount (quote currency) |
| `--maxSafetyOrds` | Yes | - | Max safety orders, integer [0, 100] (e.g., `3`; `0` = no DCA) |
| `--safetyOrdAmt` | Cond. | - | Safety order amount (quote currency). Required when `maxSafetyOrds > 0` |
| `--pxSteps` | Cond. | - | Initial price deviation [0.001, 0.5], e.g., `0.03` = 3%. Required when `maxSafetyOrds > 0` |
| `--pxStepsMult` | Cond. | `1` | Price step multiplier (e.g., `1.2`). Required when `maxSafetyOrds > 0` |
| `--volMult` | Cond. | `1` | Safety order size multiplier (e.g., `1.5`). Required when `maxSafetyOrds > 0` |
| `--tpPct` | Yes | - | Take-profit ratio: long [0.001, 10], short [0.001, 0.9999] (e.g., `0.03` = 3%) |
| `--slPct` | No | - | Stop-loss ratio, must exceed MPD (e.g., `0.05` = 5%). Must be used with `--slMode` |
| `--slMode` | No | `market` | Stop-loss type: `limit` or `market`. Must be used with `--slPct` |
| `--allowReinvest` | No | `true` | Reinvest profit into the next DCA cycle |
| `--triggerStrategy` | No | `instant` | contract_dca: `instant`, `price`, `rsi`; spot_dca: `instant`, `rsi` |
| `--triggerPx` | No | - | Trigger price — required when `triggerStrategy=price` (contract_dca only) |
| `--triggerCond` | No | - | `cross_up` or `cross_down` — required when `triggerStrategy=rsi`, optional when `triggerStrategy=price` |
| `--thold` | No | - | RSI threshold (e.g. `30`) — required when `triggerStrategy=rsi` |
| `--timeframe` | No | - | RSI timeframe (e.g. `15m`) — required when `triggerStrategy=rsi` |
| `--timePeriod` | No | `14` | RSI period — optional when `triggerStrategy=rsi` |
| `--algoClOrdId` | No | - | Client-defined strategy order ID (1-32 alphanumeric) |
| `--reserveFunds` | No | `true` | `true` or `false` — whether to reserve funds |
| `--tradeQuoteCcy` | No | - | Trade quote currency |

**Conditional required logic:**
- Always required: `--algoOrdType`, `--instId`, `--direction`, `--initOrdAmt`, `--maxSafetyOrds`, `--tpPct`
- When `algoOrdType=contract_dca`: also required `--lever`
- When `maxSafetyOrds > 0`: also required `--safetyOrdAmt`, `--pxSteps`, `--pxStepsMult`, `--volMult`
- `--slPct` and `--slMode` must be both set or both omitted

---

### DCA Bot — Stop

```bash
okx bot dca stop --algoOrdType <spot_dca|contract_dca> --algoId <id> [--stopType <1|2>] [--json]
```

**Workflow:**
1. Run `bot dca details --algoId <id> --algoOrdType <type>` and check the `state` field.
2. If `state=running`: call stop (with `--stopType` for spot_dca).
3. If `state=no_close_position` (user previously stopped with stopType=2): call stop again with `--stopType 1` to close the remaining open position.

| Param | Required | Default | Description |
|---|---|---|---|
| `--algoOrdType` | Yes | - | `spot_dca` or `contract_dca` |
| `--algoId` | Yes | - | DCA bot algo order ID (from create or list output). NOT a normal trade order ID |
| `--stopType` | Cond. | `1` | `spot_dca` required: `1`=sell all tokens, `2`=keep tokens. `contract_dca`: `1`=close position (default), `2`=keep position open |

---

### DCA Bot — List Orders

```bash
okx bot dca orders [--algoOrdType <spot_dca|contract_dca>] [--algoId <id>] [--instId <id>] [--history] [--json]
```

| Param | Required | Default | Description |
|---|---|---|---|
| `--algoOrdType` | No | `contract_dca` | Filter by strategy type |
| `--algoId` | No | - | Filter by DCA bot algo order ID |
| `--instId` | No | - | Filter by instrument |
| `--history` | No | false | Show completed/stopped bots instead of active |

---

### DCA Bot — Details

```bash
okx bot dca details --algoOrdType <spot_dca|contract_dca> --algoId <id> [--json]
```

Returns: `avgPx`, `upl`, `liqPx`, `sz`, `tpPx`, `slPx`, `initPx`, `fundingFee`, `fee`, `fillSafetyOrds`, `algoClOrdId`, `baseSz`, `quoteSz`, `tradeQuoteCcy`.

---

### DCA Bot — Sub-Orders

```bash
okx bot dca sub-orders --algoOrdType <spot_dca|contract_dca> --algoId <id> [--cycleId <id>] [--json]
```

| Flag / Param | Effect |
|---|---|
| *(default)* | List all cycles |
| `--cycleId <id>` | Show orders within a specific cycle |

## Quickstart

```bash
# Spot grid: BTC $90k–$100k, 10 grids, 1000 USDT
okx bot grid create --instId BTC-USDT --algoOrdType grid \
  --minPx 90000 --maxPx 100000 --gridNum 10 --quoteSz 1000

# Contract grid: BTC perp, neutral, 5x, 100 USDT margin
okx bot grid create --instId BTC-USDT-SWAP --algoOrdType contract_grid \
  --minPx 90000 --maxPx 100000 --gridNum 10 \
  --direction neutral --lever 5 --sz 100

# Coin-margined contract grid: BTC inverse perp
okx bot grid create --instId BTC-USD-SWAP --algoOrdType contract_grid \
  --minPx 90000 --maxPx 100000 --gridNum 10 \
  --direction long --lever 5 --sz 0.01

# Contract DCA bot: BTC perp, long, 3x, 3% TP
okx bot dca create --algoOrdType contract_dca --instId BTC-USDT-SWAP --lever 3 --direction long \
  --initOrdAmt 100 --safetyOrdAmt 50 --maxSafetyOrds 3 \
  --pxSteps 0.03 --pxStepsMult 1 --volMult 1 --tpPct 0.03

# Spot DCA bot: BTC spot, long, 5% TP
okx bot dca create --algoOrdType spot_dca --instId BTC-USDT --direction long \
  --initOrdAmt 100 --safetyOrdAmt 50 --maxSafetyOrds 3 \
  --pxSteps 0.03 --pxStepsMult 1.2 --vol