@okx_ai/okx-trade-cli 1.2.6 → 1.2.7-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1524,7 +1524,8 @@ var BOT_DEFAULT_SUB_MODULES = ["bot.grid"];
1524
1524
  var EARN_SUB_MODULE_IDS = [
1525
1525
  "earn.savings",
1526
1526
  "earn.onchain",
1527
- "earn.dcd"
1527
+ "earn.dcd",
1528
+ "earn.autoearn"
1528
1529
  ];
1529
1530
  var MODULES = [
1530
1531
  "market",
@@ -2141,6 +2142,11 @@ function registerAlgoTradeTools() {
2141
2142
  type: "string",
2142
2143
  description: "Activation price; tracking starts after market reaches this level (move_order_stop only)"
2143
2144
  },
2145
+ tgtCcy: {
2146
+ type: "string",
2147
+ enum: ["base_ccy", "quote_ccy"],
2148
+ description: "Size unit. base_ccy(default): sz in contracts, quote_ccy: sz in USDT"
2149
+ },
2144
2150
  reduceOnly: {
2145
2151
  type: "boolean",
2146
2152
  description: "Ensure order only reduces position"
@@ -2164,6 +2170,7 @@ function registerAlgoTradeTools() {
2164
2170
  posSide: readString(args, "posSide"),
2165
2171
  ordType: requireString(args, "ordType"),
2166
2172
  sz: requireString(args, "sz"),
2173
+ tgtCcy: readString(args, "tgtCcy"),
2167
2174
  tpTriggerPx: readString(args, "tpTriggerPx"),
2168
2175
  tpOrdPx: readString(args, "tpOrdPx"),
2169
2176
  tpTriggerPxType: readString(args, "tpTriggerPxType"),
@@ -2468,6 +2475,11 @@ function registerFuturesAlgoTools() {
2468
2475
  type: "string",
2469
2476
  description: "Activation price; tracking starts after market reaches this level (move_order_stop only)"
2470
2477
  },
2478
+ tgtCcy: {
2479
+ type: "string",
2480
+ enum: ["base_ccy", "quote_ccy"],
2481
+ description: "Size unit. base_ccy(default): sz in contracts, quote_ccy: sz in USDT"
2482
+ },
2471
2483
  reduceOnly: {
2472
2484
  type: "boolean",
2473
2485
  description: "Ensure order only reduces position"
@@ -2491,6 +2503,7 @@ function registerFuturesAlgoTools() {
2491
2503
  posSide: readString(args, "posSide"),
2492
2504
  ordType: requireString(args, "ordType"),
2493
2505
  sz: requireString(args, "sz"),
2506
+ tgtCcy: readString(args, "tgtCcy"),
2494
2507
  tpTriggerPx: readString(args, "tpTriggerPx"),
2495
2508
  tpOrdPx: readString(args, "tpOrdPx"),
2496
2509
  tpTriggerPxType: readString(args, "tpTriggerPxType"),
@@ -2873,7 +2886,7 @@ function registerGridTools() {
2873
2886
  enum: ["active", "history"],
2874
2887
  description: "active=running (default); history=stopped"
2875
2888
  },
2876
- instId: { type: "string", description: "e.g. BTC-USDT" },
2889
+ instId: { type: "string", description: "e.g. BTC-USDT, BTC-USD-SWAP" },
2877
2890
  algoId: { type: "string", description: "Grid bot algo order ID (not a trade ordId)" },
2878
2891
  after: { type: "string", description: "Cursor for older records" },
2879
2892
  before: { type: "string", description: "Cursor for newer records" },
@@ -2978,12 +2991,12 @@ function registerGridTools() {
2978
2991
  {
2979
2992
  name: "grid_create_order",
2980
2993
  module: "bot.grid",
2981
- description: "Create grid bot. [CAUTION] Real trades, locks funds. Spot('grid'): need quoteSz|baseSz. Contract('contract_grid'): need direction+lever+sz.",
2994
+ description: "Create grid bot (spot, USDT-margined, or coin-margined contract). [CAUTION] Locks funds. Spot: quoteSz|baseSz. Contract: direction+lever+sz.",
2982
2995
  isWrite: true,
2983
2996
  inputSchema: {
2984
2997
  type: "object",
2985
2998
  properties: {
2986
- instId: { type: "string", description: "e.g. BTC-USDT" },
2999
+ instId: { type: "string", description: "e.g. BTC-USDT, BTC-USDT-SWAP, BTC-USD-SWAP (coin-margined)" },
2987
3000
  algoOrdType: {
2988
3001
  type: "string",
2989
3002
  enum: ["grid", "contract_grid"],
@@ -3005,8 +3018,13 @@ function registerGridTools() {
3005
3018
  description: "Contract only"
3006
3019
  },
3007
3020
  lever: { type: "string", description: "Leverage. Contract only" },
3008
- sz: { type: "string", description: "Margin amount. Contract only" },
3009
- basePos: { type: "boolean", description: "Open base position for contract. Default: true" }
3021
+ sz: { type: "string", description: "Margin in USDT or base coin (CoinM). Contract only" },
3022
+ basePos: { type: "boolean", description: "Open base position for contract. Default: true" },
3023
+ tpTriggerPx: { type: "string", description: "TP trigger price" },
3024
+ slTriggerPx: { type: "string", description: "SL trigger price" },
3025
+ tpRatio: { type: "string", description: "TP ratio e.g. 0.1=10%. Contract only" },
3026
+ slRatio: { type: "string", description: "SL ratio e.g. 0.1=10%. Contract only" },
3027
+ algoClOrdId: { type: "string", description: "User-defined ID. Alphanumeric, max 32, unique per user" }
3010
3028
  },
3011
3029
  required: ["instId", "algoOrdType", "maxPx", "minPx", "gridNum"]
3012
3030
  },
@@ -3025,9 +3043,15 @@ function registerGridTools() {
3025
3043
  direction: readString(args, "direction"),
3026
3044
  lever: readString(args, "lever"),
3027
3045
  sz: readString(args, "sz"),
3046
+ tpTriggerPx: readString(args, "tpTriggerPx"),
3047
+ slTriggerPx: readString(args, "slTriggerPx"),
3048
+ tpRatio: readString(args, "tpRatio"),
3049
+ slRatio: readString(args, "slRatio"),
3050
+ algoClOrdId: readString(args, "algoClOrdId"),
3028
3051
  tag: context.config.sourceTag
3029
3052
  });
3030
3053
  if (algoOrdType === "contract_grid") {
3054
+ requireString(args, "direction");
3031
3055
  body.triggerParams = [{ triggerAction: "start", triggerStrategy: "instant" }];
3032
3056
  body.basePos = readBoolean(args, "basePos") ?? true;
3033
3057
  }
@@ -3053,11 +3077,11 @@ function registerGridTools() {
3053
3077
  enum: ["grid", "contract_grid"],
3054
3078
  description: "grid=Spot, contract_grid=Contract"
3055
3079
  },
3056
- instId: { type: "string", description: "e.g. BTC-USDT" },
3080
+ instId: { type: "string", description: "e.g. BTC-USDT, BTC-USD-SWAP" },
3057
3081
  stopType: {
3058
3082
  type: "string",
3059
3083
  enum: ["1", "2", "3", "5", "6"],
3060
- description: "1=close all; 2=keep assets (default); 3=limit close; 5=partial; 6=no sell"
3084
+ description: "1=close all (default); 2=keep assets; 3=limit close; 5=partial; 6=no sell"
3061
3085
  }
3062
3086
  },
3063
3087
  required: ["algoId", "algoOrdType", "instId"]
@@ -3070,7 +3094,7 @@ function registerGridTools() {
3070
3094
  algoId: requireString(args, "algoId"),
3071
3095
  algoOrdType: requireString(args, "algoOrdType"),
3072
3096
  instId: requireString(args, "instId"),
3073
- stopType: readString(args, "stopType") ?? "2"
3097
+ stopType: readString(args, "stopType") ?? "1"
3074
3098
  })],
3075
3099
  privateRateLimit("grid_stop_order", 20)
3076
3100
  );
@@ -3107,32 +3131,44 @@ function registerDcaTools() {
3107
3131
  {
3108
3132
  name: "dca_create_order",
3109
3133
  module: "bot.dca",
3110
- description: "Create Contract DCA (Martingale) bot. [CAUTION] Real trades. When maxSafetyOrds > 0: also need safetyOrdAmt, pxSteps, pxStepsMult, volMult.",
3134
+ description: "Create a DCA (Martingale) bot. [CAUTION] Real trades. contract_dca requires lever; spot_dca must be long. If maxSafetyOrds>0: need safetyOrdAmt, pxSteps.",
3111
3135
  isWrite: true,
3112
3136
  inputSchema: {
3113
3137
  type: "object",
3114
3138
  properties: {
3115
- instId: { type: "string", description: "e.g. BTC-USDT-SWAP" },
3116
- lever: { type: "string", description: "Leverage, e.g. '3'" },
3139
+ instId: { type: "string", description: "BTC-USDT (spot) or BTC-USDT-SWAP (contract)" },
3140
+ algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"] },
3141
+ lever: { type: "string", description: "Required for contract_dca" },
3117
3142
  direction: { type: "string", enum: ["long", "short"] },
3118
- initOrdAmt: { type: "string", description: "Initial order amount (USDT)" },
3119
- maxSafetyOrds: { type: "string", description: "Max safety orders, e.g. '3'" },
3120
- tpPct: { type: "string", description: "Take-profit ratio, e.g. '0.03' = 3%" },
3121
- safetyOrdAmt: { type: "string", description: "Safety order amount (USDT). Need when maxSafetyOrds > 0" },
3122
- pxSteps: { type: "string", description: "Price drop % per safety order, e.g. '0.03'. Need when maxSafetyOrds > 0" },
3123
- pxStepsMult: { type: "string", description: "Price step multiplier, e.g. '1.2'. Need when maxSafetyOrds > 0" },
3124
- volMult: { type: "string", description: "Safety order size multiplier, e.g. '1.5'. Need when maxSafetyOrds > 0" },
3125
- slPct: { type: "string", description: "Stop-loss ratio, e.g. '0.05' = 5%" },
3126
- slMode: { type: "string", enum: ["limit", "market"], description: "Stop-loss type. Default: market" },
3127
- allowReinvest: { type: "string", enum: ["true", "false"], description: "Reinvest profit. Default: 'true'" },
3128
- triggerStrategy: { type: "string", enum: ["instant", "price", "rsi"], default: "instant", description: "How bot starts. Default: instant" },
3129
- triggerPx: { type: "string", description: "Required when triggerStrategy='price'" }
3143
+ initOrdAmt: { type: "string", description: "Initial amount in quote ccy" },
3144
+ maxSafetyOrds: { type: "string", description: "0=no DCA, max 100" },
3145
+ tpPct: { type: "string", description: "Take-profit ratio, 0.03=3%" },
3146
+ safetyOrdAmt: { type: "string", description: "Safety order amount. Need if maxSafetyOrds>0" },
3147
+ pxSteps: { type: "string", description: "Price drop per safety order. Need if maxSafetyOrds>0" },
3148
+ pxStepsMult: { type: "string", description: "Step multiplier. Required when maxSafetyOrds>0, e.g. '1'" },
3149
+ volMult: { type: "string", description: "Size multiplier. Required when maxSafetyOrds>0, e.g. '1'" },
3150
+ slPct: { type: "string", description: "Stop-loss ratio, 0.05=5%" },
3151
+ slMode: { type: "string", enum: ["limit", "market"] },
3152
+ allowReinvest: { type: "boolean", description: "Default true" },
3153
+ triggerStrategy: { type: "string", enum: ["instant", "price"] },
3154
+ triggerPx: { type: "string", description: "Need if triggerStrategy=price" },
3155
+ algoClOrdId: { type: "string", description: "Client order ID, 1-32 chars" },
3156
+ // Backend expects boolean, but kept as string for backward compatibility with older clients.
3157
+ reserveFunds: { type: "string", description: "'true' or 'false', default 'true'" },
3158
+ tradeQuoteCcy: { type: "string" }
3130
3159
  },
3131
- required: ["instId", "lever", "direction", "initOrdAmt", "maxSafetyOrds", "tpPct"]
3160
+ required: ["instId", "algoOrdType", "direction", "initOrdAmt", "maxSafetyOrds", "tpPct"]
3132
3161
  },
3133
3162
  handler: async (rawArgs, context) => {
3134
3163
  const args = asRecord(rawArgs);
3135
3164
  const instId = requireString(args, "instId");
3165
+ const algoOrdType = requireString(args, "algoOrdType");
3166
+ if (algoOrdType === "contract_dca" && !readString(args, "lever")) {
3167
+ throw new OkxApiError("lever is required for contract_dca", {
3168
+ code: "VALIDATION",
3169
+ endpoint: `${BASE}/create`
3170
+ });
3171
+ }
3136
3172
  const triggerStrategy = readString(args, "triggerStrategy") ?? "instant";
3137
3173
  const triggerParam = {
3138
3174
  triggerAction: "start",
@@ -3141,24 +3177,55 @@ function registerDcaTools() {
3141
3177
  if (triggerStrategy === "price") {
3142
3178
  triggerParam["triggerPx"] = requireString(args, "triggerPx");
3143
3179
  }
3180
+ const maxSafetyOrds = requireString(args, "maxSafetyOrds");
3181
+ if (Number(maxSafetyOrds) > 0) {
3182
+ if (!readString(args, "safetyOrdAmt")) {
3183
+ throw new OkxApiError("safetyOrdAmt is required when maxSafetyOrds > 0", {
3184
+ code: "VALIDATION",
3185
+ endpoint: `${BASE}/create`
3186
+ });
3187
+ }
3188
+ if (!readString(args, "pxSteps")) {
3189
+ throw new OkxApiError("pxSteps is required when maxSafetyOrds > 0", {
3190
+ code: "VALIDATION",
3191
+ endpoint: `${BASE}/create`
3192
+ });
3193
+ }
3194
+ if (!readString(args, "pxStepsMult")) {
3195
+ throw new OkxApiError("pxStepsMult is required when maxSafetyOrds > 0", {
3196
+ code: "VALIDATION",
3197
+ endpoint: `${BASE}/create`
3198
+ });
3199
+ }
3200
+ if (!readString(args, "volMult")) {
3201
+ throw new OkxApiError("volMult is required when maxSafetyOrds > 0", {
3202
+ code: "VALIDATION",
3203
+ endpoint: `${BASE}/create`
3204
+ });
3205
+ }
3206
+ }
3144
3207
  const response = await context.client.privatePost(
3145
3208
  `${BASE}/create`,
3146
3209
  compactObject({
3147
3210
  instId,
3148
- algoOrdType: "contract_dca",
3149
- lever: requireString(args, "lever"),
3211
+ algoOrdType,
3212
+ lever: readString(args, "lever"),
3150
3213
  direction: requireString(args, "direction"),
3151
3214
  initOrdAmt: requireString(args, "initOrdAmt"),
3152
3215
  safetyOrdAmt: readString(args, "safetyOrdAmt"),
3153
- maxSafetyOrds: requireString(args, "maxSafetyOrds"),
3216
+ maxSafetyOrds,
3154
3217
  pxSteps: readString(args, "pxSteps"),
3155
3218
  pxStepsMult: readString(args, "pxStepsMult"),
3156
3219
  volMult: readString(args, "volMult"),
3157
3220
  tpPct: requireString(args, "tpPct"),
3158
3221
  slPct: readString(args, "slPct"),
3159
3222
  slMode: readString(args, "slMode"),
3160
- allowReinvest: readString(args, "allowReinvest"),
3161
- triggerParams: [triggerParam]
3223
+ allowReinvest: args["allowReinvest"] !== void 0 ? args["allowReinvest"] === true || args["allowReinvest"] === "true" : void 0,
3224
+ triggerParams: [triggerParam],
3225
+ tag: context.config.sourceTag,
3226
+ algoClOrdId: readString(args, "algoClOrdId"),
3227
+ reserveFunds: readString(args, "reserveFunds"),
3228
+ tradeQuoteCcy: readString(args, "tradeQuoteCcy")
3162
3229
  }),
3163
3230
  privateRateLimit("dca_create_order", 20)
3164
3231
  );
@@ -3168,21 +3235,31 @@ function registerDcaTools() {
3168
3235
  {
3169
3236
  name: "dca_stop_order",
3170
3237
  module: "bot.dca",
3171
- description: "Stop a running Contract DCA bot. [CAUTION] This will stop the bot.",
3238
+ description: "Stop a running DCA bot. [CAUTION] spot_dca needs stopType: 1=sell, 2=keep.",
3172
3239
  isWrite: true,
3173
3240
  inputSchema: {
3174
3241
  type: "object",
3175
3242
  properties: {
3176
- algoId: { type: "string", description: "DCA bot algo order ID (not a trade ordId)" }
3243
+ algoId: { type: "string", description: "Algo order ID" },
3244
+ algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"] },
3245
+ stopType: { type: "string", enum: ["1", "2"], description: "Required for spot_dca: 1=sell all, 2=keep tokens" }
3177
3246
  },
3178
- required: ["algoId"]
3247
+ required: ["algoId", "algoOrdType"]
3179
3248
  },
3180
3249
  handler: async (rawArgs, context) => {
3181
3250
  const args = asRecord(rawArgs);
3182
3251
  const algoId = requireString(args, "algoId");
3252
+ const algoOrdType = requireString(args, "algoOrdType");
3253
+ const stopType = readString(args, "stopType");
3254
+ if (algoOrdType === "spot_dca" && !stopType) {
3255
+ throw new OkxApiError(
3256
+ "stopType is required for spot_dca. Use '1' (sell all tokens) or '2' (keep tokens)",
3257
+ { code: "VALIDATION", endpoint: `${BASE}/stop` }
3258
+ );
3259
+ }
3183
3260
  const response = await context.client.privatePost(
3184
3261
  `${BASE}/stop`,
3185
- { algoId, algoOrdType: "contract_dca" },
3262
+ compactObject({ algoId, algoOrdType, stopType }),
3186
3263
  privateRateLimit("dca_stop_order", 20)
3187
3264
  );
3188
3265
  return normalizeWrite2(response);
@@ -3191,21 +3268,18 @@ function registerDcaTools() {
3191
3268
  {
3192
3269
  name: "dca_get_orders",
3193
3270
  module: "bot.dca",
3194
- description: "List DCA bots. status='active' for running; 'history' for stopped.",
3271
+ description: "List DCA bots. Default: active (running). Use status=history for stopped.",
3195
3272
  isWrite: false,
3196
3273
  inputSchema: {
3197
3274
  type: "object",
3198
3275
  properties: {
3199
- status: {
3200
- type: "string",
3201
- enum: ["active", "history"],
3202
- description: "active=running (default); history=stopped"
3203
- },
3204
- algoId: { type: "string", description: "DCA bot algo order ID (not a trade ordId)" },
3205
- instId: { type: "string", description: "e.g. BTC-USDT-SWAP" },
3206
- after: { type: "string", description: "Cursor for older records" },
3207
- before: { type: "string", description: "Cursor for newer records" },
3208
- limit: { type: "number", description: "Default 100" }
3276
+ status: { type: "string", enum: ["active", "history"] },
3277
+ algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"], description: "Default: contract_dca" },
3278
+ algoId: { type: "string", description: "Algo order ID" },
3279
+ instId: { type: "string" },
3280
+ after: { type: "string", description: "Pagination cursor" },
3281
+ before: { type: "string", description: "Pagination cursor" },
3282
+ limit: { type: "number" }
3209
3283
  },
3210
3284
  required: []
3211
3285
  },
@@ -3213,10 +3287,11 @@ function registerDcaTools() {
3213
3287
  const args = asRecord(rawArgs);
3214
3288
  const status = readString(args, "status") ?? "active";
3215
3289
  const path42 = status === "history" ? `${BASE}/history-list` : `${BASE}/ongoing-list`;
3290
+ const algoOrdType = readString(args, "algoOrdType") ?? "contract_dca";
3216
3291
  const response = await context.client.privateGet(
3217
3292
  path42,
3218
3293
  compactObject({
3219
- algoOrdType: "contract_dca",
3294
+ algoOrdType,
3220
3295
  algoId: readString(args, "algoId"),
3221
3296
  instId: readString(args, "instId"),
3222
3297
  after: readString(args, "after"),
@@ -3231,21 +3306,23 @@ function registerDcaTools() {
3231
3306
  {
3232
3307
  name: "dca_get_order_details",
3233
3308
  module: "bot.dca",
3234
- description: "Get DCA bot detail by algo ID. Returns current position details.",
3309
+ description: "Get DCA bot position details (avgPx, upl, liqPx, etc).",
3235
3310
  isWrite: false,
3236
3311
  inputSchema: {
3237
3312
  type: "object",
3238
3313
  properties: {
3239
- algoId: { type: "string", description: "DCA bot algo order ID (not a trade ordId)" }
3314
+ algoId: { type: "string", description: "Algo order ID" },
3315
+ algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"] }
3240
3316
  },
3241
- required: ["algoId"]
3317
+ required: ["algoId", "algoOrdType"]
3242
3318
  },
3243
3319
  handler: async (rawArgs, context) => {
3244
3320
  const args = asRecord(rawArgs);
3245
3321
  const algoId = requireString(args, "algoId");
3322
+ const algoOrdType = requireString(args, "algoOrdType");
3246
3323
  const response = await context.client.privateGet(
3247
3324
  `${BASE}/position-details`,
3248
- { algoId, algoOrdType: "contract_dca" },
3325
+ { algoId, algoOrdType },
3249
3326
  privateRateLimit("dca_get_order_details", 20)
3250
3327
  );
3251
3328
  return normalizeResponse(response);
@@ -3254,29 +3331,31 @@ function registerDcaTools() {
3254
3331
  {
3255
3332
  name: "dca_get_sub_orders",
3256
3333
  module: "bot.dca",
3257
- description: "Query DCA bot cycles or orders within a cycle. Omit cycleId for cycle list; provide cycleId for orders.",
3334
+ description: "Get DCA cycles or orders in a cycle. Omit cycleId=cycle list; with cycleId=orders.",
3258
3335
  isWrite: false,
3259
3336
  inputSchema: {
3260
3337
  type: "object",
3261
3338
  properties: {
3262
- algoId: { type: "string", description: "DCA bot algo order ID (not a trade ordId)" },
3263
- cycleId: { type: "string", description: "Omit for cycle list; provide for orders within a cycle" },
3264
- after: { type: "string", description: "Cursor for older records (cycle-list mode only)" },
3265
- before: { type: "string", description: "Cursor for newer records (cycle-list mode only)" },
3266
- limit: { type: "number", description: "Default 100" }
3339
+ algoId: { type: "string", description: "Algo order ID" },
3340
+ algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"] },
3341
+ cycleId: { type: "string", description: "Omit for cycles; provide for orders" },
3342
+ after: { type: "string", description: "Pagination cursor" },
3343
+ before: { type: "string", description: "Pagination cursor" },
3344
+ limit: { type: "number" }
3267
3345
  },
3268
- required: ["algoId"]
3346
+ required: ["algoId", "algoOrdType"]
3269
3347
  },
3270
3348
  handler: async (rawArgs, context) => {
3271
3349
  const args = asRecord(rawArgs);
3272
3350
  const algoId = requireString(args, "algoId");
3351
+ const algoOrdType = requireString(args, "algoOrdType");
3273
3352
  const cycleId = readString(args, "cycleId");
3274
3353
  if (cycleId) {
3275
3354
  const response2 = await context.client.privateGet(
3276
3355
  `${BASE}/orders`,
3277
3356
  compactObject({
3278
3357
  algoId,
3279
- algoOrdType: "contract_dca",
3358
+ algoOrdType,
3280
3359
  cycleId,
3281
3360
  limit: readNumber(args, "limit")
3282
3361
  }),
@@ -3288,7 +3367,7 @@ function registerDcaTools() {
3288
3367
  `${BASE}/cycle-list`,
3289
3368
  compactObject({
3290
3369
  algoId,
3291
- algoOrdType: "contract_dca",
3370
+ algoOrdType,
3292
3371
  after: readString(args, "after"),
3293
3372
  before: readString(args, "before"),
3294
3373
  limit: readNumber(args, "limit")
@@ -3311,7 +3390,7 @@ function registerEarnTools() {
3311
3390
  {
3312
3391
  name: "earn_get_savings_balance",
3313
3392
  module: "earn.savings",
3314
- description: "Get Simple Earn (savings/flexible earn) balance. Returns current holdings for all currencies or a specific one. To show market rates alongside balance (\u5E02\u573A\u5747\u5229\u7387), call earn_get_lending_rate_history \u2014 do NOT use earn_get_lending_rate_summary for this purpose.",
3393
+ description: "Get Simple Earn (savings/flexible earn) balance. Returns current holdings, lent amount, pending interest, and the user's set rate. Response fields: amt (total held), loanAmt (actively lent), pendingAmt (awaiting match), earnings (cumulative interest), rate (user's own minimum lending rate setting \u2014 NOT market yield, NOT APY). To get the actual market lending rate, call earn_get_lending_rate_history instead.",
3315
3394
  isWrite: false,
3316
3395
  inputSchema: {
3317
3396
  type: "object",
@@ -3350,7 +3429,7 @@ function registerEarnTools() {
3350
3429
  },
3351
3430
  rate: {
3352
3431
  type: "string",
3353
- description: "Lending rate. Annual rate in decimal, e.g. 0.01 = 1%. Defaults to 0.01 (1%, minimum rate, easiest to match)."
3432
+ description: "Minimum lending rate threshold (annual, decimal). e.g. 0.01 = 1%. Only matched when market rate \u2265 this value. Defaults to 0.01. Keep at 0.01 to maximize matching probability \u2014 do NOT raise this to increase yield, as actual yield (lendingRate) is determined by market supply/demand, not this setting."
3354
3433
  }
3355
3434
  },
3356
3435
  required: ["ccy", "amt"]
@@ -3419,7 +3498,7 @@ function registerEarnTools() {
3419
3498
  },
3420
3499
  rate: {
3421
3500
  type: "string",
3422
- description: "Lending rate. Annual rate in decimal, e.g. 0.01 = 1%"
3501
+ description: "Minimum lending rate threshold (annual, decimal). e.g. 0.01 = 1%. Only matched when market rate \u2265 this value. Keep at 0.01 to maximize matching probability \u2014 do NOT raise this to increase yield, as actual yield (lendingRate) is determined by market supply/demand, not this setting."
3423
3502
  }
3424
3503
  },
3425
3504
  required: ["ccy", "rate"]
@@ -3441,7 +3520,7 @@ function registerEarnTools() {
3441
3520
  {
3442
3521
  name: "earn_get_lending_history",
3443
3522
  module: "earn.savings",
3444
- description: "Get market lending rate history for Simple Earn. Use this tool to query market lending rates. Returns market lending records with amount, rate, and earnings data.",
3523
+ description: "Get personal lending records for Simple Earn (your own lending history). NOT for market rate queries. Returns your lending records with amount, rate, and earnings data.",
3445
3524
  isWrite: false,
3446
3525
  inputSchema: {
3447
3526
  type: "object",
@@ -3479,34 +3558,10 @@ function registerEarnTools() {
3479
3558
  return normalizeResponse(response);
3480
3559
  }
3481
3560
  },
3482
- {
3483
- name: "earn_get_lending_rate_summary",
3484
- module: "earn.savings",
3485
- description: "Get coin lending market rate summary. NOT related to Simple Earn. Use this to query the lending/borrowing market rates (\u501F\u5E01\u5E02\u573A\u5229\u7387). Returns aggregate overview: average rate (avgRate), estimated next-cycle rate (estRate), previous-cycle rate (preRate), and available lending amounts.",
3486
- isWrite: false,
3487
- inputSchema: {
3488
- type: "object",
3489
- properties: {
3490
- ccy: {
3491
- type: "string",
3492
- description: "e.g. USDT. Omit for all."
3493
- }
3494
- }
3495
- },
3496
- handler: async (rawArgs, context) => {
3497
- const args = asRecord(rawArgs);
3498
- const response = await context.client.publicGet(
3499
- "/api/v5/finance/savings/lending-rate-summary",
3500
- compactObject({ ccy: readString(args, "ccy") }),
3501
- publicRateLimit("earn_get_lending_rate_summary", 6)
3502
- );
3503
- return normalizeResponse(response);
3504
- }
3505
- },
3506
3561
  {
3507
3562
  name: "earn_get_lending_rate_history",
3508
3563
  module: "earn.savings",
3509
- description: "Query Simple Earn lending rates. Use this tool when the user asks about current or historical lending rates for Simple Earn, or when displaying savings balance with market rate context (\u5E02\u573A\u5747\u5229\u7387). Returns actual settled lending rate records (lendingRate field) with timestamps, ordered newest-first.",
3564
+ description: "Query Simple Earn lending rates. Public endpoint (no API key required). Use this tool when the user asks about current or historical lending rates for Simple Earn, or when displaying savings balance with market rate context. Response fields per record: rate (market lending rate \u2014 the rate borrowers pay this period; user's minimum setting must be \u2264 this to be eligible), lendingRate (actual yield received by lenders; stablecoins e.g. USDT/USDC only: subject to pro-rata dilution \u2014 when eligible supply exceeds borrowing demand total interest is shared so lendingRate < rate; non-stablecoins: lendingRate = rate, no dilution; always use lendingRate as the true APY to show users), ts (settlement timestamp ms). To get current APY: use limit=1 and read lendingRate.",
3510
3565
  isWrite: false,
3511
3566
  inputSchema: {
3512
3567
  type: "object",
@@ -3890,7 +3945,7 @@ function registerDcdTools() {
3890
3945
  properties: {
3891
3946
  baseCcy: { type: "string", description: "Base currency, e.g. BTC" },
3892
3947
  quoteCcy: { type: "string", description: "Quote currency, e.g. USDT" },
3893
- optType: { type: "string", description: "Option type: C (Call/\u9AD8\u5356) or P (Put/\u4F4E\u4E70)" }
3948
+ optType: { type: "string", description: "Option type: C (Call, sell high) or P (Put, buy low)" }
3894
3949
  },
3895
3950
  required: ["baseCcy", "quoteCcy", "optType"]
3896
3951
  },
@@ -4129,11 +4184,53 @@ function registerDcdTools() {
4129
4184
  }
4130
4185
  ];
4131
4186
  }
4187
+ function registerAutoEarnTools() {
4188
+ return [
4189
+ {
4190
+ name: "earn_auto_set",
4191
+ module: "earn.autoearn",
4192
+ description: "Enable or disable auto-earn for a currency. earnType='0' for auto-lend+stake (most currencies); earnType='1' for USDG earn (USDG, BUIDL). Use account_get_balance first: if autoLendStatus or autoStakingStatus != 'unsupported', use earnType='0'; for USDG/BUIDL use earnType='1'. [CAUTION] Cannot disable within 24h of enabling.",
4193
+ isWrite: true,
4194
+ inputSchema: {
4195
+ type: "object",
4196
+ properties: {
4197
+ ccy: {
4198
+ type: "string",
4199
+ description: "Currency, e.g. SOL, USDG"
4200
+ },
4201
+ action: {
4202
+ type: "string",
4203
+ description: "turn_on or turn_off"
4204
+ },
4205
+ earnType: {
4206
+ type: "string",
4207
+ description: "0=auto-lend+stake (default), 1=USDG earn. Omit to use default."
4208
+ }
4209
+ },
4210
+ required: ["ccy", "action"]
4211
+ },
4212
+ handler: async (rawArgs, context) => {
4213
+ const args = asRecord(rawArgs);
4214
+ const response = await context.client.privatePost(
4215
+ "/api/v5/account/set-auto-earn",
4216
+ compactObject({
4217
+ ccy: requireString(args, "ccy"),
4218
+ action: requireString(args, "action"),
4219
+ earnType: readString(args, "earnType") ?? "0"
4220
+ }),
4221
+ privateRateLimit("earn_auto_set", 10)
4222
+ );
4223
+ return normalizeResponse(response);
4224
+ }
4225
+ }
4226
+ ];
4227
+ }
4132
4228
  function registerAllEarnTools() {
4133
4229
  return [
4134
4230
  ...registerEarnTools(),
4135
4231
  ...registerOnchainEarnTools(),
4136
- ...registerDcdTools()
4232
+ ...registerDcdTools(),
4233
+ ...registerAutoEarnTools()
4137
4234
  ];
4138
4235
  }
4139
4236
  function buildContractTradeTools(cfg) {
@@ -5247,6 +5344,11 @@ function registerOptionAlgoTools() {
5247
5344
  type: "string",
5248
5345
  enum: ["last", "index", "mark"]
5249
5346
  },
5347
+ tgtCcy: {
5348
+ type: "string",
5349
+ enum: ["base_ccy", "quote_ccy"],
5350
+ description: "Size unit. base_ccy(default): sz in contracts, quote_ccy: sz in USDT (may not be supported for options)"
5351
+ },
5250
5352
  reduceOnly: {
5251
5353
  type: "boolean",
5252
5354
  description: "Ensure order only reduces position"
@@ -5269,6 +5371,7 @@ function registerOptionAlgoTools() {
5269
5371
  side: requireString(args, "side"),
5270
5372
  ordType: requireString(args, "ordType"),
5271
5373
  sz: requireString(args, "sz"),
5374
+ tgtCcy: readString(args, "tgtCcy"),
5272
5375
  tpTriggerPx: readString(args, "tpTriggerPx"),
5273
5376
  tpOrdPx: readString(args, "tpOrdPx"),
5274
5377
  tpTriggerPxType: readString(args, "tpTriggerPxType"),
@@ -6116,6 +6219,11 @@ function registerSpotTradeTools() {
6116
6219
  type: "string",
6117
6220
  description: "SL order price, -1=market (conditional/oco only)"
6118
6221
  },
6222
+ tgtCcy: {
6223
+ type: "string",
6224
+ enum: ["base_ccy", "quote_ccy"],
6225
+ description: "Size unit. base_ccy(default): sz in base (e.g. BTC), quote_ccy: sz in quote (e.g. USDT)"
6226
+ },
6119
6227
  callbackRatio: {
6120
6228
  type: "string",
6121
6229
  description: "Callback ratio e.g. 0.01=1%, use ratio or spread (move_order_stop only)"
@@ -6141,6 +6249,7 @@ function registerSpotTradeTools() {
6141
6249
  side: requireString(args, "side"),
6142
6250
  ordType: requireString(args, "ordType"),
6143
6251
  sz: requireString(args, "sz"),
6252
+ tgtCcy: readString(args, "tgtCcy"),
6144
6253
  tpTriggerPx: readString(args, "tpTriggerPx"),
6145
6254
  tpOrdPx: readString(args, "tpOrdPx"),
6146
6255
  slTriggerPx: readString(args, "slTriggerPx"),
@@ -7142,6 +7251,12 @@ function fail(label, detail, hints) {
7142
7251
  outputLine(` \u2192 ${hint}`);
7143
7252
  }
7144
7253
  }
7254
+ function warn(label, detail, hints = []) {
7255
+ outputLine(` \u26A0 ${label.padEnd(14)} ${detail}`);
7256
+ for (const hint of hints) {
7257
+ outputLine(` \u2192 ${hint}`);
7258
+ }
7259
+ }
7145
7260
  function section(title) {
7146
7261
  outputLine("");
7147
7262
  outputLine(` ${title}`);
@@ -7252,59 +7367,154 @@ function checkMcpEntryPoint(report) {
7252
7367
  return { entryPath: null, passed: false };
7253
7368
  }
7254
7369
  }
7255
- function checkClaudeDesktopConfig(report) {
7256
- section("Claude Desktop Config");
7257
- const configPath = getConfigPath("claude-desktop");
7258
- if (!configPath) {
7259
- ok("config path", "(not applicable on this platform)");
7260
- report.add("claude_cfg", "n/a");
7261
- return true;
7262
- }
7263
- if (!fs4.existsSync(configPath)) {
7264
- fail("config file", `not found: ${configPath}`, [
7265
- "Claude Desktop may not be installed",
7266
- "Run: okx setup --client claude-desktop to configure"
7267
- ]);
7268
- report.add("claude_cfg", `MISSING ${sanitize(configPath)}`);
7269
- return false;
7270
- }
7271
- ok("config file", configPath);
7272
- report.add("claude_cfg", sanitize(configPath));
7370
+ var MCP_SERVER_NAME = "okx-trade-mcp";
7371
+ var CLIENT_LIMITS = {
7372
+ cursor: { perServer: 40, total: 80 }
7373
+ };
7374
+ function checkJsonMcpConfig(configPath) {
7375
+ if (!fs4.existsSync(configPath)) return "missing";
7273
7376
  try {
7274
7377
  const raw = fs4.readFileSync(configPath, "utf8");
7275
7378
  const parsed = JSON.parse(raw);
7276
7379
  const mcpServers = parsed["mcpServers"];
7277
- if (!mcpServers) {
7278
- fail("mcp entry", "no mcpServers section found", [
7279
- "Run: okx setup --client claude-desktop"
7280
- ]);
7281
- report.add("claude_mcp", "NO_SECTION");
7282
- return false;
7283
- }
7380
+ if (!mcpServers) return "not-configured";
7284
7381
  const entries = Object.entries(mcpServers);
7285
- const mcpEntry = entries.find(([, v]) => {
7382
+ const found = entries.find(([name, v]) => {
7383
+ if (name.includes(MCP_SERVER_NAME)) return true;
7286
7384
  const val = v;
7287
7385
  const cmd = String(val["command"] ?? "");
7288
7386
  const args = val["args"] ?? [];
7289
- return cmd.includes("okx-trade-mcp") || args.some((a) => a.includes("okx-trade-mcp"));
7387
+ return cmd.includes(MCP_SERVER_NAME) || args.some((a) => a.includes(MCP_SERVER_NAME));
7290
7388
  });
7291
- if (mcpEntry) {
7292
- ok("mcp entry", `found: "${mcpEntry[0]}"`);
7293
- report.add("claude_mcp", `found:${mcpEntry[0]}`);
7294
- return true;
7389
+ return found ? "found" : "not-configured";
7390
+ } catch (_e) {
7391
+ return "parse-error";
7392
+ }
7393
+ }
7394
+ function checkClaudeCodeConfig() {
7395
+ const home = os2.homedir();
7396
+ const candidates = [
7397
+ path2.join(home, ".claude", "settings.json"),
7398
+ path2.join(home, ".claude.json")
7399
+ ];
7400
+ let anyFound = false;
7401
+ let anyParseError = false;
7402
+ for (const cfgPath of candidates) {
7403
+ if (!fs4.existsSync(cfgPath)) continue;
7404
+ anyFound = true;
7405
+ const result = checkJsonMcpConfig(cfgPath);
7406
+ if (result === "found") return "found";
7407
+ if (result === "parse-error") anyParseError = true;
7408
+ }
7409
+ if (!anyFound) return "missing";
7410
+ if (anyParseError) return "parse-error";
7411
+ return "not-configured";
7412
+ }
7413
+ function checkMcpClients(report) {
7414
+ section("MCP Client Config");
7415
+ const jsonClients = ["claude-desktop", "cursor", "windsurf"];
7416
+ const configuredClients = [];
7417
+ let anyFailed = false;
7418
+ for (const clientId of jsonClients) {
7419
+ const configPath = getConfigPath(clientId);
7420
+ if (!configPath) continue;
7421
+ const name = CLIENT_NAMES[clientId];
7422
+ const status = checkJsonMcpConfig(configPath);
7423
+ if (status === "missing") {
7424
+ continue;
7425
+ }
7426
+ if (status === "found") {
7427
+ ok(name, `configured (${sanitize(configPath)})`);
7428
+ report.add(`client_${clientId}`, `OK ${sanitize(configPath)}`);
7429
+ configuredClients.push(clientId);
7430
+ } else if (status === "not-configured") {
7431
+ fail(name, "okx-trade-mcp not found in mcpServers", [
7432
+ `Run: okx setup --client ${clientId}`
7433
+ ]);
7434
+ report.add(`client_${clientId}`, "NOT_CONFIGURED");
7435
+ anyFailed = true;
7295
7436
  } else {
7296
- fail("mcp entry", "okx-trade-mcp not found in mcpServers", [
7297
- "Run: okx setup --client claude-desktop"
7437
+ fail(name, `JSON parse error in ${sanitize(configPath)}`, [
7438
+ `Check ${sanitize(configPath)} for JSON syntax errors`,
7439
+ `Then run: okx setup --client ${clientId}`
7298
7440
  ]);
7299
- report.add("claude_mcp", "NOT_CONFIGURED");
7300
- return false;
7441
+ report.add(`client_${clientId}`, "PARSE_ERROR");
7442
+ anyFailed = true;
7301
7443
  }
7302
- } catch (e) {
7303
- fail("config parse", `JSON parse error: ${e instanceof Error ? e.message : String(e)}`, [
7304
- `Check ${configPath} for JSON syntax errors`
7444
+ }
7445
+ const claudeCodeStatus = checkClaudeCodeConfig();
7446
+ if (claudeCodeStatus !== "missing") {
7447
+ const name = CLIENT_NAMES["claude-code"];
7448
+ if (claudeCodeStatus === "found") {
7449
+ ok(name, "configured");
7450
+ report.add("client_claude-code", "OK");
7451
+ configuredClients.push("claude-code");
7452
+ } else if (claudeCodeStatus === "not-configured") {
7453
+ warn(name, "installed but okx-trade-mcp not configured", [
7454
+ "Run: okx setup --client claude-code"
7455
+ ]);
7456
+ report.add("client_claude-code", "NOT_CONFIGURED");
7457
+ } else {
7458
+ fail(name, "settings file has JSON parse error", [
7459
+ "Run: okx setup --client claude-code"
7460
+ ]);
7461
+ report.add("client_claude-code", "PARSE_ERROR");
7462
+ anyFailed = true;
7463
+ }
7464
+ }
7465
+ if (configuredClients.length === 0 && !anyFailed) {
7466
+ fail("no client", "no MCP client configuration found", [
7467
+ "Run: okx setup --client <client>",
7468
+ "Supported clients: claude-desktop, cursor, windsurf, claude-code"
7305
7469
  ]);
7306
- report.add("claude_cfg_parse", "FAIL");
7307
- return false;
7470
+ report.add("client_cfg", "NONE_FOUND");
7471
+ return { passed: false, configuredClients };
7472
+ }
7473
+ const passed = configuredClients.length > 0 && !anyFailed;
7474
+ report.add("client_cfg", passed ? `OK (${configuredClients.join(",")})` : "FAIL");
7475
+ return { passed, configuredClients };
7476
+ }
7477
+ function checkToolCount(report, configuredClients, getSpecs = allToolSpecs) {
7478
+ section("Tool Count");
7479
+ const specs = getSpecs();
7480
+ const totalCount = specs.length;
7481
+ const defaultModuleSet = new Set(DEFAULT_MODULES);
7482
+ const defaultCount = specs.filter((s) => defaultModuleSet.has(s.module)).length;
7483
+ const defaultModulesArg = DEFAULT_MODULES.join(",");
7484
+ const applicableLimits = configuredClients.map((id) => ({ id, limits: CLIENT_LIMITS[id] })).filter((x) => x.limits !== void 0);
7485
+ if (applicableLimits.length === 0) {
7486
+ ok("total tools", `${totalCount} tools loaded`);
7487
+ report.add("tool_count", `${totalCount}`);
7488
+ return;
7489
+ }
7490
+ let anyExceeded = false;
7491
+ for (const { id, limits } of applicableLimits) {
7492
+ const name = CLIENT_NAMES[id];
7493
+ if (totalCount > limits.total) {
7494
+ warn(
7495
+ "tool count",
7496
+ `${totalCount} tools loaded \u2014 exceeds ${name} limit (${limits.total} total / ${limits.perServer} per server)`,
7497
+ [
7498
+ `Use --modules to reduce: okx-trade-mcp --modules ${defaultModulesArg} (${defaultCount} tools)`
7499
+ ]
7500
+ );
7501
+ report.add("tool_count", `${totalCount} EXCEEDS_${id.toUpperCase()}_LIMIT`);
7502
+ anyExceeded = true;
7503
+ } else if (totalCount > limits.perServer) {
7504
+ warn(
7505
+ "tool count",
7506
+ `${totalCount} tools loaded \u2014 exceeds ${name} per-server limit (${limits.perServer})`,
7507
+ [
7508
+ `Use --modules to reduce: okx-trade-mcp --modules ${defaultModulesArg} (${defaultCount} tools)`
7509
+ ]
7510
+ );
7511
+ report.add("tool_count", `${totalCount} EXCEEDS_${id.toUpperCase()}_PER_SERVER_LIMIT`);
7512
+ anyExceeded = true;
7513
+ }
7514
+ }
7515
+ if (!anyExceeded) {
7516
+ ok("total tools", `${totalCount} tools loaded (within limits for all configured clients)`);
7517
+ report.add("tool_count", `${totalCount} OK`);
7308
7518
  }
7309
7519
  }
7310
7520
  function readLogTail(logPath) {
@@ -7497,9 +7707,10 @@ async function cmdDiagnoseMcp(options = {}) {
7497
7707
  checkMcpPackageVersion(report);
7498
7708
  const nodePassed = checkNodeCompat(report);
7499
7709
  const { entryPath, passed: entryPassed } = checkMcpEntryPoint(report);
7500
- const cfgPassed = checkClaudeDesktopConfig(report);
7710
+ const { passed: cfgPassed, configuredClients } = checkMcpClients(report);
7501
7711
  checkMcpLogs(report);
7502
7712
  const moduleLoadPassed = checkModuleLoading(entryPath, report);
7713
+ checkToolCount(report, configuredClients);
7503
7714
  let handshakePassed = false;
7504
7715
  if (entryPath && entryPassed && moduleLoadPassed) {
7505
7716
  handshakePassed = await checkStdioHandshake(entryPath, report);
@@ -7524,7 +7735,7 @@ async function cmdDiagnoseMcp(options = {}) {
7524
7735
 
7525
7736
  // src/commands/diagnose.ts
7526
7737
  var CLI_VERSION = readCliVersion();
7527
- var GIT_HASH = true ? "9f66f84" : "dev";
7738
+ var GIT_HASH = true ? "c270a0b" : "dev";
7528
7739
  function maskKey2(key) {
7529
7740
  if (!key) return "(not set)";
7530
7741
  if (key.length <= 8) return "****";
@@ -8253,11 +8464,7 @@ var HELP_TREE = {
8253
8464
  },
8254
8465
  "lending-history": {
8255
8466
  usage: "okx earn savings lending-history [--ccy <ccy>] [--limit <n>]",
8256
- description: "Get market lending rate history"
8257
- },
8258
- "rate-summary": {
8259
- usage: "okx earn savings rate-summary [<ccy>]",
8260
- description: "Get coin lending market rate summary (not Simple Earn, public)"
8467
+ description: "Get personal lending records (requires auth)"
8261
8468
  },
8262
8469
  "rate-history": {
8263
8470
  usage: "okx earn savings rate-history [--ccy <ccy>] [--limit <n>]",
@@ -8294,6 +8501,23 @@ var HELP_TREE = {
8294
8501
  }
8295
8502
  }
8296
8503
  },
8504
+ "auto-earn": {
8505
+ description: "Auto-earn \u2014 automatically lend, stake, or earn on idle assets",
8506
+ commands: {
8507
+ status: {
8508
+ usage: "okx earn auto-earn status [<ccy>]",
8509
+ description: "Query auto-earn status for all or a specific currency"
8510
+ },
8511
+ on: {
8512
+ usage: "okx earn auto-earn on <ccy>",
8513
+ description: "Enable auto-earn for a currency (auto-detects lend/stake vs USDG earn)"
8514
+ },
8515
+ off: {
8516
+ usage: "okx earn auto-earn off <ccy>",
8517
+ description: "Disable auto-earn for a currency"
8518
+ }
8519
+ }
8520
+ },
8297
8521
  dcd: {
8298
8522
  description: "DCD (Dual Currency Deposit) \u2014 structured products with fixed yield",
8299
8523
  commands: {
@@ -8344,7 +8568,7 @@ var HELP_TREE = {
8344
8568
  description: "List sub-orders of a grid bot (filled or live)"
8345
8569
  },
8346
8570
  create: {
8347
- usage: "okx bot grid create --instId <id> --algoOrdType <grid|contract_grid> --maxPx <px> --minPx <px> --gridNum <n>\n [--runType <1|2>] [--quoteSz <n>] [--baseSz <n>]\n [--direction <long|short|neutral>] [--lever <n>] [--sz <n>] [--basePos] [--no-basePos]",
8571
+ usage: "okx bot grid create --instId <id> --algoOrdType <grid|contract_grid> --maxPx <px> --minPx <px> --gridNum <n>\n [--runType <1|2>] [--quoteSz <n>] [--baseSz <n>]\n [--direction <long|short|neutral>] [--lever <n>] [--sz <n>] [--basePos] [--no-basePos]\n [--tpTriggerPx <px>] [--slTriggerPx <px>] [--tpRatio <n>] [--slRatio <n>] [--algoClOrdId <id>]",
8348
8572
  description: "Create a new grid bot order (contract grid opens base position by default)"
8349
8573
  },
8350
8574
  stop: {
@@ -8354,27 +8578,27 @@ var HELP_TREE = {
8354
8578
  }
8355
8579
  },
8356
8580
  dca: {
8357
- description: "Contract DCA (Martingale) bot \u2014 leveraged recurring buys on futures/swaps",
8581
+ description: "DCA (Martingale) bot \u2014 spot or contract recurring buys",
8358
8582
  commands: {
8359
8583
  orders: {
8360
- usage: "okx bot dca orders [--algoId <id>] [--instId <id>] [--history]",
8361
- description: "List active or historical Contract DCA bot orders"
8584
+ usage: "okx bot dca orders [--algoOrdType <spot_dca|contract_dca>] [--algoId <id>] [--instId <id>] [--history]",
8585
+ description: "List DCA bots (spot and/or contract)"
8362
8586
  },
8363
8587
  details: {
8364
- usage: "okx bot dca details --algoId <id>",
8365
- description: "Get details of a specific Contract DCA bot order"
8588
+ usage: "okx bot dca details --algoOrdType <spot_dca|contract_dca> --algoId <id>",
8589
+ description: "Get DCA bot details (spot or contract)"
8366
8590
  },
8367
8591
  "sub-orders": {
8368
- usage: "okx bot dca sub-orders --algoId <id> [--cycleId <id>]",
8369
- description: "List cycles or orders within a cycle of a Contract DCA bot"
8592
+ usage: "okx bot dca sub-orders --algoOrdType <spot_dca|contract_dca> --algoId <id> [--cycleId <id>]",
8593
+ description: "Get DCA cycles/orders (spot or contract)"
8370
8594
  },
8371
8595
  create: {
8372
- usage: "okx bot dca create --instId <id> --lever <n> --direction <long|short>\n --initOrdAmt <n> --maxSafetyOrds <n> --tpPct <n>\n [--safetyOrdAmt <n>] [--pxSteps <n>] [--pxStepsMult <n>] [--volMult <n>]\n [--slPct <n>] [--slMode <limit|market>]\n [--allowReinvest <true|false>] [--triggerStrategy <instant|price|rsi>] [--triggerPx <price>]\n Note: safetyOrdAmt, pxSteps, pxStepsMult, volMult are required when maxSafetyOrds > 0",
8373
- description: "Create a new Contract DCA bot order"
8596
+ usage: "okx bot dca create --algoOrdType <spot_dca|contract_dca> --instId <id> --direction <long|short>\n --initOrdAmt <n> --maxSafetyOrds <n> --tpPct <n>\n [--lever <n>] [--safetyOrdAmt <n>] [--pxSteps <n>] [--pxStepsMult <n>] [--volMult <n>]\n [--slPct <n>] [--slMode <limit|market>] [--allowReinvest <true|false>]\n [--triggerStrategy <instant|price|rsi>] [--triggerPx <price>]\n [--algoClOrdId <id>] [--reserveFunds <true|false>] [--tradeQuoteCcy <ccy>]\n Note: --lever required for contract_dca; safetyOrdAmt, pxSteps, pxStepsMult, volMult required when maxSafetyOrds > 0",
8597
+ description: "Create a DCA (Martingale) bot (spot or contract)"
8374
8598
  },
8375
8599
  stop: {
8376
- usage: "okx bot dca stop --algoId <id>",
8377
- description: "Stop a running Contract DCA bot order"
8600
+ usage: "okx bot dca stop --algoOrdType <spot_dca|contract_dca> --algoId <id> [--stopType <1|2>]\n Note: --stopType required for spot_dca (1=sell all, 2=keep tokens)",
8601
+ description: "Stop a DCA bot (spot or contract)"
8378
8602
  }
8379
8603
  }
8380
8604
  }
@@ -8588,6 +8812,9 @@ var CLI_OPTIONS = {
8588
8812
  baseSz: { type: "string" },
8589
8813
  direction: { type: "string" },
8590
8814
  basePos: { type: "boolean", default: true },
8815
+ tpRatio: { type: "string" },
8816
+ slRatio: { type: "string" },
8817
+ algoClOrdId: { type: "string" },
8591
8818
  stopType: { type: "string" },
8592
8819
  live: { type: "boolean", default: false },
8593
8820
  // market extras
@@ -8606,7 +8833,7 @@ var CLI_OPTIONS = {
8606
8833
  autoCxl: { type: "boolean", default: false },
8607
8834
  clOrdId: { type: "string" },
8608
8835
  newPx: { type: "string" },
8609
- // dca bot (contract only)
8836
+ // dca bot (spot & contract)
8610
8837
  initOrdAmt: { type: "string" },
8611
8838
  safetyOrdAmt: { type: "string" },
8612
8839
  maxSafetyOrds: { type: "string" },
@@ -8620,6 +8847,8 @@ var CLI_OPTIONS = {
8620
8847
  triggerStrategy: { type: "string" },
8621
8848
  triggerPx: { type: "string" },
8622
8849
  cycleId: { type: "string" },
8850
+ reserveFunds: { type: "string" },
8851
+ tradeQuoteCcy: { type: "string" },
8623
8852
  // i18n
8624
8853
  lang: { type: "string" },
8625
8854
  // option
@@ -8839,10 +9068,15 @@ async function cmdMarketTicker(run, instId, json) {
8839
9068
  printKv({
8840
9069
  instId: t["instId"],
8841
9070
  last: t["last"],
8842
- "24h change %": t["sodUtc8"],
9071
+ "24h open": t["open24h"],
8843
9072
  "24h high": t["high24h"],
8844
9073
  "24h low": t["low24h"],
8845
9074
  "24h vol": t["vol24h"],
9075
+ "24h change %": (() => {
9076
+ const last = Number(t["last"]);
9077
+ const open24h = Number(t["open24h"]);
9078
+ return open24h !== 0 ? ((last - open24h) / open24h * 100).toFixed(2) + "%" : "N/A";
9079
+ })(),
8846
9080
  time: new Date(Number(t["ts"])).toLocaleString()
8847
9081
  });
8848
9082
  }
@@ -9263,6 +9497,7 @@ async function cmdSpotAlgoPlace(run, opts) {
9263
9497
  side: opts.side,
9264
9498
  ordType: opts.ordType,
9265
9499
  sz: opts.sz,
9500
+ tgtCcy: opts.tgtCcy,
9266
9501
  tpTriggerPx: opts.tpTriggerPx,
9267
9502
  tpOrdPx: opts.tpOrdPx,
9268
9503
  slTriggerPx: opts.slTriggerPx,
@@ -9510,6 +9745,7 @@ async function cmdSwapAlgoPlace(run, opts) {
9510
9745
  side: opts.side,
9511
9746
  ordType: opts.ordType,
9512
9747
  sz: opts.sz,
9748
+ tgtCcy: opts.tgtCcy,
9513
9749
  posSide: opts.posSide,
9514
9750
  tpTriggerPx: opts.tpTriggerPx,
9515
9751
  tpOrdPx: opts.tpOrdPx,
@@ -9915,6 +10151,7 @@ async function cmdFuturesAlgoPlace(run, opts) {
9915
10151
  side: opts.side,
9916
10152
  ordType: opts.ordType,
9917
10153
  sz: opts.sz,
10154
+ tgtCcy: opts.tgtCcy,
9918
10155
  posSide: opts.posSide,
9919
10156
  tpTriggerPx: opts.tpTriggerPx,
9920
10157
  tpOrdPx: opts.tpOrdPx,
@@ -10209,6 +10446,7 @@ async function cmdOptionAlgoPlace(run, opts) {
10209
10446
  side: opts.side,
10210
10447
  ordType: opts.ordType,
10211
10448
  sz: opts.sz,
10449
+ tgtCcy: opts.tgtCcy,
10212
10450
  tpTriggerPx: opts.tpTriggerPx,
10213
10451
  tpOrdPx: opts.tpOrdPx,
10214
10452
  slTriggerPx: opts.slTriggerPx,
@@ -10648,15 +10886,6 @@ async function cmdEarnLendingHistory(run, opts) {
10648
10886
  ts: new Date(Number(r["ts"])).toLocaleString()
10649
10887
  }));
10650
10888
  }
10651
- async function cmdEarnLendingRateSummary(run, ccy, json) {
10652
- const data = extractData(await run("earn_get_lending_rate_summary", { ccy }));
10653
- printDataList(data, json, "No rate summary data", (r) => ({
10654
- ccy: r["ccy"],
10655
- avgRate: r["avgRate"],
10656
- estRate: r["estRate"],
10657
- avgAmt: r["avgAmt"]
10658
- }));
10659
- }
10660
10889
  async function cmdEarnLendingRateHistory(run, opts) {
10661
10890
  const data = extractData(await run("earn_get_lending_rate_history", { ccy: opts.ccy, limit: opts.limit }));
10662
10891
  printDataList(data, opts.json, "No rate history data", (r) => ({
@@ -10667,6 +10896,92 @@ async function cmdEarnLendingRateHistory(run, opts) {
10667
10896
  }));
10668
10897
  }
10669
10898
 
10899
+ // src/commands/auto-earn.ts
10900
+ var USDG_EARN_CURRENCIES = /* @__PURE__ */ new Set(["USDG", "BUIDL"]);
10901
+ function isSupported(status) {
10902
+ return !!status && status !== "unsupported";
10903
+ }
10904
+ function inferEarnType(detail) {
10905
+ if (isSupported(detail.autoLendStatus) || isSupported(detail.autoStakingStatus)) return "0";
10906
+ if (USDG_EARN_CURRENCIES.has(detail.ccy)) return "1";
10907
+ return null;
10908
+ }
10909
+ async function getBalanceDetails(run, ccy) {
10910
+ const result = await run("account_get_balance", ccy ? { ccy } : {});
10911
+ const data = result.data;
10912
+ const first = data?.[0];
10913
+ return first?.details ?? [];
10914
+ }
10915
+ function earnTypeLabel(et) {
10916
+ return et === "1" ? "USDG earn" : "lend+stake";
10917
+ }
10918
+ async function cmdAutoEarnStatus(run, ccy, json) {
10919
+ const details = await getBalanceDetails(run, ccy);
10920
+ const relevant = details.filter((d) => inferEarnType(d) !== null);
10921
+ if (json) {
10922
+ printJson(relevant);
10923
+ return;
10924
+ }
10925
+ if (!relevant.length) {
10926
+ outputLine(ccy ? `${ccy} does not support auto-earn` : "No currencies support auto-earn");
10927
+ return;
10928
+ }
10929
+ printTable(relevant.map((d) => {
10930
+ const et = inferEarnType(d);
10931
+ return {
10932
+ ccy: d.ccy,
10933
+ earnType: earnTypeLabel(et),
10934
+ autoLend: d.autoLendStatus,
10935
+ autoStaking: d.autoStakingStatus,
10936
+ invested: et === "1" ? d.eq || "-" : d.autoLendAmt || "-",
10937
+ matched: d.autoLendMtAmt || "-",
10938
+ apr: d.autoLendApr ? `${(Number(d.autoLendApr) * 100).toFixed(2)}%` : "-"
10939
+ };
10940
+ }));
10941
+ }
10942
+ async function cmdAutoEarnOn(run, ccy, json) {
10943
+ const details = await getBalanceDetails(run, ccy);
10944
+ const detail = details.find((d) => d.ccy === ccy);
10945
+ if (!detail) {
10946
+ errorLine(`Currency ${ccy} not found in account balance`);
10947
+ process.exitCode = 1;
10948
+ return;
10949
+ }
10950
+ const earnType = inferEarnType(detail);
10951
+ if (earnType === null) {
10952
+ errorLine(`${ccy} does not support auto-earn`);
10953
+ process.exitCode = 1;
10954
+ return;
10955
+ }
10956
+ const result = await run("earn_auto_set", { ccy, action: "turn_on", earnType });
10957
+ if (json) {
10958
+ printJson(result.data);
10959
+ return;
10960
+ }
10961
+ outputLine(`Auto-earn enabled for ${ccy} (${earnTypeLabel(earnType)})`);
10962
+ }
10963
+ async function cmdAutoEarnOff(run, ccy, json) {
10964
+ const details = await getBalanceDetails(run, ccy);
10965
+ const detail = details.find((d) => d.ccy === ccy);
10966
+ if (!detail) {
10967
+ errorLine(`Currency ${ccy} not found in account balance`);
10968
+ process.exitCode = 1;
10969
+ return;
10970
+ }
10971
+ const earnType = inferEarnType(detail);
10972
+ if (earnType === null) {
10973
+ errorLine(`${ccy} does not support auto-earn`);
10974
+ process.exitCode = 1;
10975
+ return;
10976
+ }
10977
+ const result = await run("earn_auto_set", { ccy, action: "turn_off", earnType });
10978
+ if (json) {
10979
+ printJson(result.data);
10980
+ return;
10981
+ }
10982
+ outputLine(`Auto-earn disabled for ${ccy} (${earnTypeLabel(earnType)})`);
10983
+ }
10984
+
10670
10985
  // src/commands/bot.ts
10671
10986
  function emitWriteResult5(item, label, idKey) {
10672
10987
  const isError = item?.["sCode"] !== "0" && item?.["sCode"] !== 0;
@@ -10771,7 +11086,12 @@ async function cmdGridCreate(run, opts) {
10771
11086
  direction: opts.direction,
10772
11087
  lever: opts.lever,
10773
11088
  sz: opts.sz,
10774
- basePos: opts.basePos
11089
+ basePos: opts.basePos,
11090
+ tpTriggerPx: opts.tpTriggerPx,
11091
+ slTriggerPx: opts.slTriggerPx,
11092
+ tpRatio: opts.tpRatio,
11093
+ slRatio: opts.slRatio,
11094
+ algoClOrdId: opts.algoClOrdId
10775
11095
  });
10776
11096
  const data = getData7(result);
10777
11097
  if (opts.json) return printJson(data);
@@ -10793,6 +11113,7 @@ async function cmdGridStop(run, opts) {
10793
11113
  async function cmdDcaCreate(run, opts) {
10794
11114
  const result = await run("dca_create_order", {
10795
11115
  instId: opts.instId,
11116
+ algoOrdType: opts.algoOrdType,
10796
11117
  lever: opts.lever,
10797
11118
  direction: opts.direction,
10798
11119
  initOrdAmt: opts.initOrdAmt,
@@ -10806,25 +11127,29 @@ async function cmdDcaCreate(run, opts) {
10806
11127
  slMode: opts.slMode,
10807
11128
  allowReinvest: opts.allowReinvest,
10808
11129
  triggerStrategy: opts.triggerStrategy,
10809
- triggerPx: opts.triggerPx
11130
+ triggerPx: opts.triggerPx,
11131
+ algoClOrdId: opts.algoClOrdId,
11132
+ reserveFunds: opts.reserveFunds,
11133
+ tradeQuoteCcy: opts.tradeQuoteCcy
10810
11134
  });
10811
11135
  const data = getData7(result);
10812
11136
  if (opts.json) return printJson(data);
10813
- const r = data?.[0];
10814
11137
  emitWriteResult5(data?.[0], "DCA bot created", "algoId");
10815
11138
  }
10816
11139
  async function cmdDcaStop(run, opts) {
10817
11140
  const result = await run("dca_stop_order", {
10818
- algoId: opts.algoId
11141
+ algoId: opts.algoId,
11142
+ algoOrdType: opts.algoOrdType,
11143
+ stopType: opts.stopType
10819
11144
  });
10820
11145
  const data = getData7(result);
10821
11146
  if (opts.json) return printJson(data);
10822
- const r = data?.[0];
10823
11147
  emitWriteResult5(data?.[0], "DCA bot stopped", "algoId");
10824
11148
  }
10825
11149
  async function cmdDcaOrders(run, opts) {
10826
11150
  const result = await run("dca_get_orders", {
10827
11151
  status: opts.history ? "history" : "active",
11152
+ algoOrdType: opts.algoOrdType,
10828
11153
  algoId: opts.algoId,
10829
11154
  instId: opts.instId
10830
11155
  });
@@ -10838,6 +11163,7 @@ async function cmdDcaOrders(run, opts) {
10838
11163
  orders.map((o) => ({
10839
11164
  algoId: o["algoId"],
10840
11165
  instId: o["instId"],
11166
+ type: o["algoOrdType"],
10841
11167
  state: o["state"],
10842
11168
  pnl: o["pnl"],
10843
11169
  pnlRatio: o["pnlRatio"],
@@ -10847,7 +11173,8 @@ async function cmdDcaOrders(run, opts) {
10847
11173
  }
10848
11174
  async function cmdDcaDetails(run, opts) {
10849
11175
  const result = await run("dca_get_order_details", {
10850
- algoId: opts.algoId
11176
+ algoId: opts.algoId,
11177
+ algoOrdType: opts.algoOrdType
10851
11178
  });
10852
11179
  const detail = (getData7(result) ?? [])[0];
10853
11180
  if (!detail) {
@@ -10857,6 +11184,7 @@ async function cmdDcaDetails(run, opts) {
10857
11184
  if (opts.json) return printJson(detail);
10858
11185
  printKv({
10859
11186
  algoId: detail["algoId"],
11187
+ algoOrdType: detail["algoOrdType"],
10860
11188
  instId: detail["instId"],
10861
11189
  sz: detail["sz"],
10862
11190
  avgPx: detail["avgPx"],
@@ -10874,26 +11202,42 @@ async function cmdDcaDetails(run, opts) {
10874
11202
  async function cmdDcaSubOrders(run, opts) {
10875
11203
  const result = await run("dca_get_sub_orders", {
10876
11204
  algoId: opts.algoId,
11205
+ algoOrdType: opts.algoOrdType,
10877
11206
  cycleId: opts.cycleId
10878
11207
  });
10879
- const orders = getData7(result) ?? [];
10880
- if (opts.json) return printJson(orders);
10881
- if (!orders.length) {
11208
+ const rows = getData7(result) ?? [];
11209
+ if (opts.json) return printJson(rows);
11210
+ if (!rows.length) {
10882
11211
  outputLine("No sub-orders");
10883
11212
  return;
10884
11213
  }
10885
- printTable(
10886
- orders.map((o) => ({
10887
- cycleId: o["cycleId"],
10888
- status: o["cycleStatus"],
10889
- current: o["currentCycle"] ? "yes" : "",
10890
- avgPx: o["avgPx"],
10891
- tpPx: o["tpPx"],
10892
- realizedPnl: o["realizedPnl"],
10893
- fee: o["fee"],
10894
- startTime: o["startTime"] ? new Date(Number(o["startTime"])).toLocaleString() : ""
10895
- }))
10896
- );
11214
+ if (opts.cycleId) {
11215
+ printTable(
11216
+ rows.map((o) => ({
11217
+ ordId: o["ordId"],
11218
+ side: o["side"],
11219
+ ordType: o["ordType"],
11220
+ px: o["px"],
11221
+ filledSz: o["filledSz"],
11222
+ avgFillPx: o["avgFillPx"],
11223
+ state: o["state"],
11224
+ fee: o["fee"]
11225
+ }))
11226
+ );
11227
+ } else {
11228
+ printTable(
11229
+ rows.map((o) => ({
11230
+ cycleId: o["cycleId"],
11231
+ status: o["cycleStatus"],
11232
+ current: o["currentCycle"] ? "yes" : "",
11233
+ avgPx: o["avgPx"],
11234
+ tpPx: o["tpPx"],
11235
+ realizedPnl: o["realizedPnl"],
11236
+ fee: o["fee"],
11237
+ startTime: o["startTime"] ? new Date(Number(o["startTime"])).toLocaleString() : ""
11238
+ }))
11239
+ );
11240
+ }
10897
11241
  }
10898
11242
 
10899
11243
  // src/commands/onchain-earn.ts
@@ -11193,7 +11537,7 @@ async function cmdDcdQuoteAndBuy(run, opts) {
11193
11537
  // src/index.ts
11194
11538
  var _require3 = createRequire3(import.meta.url);
11195
11539
  var CLI_VERSION2 = _require3("../package.json").version;
11196
- var GIT_HASH2 = true ? "9f66f84" : "dev";
11540
+ var GIT_HASH2 = true ? "c270a0b" : "dev";
11197
11541
  function handleConfigCommand(action, rest, json, lang, force) {
11198
11542
  if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
11199
11543
  if (action === "show") return cmdConfigShow(json);
@@ -11331,6 +11675,7 @@ function handleSpotAlgoCommand(run, subAction, v, json) {
11331
11675
  side: v.side,
11332
11676
  ordType: v.ordType ?? "conditional",
11333
11677
  sz: v.sz,
11678
+ tgtCcy: v.tgtCcy,
11334
11679
  tpTriggerPx: v.tpTriggerPx,
11335
11680
  tpOrdPx: v.tpOrdPx,
11336
11681
  slTriggerPx: v.slTriggerPx,
@@ -11425,6 +11770,7 @@ function handleSwapAlgoCommand(run, subAction, v, json) {
11425
11770
  sz: v.sz,
11426
11771
  posSide: v.posSide,
11427
11772
  tdMode: v.tdMode ?? "cross",
11773
+ tgtCcy: v.tgtCcy,
11428
11774
  tpTriggerPx: v.tpTriggerPx,
11429
11775
  tpOrdPx: v.tpOrdPx,
11430
11776
  slTriggerPx: v.slTriggerPx,
@@ -11537,6 +11883,7 @@ function handleOptionAlgoCommand(run, subAction, v, json) {
11537
11883
  side: v.side,
11538
11884
  ordType: v.ordType ?? "conditional",
11539
11885
  sz: v.sz,
11886
+ tgtCcy: v.tgtCcy,
11540
11887
  tpTriggerPx: v.tpTriggerPx,
11541
11888
  tpOrdPx: v.tpOrdPx,
11542
11889
  slTriggerPx: v.slTriggerPx,
@@ -11637,6 +11984,7 @@ function handleFuturesAlgoCommand(run, subAction, v, json) {
11637
11984
  sz: v.sz,
11638
11985
  posSide: v.posSide,
11639
11986
  tdMode: v.tdMode ?? "cross",
11987
+ tgtCcy: v.tgtCcy,
11640
11988
  tpTriggerPx: v.tpTriggerPx,
11641
11989
  tpOrdPx: v.tpOrdPx,
11642
11990
  slTriggerPx: v.slTriggerPx,
@@ -11779,6 +12127,11 @@ function handleBotGridCommand(run, v, rest, json) {
11779
12127
  lever: v.lever,
11780
12128
  sz: v.sz,
11781
12129
  basePos: v.basePos,
12130
+ tpTriggerPx: v.tpTriggerPx,
12131
+ slTriggerPx: v.slTriggerPx,
12132
+ tpRatio: v.tpRatio,
12133
+ slRatio: v.slRatio,
12134
+ algoClOrdId: v.algoClOrdId,
11782
12135
  json
11783
12136
  });
11784
12137
  if (subAction === "stop")
@@ -11791,15 +12144,17 @@ function handleBotGridCommand(run, v, rest, json) {
11791
12144
  });
11792
12145
  }
11793
12146
  function handleBotDcaCommand(run, subAction, v, json) {
12147
+ const algoOrdType = v.algoOrdType ?? "contract_dca";
11794
12148
  if (subAction === "orders")
11795
- return cmdDcaOrders(run, { algoId: v.algoId, instId: v.instId, history: v.history ?? false, json });
12149
+ return cmdDcaOrders(run, { algoOrdType, algoId: v.algoId, instId: v.instId, history: v.history ?? false, json });
11796
12150
  if (subAction === "details")
11797
- return cmdDcaDetails(run, { algoId: v.algoId, json });
12151
+ return cmdDcaDetails(run, { algoId: v.algoId, algoOrdType, json });
11798
12152
  if (subAction === "sub-orders")
11799
- return cmdDcaSubOrders(run, { algoId: v.algoId, cycleId: v.cycleId, json });
12153
+ return cmdDcaSubOrders(run, { algoId: v.algoId, algoOrdType, cycleId: v.cycleId, json });
11800
12154
  if (subAction === "create")
11801
12155
  return cmdDcaCreate(run, {
11802
12156
  instId: v.instId,
12157
+ algoOrdType,
11803
12158
  lever: v.lever,
11804
12159
  direction: v.direction,
11805
12160
  initOrdAmt: v.initOrdAmt,
@@ -11814,10 +12169,13 @@ function handleBotDcaCommand(run, subAction, v, json) {
11814
12169
  allowReinvest: v.allowReinvest,
11815
12170
  triggerStrategy: v.triggerStrategy,
11816
12171
  triggerPx: v.triggerPx,
12172
+ algoClOrdId: v.algoClOrdId,
12173
+ reserveFunds: v.reserveFunds,
12174
+ tradeQuoteCcy: v.tradeQuoteCcy,
11817
12175
  json
11818
12176
  });
11819
12177
  if (subAction === "stop")
11820
- return cmdDcaStop(run, { algoId: v.algoId, json });
12178
+ return cmdDcaStop(run, { algoId: v.algoId, algoOrdType, stopType: v.stopType, json });
11821
12179
  }
11822
12180
  function handleBotCommand(run, action, rest, v, json) {
11823
12181
  if (action === "grid") return handleBotGridCommand(run, v, rest, json);
@@ -11829,8 +12187,32 @@ function handleEarnCommand(run, submodule, rest, v, json) {
11829
12187
  if (submodule === "savings") return handleEarnSavingsCommand(run, action, innerRest, v, json);
11830
12188
  if (submodule === "onchain") return handleEarnOnchainCommand(run, action, v, json);
11831
12189
  if (submodule === "dcd") return handleEarnDcdCommand(run, action, v, json);
12190
+ if (submodule === "auto-earn") return handleEarnAutoEarnCommand(run, action, innerRest, v, json);
11832
12191
  errorLine(`Unknown earn sub-module: ${submodule}`);
11833
- errorLine("Valid: savings, onchain, dcd");
12192
+ errorLine("Valid: savings, onchain, dcd, auto-earn");
12193
+ process.exitCode = 1;
12194
+ }
12195
+ function handleEarnAutoEarnCommand(run, action, rest, v, json) {
12196
+ const ccy = rest[0] ?? v.ccy;
12197
+ if (action === "status") return cmdAutoEarnStatus(run, ccy, json);
12198
+ if (action === "on") {
12199
+ if (!ccy) {
12200
+ errorLine("Currency required: okx earn auto-earn on <ccy>");
12201
+ process.exitCode = 1;
12202
+ return;
12203
+ }
12204
+ return cmdAutoEarnOn(run, ccy, json);
12205
+ }
12206
+ if (action === "off") {
12207
+ if (!ccy) {
12208
+ errorLine("Currency required: okx earn auto-earn off <ccy>");
12209
+ process.exitCode = 1;
12210
+ return;
12211
+ }
12212
+ return cmdAutoEarnOff(run, ccy, json);
12213
+ }
12214
+ errorLine(`Unknown auto-earn command: ${action}`);
12215
+ errorLine("Valid: status, on, off");
11834
12216
  process.exitCode = 1;
11835
12217
  }
11836
12218
  function handleEarnSavingsCommand(run, action, rest, v, json) {
@@ -11840,7 +12222,6 @@ function handleEarnSavingsCommand(run, action, rest, v, json) {
11840
12222
  if (action === "redeem") return cmdEarnSavingsRedeem(run, { ccy: v.ccy, amt: v.amt, json });
11841
12223
  if (action === "set-rate") return cmdEarnSetLendingRate(run, { ccy: v.ccy, rate: v.rate, json });
11842
12224
  if (action === "lending-history") return cmdEarnLendingHistory(run, { ccy: v.ccy, limit, json });
11843
- if (action === "rate-summary") return cmdEarnLendingRateSummary(run, rest[0] ?? v.ccy, json);
11844
12225
  if (action === "rate-history") return cmdEarnLendingRateHistory(run, { ccy: v.ccy, limit, json });
11845
12226
  errorLine(`Unknown earn savings command: ${action}`);
11846
12227
  process.exitCode = 1;