@okx_ai/okx-trade-cli 1.3.9 → 1.4.0-beta.1

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
@@ -2111,6 +2111,13 @@ function requireString(args, key) {
2111
2111
  }
2112
2112
  return value;
2113
2113
  }
2114
+ function requireBoolean(args, key) {
2115
+ const value = readBoolean(args, key);
2116
+ if (value === void 0) {
2117
+ throw new ValidationError(`Missing required parameter "${key}".`);
2118
+ }
2119
+ return value;
2120
+ }
2114
2121
  function assertEnum(value, key, values) {
2115
2122
  if (value === void 0) {
2116
2123
  return;
@@ -5545,6 +5552,136 @@ function registerGridTools() {
5545
5552
  );
5546
5553
  return normalizeWrite(response);
5547
5554
  }
5555
+ },
5556
+ {
5557
+ name: "grid_get_positions",
5558
+ title: "Grid Bot Get Positions",
5559
+ module: "bot.grid",
5560
+ description: "Get open contract-grid positions for an active or recently-stopped contract-grid bot. Returns liquidation price, margin ratio, and unrealized PnL.",
5561
+ isWrite: false,
5562
+ inputSchema: {
5563
+ type: "object",
5564
+ properties: {
5565
+ algoId: { type: "string", description: "Grid bot algo order ID" },
5566
+ algoOrdType: {
5567
+ type: "string",
5568
+ enum: ["contract_grid"],
5569
+ description: "Must be contract_grid"
5570
+ }
5571
+ },
5572
+ required: ["algoId", "algoOrdType"]
5573
+ },
5574
+ handler: async (rawArgs, context) => {
5575
+ const args = asRecord(rawArgs);
5576
+ const response = await context.client.privateGet(
5577
+ "/api/v5/tradingBot/grid/positions",
5578
+ {
5579
+ algoId: requireString(args, "algoId"),
5580
+ algoOrdType: requireString(args, "algoOrdType")
5581
+ },
5582
+ privateRateLimit("grid_get_positions", 20)
5583
+ );
5584
+ return normalizeResponse(response);
5585
+ }
5586
+ },
5587
+ {
5588
+ name: "grid_get_liquidate_price",
5589
+ title: "Grid Bot Get Liquidation Price",
5590
+ module: "bot.grid",
5591
+ description: "Estimate the liquidation price for a contract-grid bot before creating it. Contract grid only. Requires the full intended config: instId, sz (margin), lever, the grid range (maxPx, minPx, gridNum) and direction. runType defaults to arithmetic ('1'); triggerStrategy is optional.",
5592
+ isWrite: false,
5593
+ inputSchema: {
5594
+ type: "object",
5595
+ properties: {
5596
+ instId: { type: "string", description: "Instrument ID, e.g. BTC-USDT-SWAP" },
5597
+ sz: { type: "string", description: "Margin size in USDT (or base coin for CoinM)" },
5598
+ lever: { type: "string", description: "Leverage, e.g. '5'" },
5599
+ direction: {
5600
+ type: "string",
5601
+ enum: ["long", "short", "neutral"],
5602
+ description: "Bot direction (pass 'neutral' for a neutral bot)"
5603
+ },
5604
+ basePos: { type: "boolean", description: "Whether the base position is opened" },
5605
+ maxPx: { type: "string", description: "Upper price of the grid range" },
5606
+ minPx: { type: "string", description: "Lower price of the grid range" },
5607
+ gridNum: { type: "string", description: "Number of grids" },
5608
+ runType: {
5609
+ type: "string",
5610
+ enum: ["1", "2"],
5611
+ description: "1=arithmetic (default); 2=geometric"
5612
+ },
5613
+ triggerStrategy: {
5614
+ type: "string",
5615
+ enum: ["instant", "price", "rsi", "webhook"],
5616
+ description: "Entry trigger strategy for the intended bot"
5617
+ }
5618
+ },
5619
+ required: ["instId", "sz", "lever", "maxPx", "minPx", "gridNum", "direction"]
5620
+ },
5621
+ handler: async (rawArgs, context) => {
5622
+ const args = asRecord(rawArgs);
5623
+ const missing = ["maxPx", "minPx", "gridNum", "direction"].filter(
5624
+ (key) => readString(args, key) === void 0
5625
+ );
5626
+ if (missing.length > 0) {
5627
+ throw new OkxApiError(
5628
+ `Missing required parameter(s): ${missing.join(", ")}. A liquidation-price estimate needs the full intended config \u2014 instId, sz, lever, maxPx, minPx, gridNum and direction.`,
5629
+ { code: "", endpoint: "grid_get_liquidate_price" }
5630
+ );
5631
+ }
5632
+ const response = await context.client.privateGet(
5633
+ "/api/v5/tradingBot/grid/liquidate-price",
5634
+ compactObject({
5635
+ instId: requireString(args, "instId"),
5636
+ sz: requireString(args, "sz"),
5637
+ lever: requireString(args, "lever"),
5638
+ direction: readString(args, "direction"),
5639
+ basePos: readBoolean(args, "basePos"),
5640
+ maxPx: readString(args, "maxPx"),
5641
+ minPx: readString(args, "minPx"),
5642
+ gridNum: readString(args, "gridNum"),
5643
+ runType: readString(args, "runType") ?? "1",
5644
+ triggerStrategy: readString(args, "triggerStrategy")
5645
+ }),
5646
+ privateRateLimit("grid_get_liquidate_price", 20)
5647
+ );
5648
+ return normalizeResponse(response);
5649
+ }
5650
+ },
5651
+ {
5652
+ name: "grid_close_position",
5653
+ title: "Grid Bot Close Position",
5654
+ module: "bot.grid",
5655
+ description: "[CAUTION] Close the remaining open position of a contract-grid bot that was stopped with stopType='2'. Use grid_get_positions first to confirm the position exists and check its size before closing. Use mktClose=true for an immediate market close, or mktClose=false to place a limit close order (provide sz and px).",
5656
+ isWrite: true,
5657
+ inputSchema: {
5658
+ type: "object",
5659
+ properties: {
5660
+ algoId: { type: "string", description: "Grid bot algo order ID" },
5661
+ mktClose: {
5662
+ type: "boolean",
5663
+ description: "Required, no default (fund-moving): true=market close immediately; false=limit close (requires sz and px)."
5664
+ },
5665
+ sz: { type: "string", description: "Close size (required when mktClose=false)" },
5666
+ px: { type: "string", description: "Limit price (required when mktClose=false)" }
5667
+ },
5668
+ required: ["algoId", "mktClose"]
5669
+ },
5670
+ handler: async (rawArgs, context) => {
5671
+ const args = asRecord(rawArgs);
5672
+ const mktClose = requireBoolean(args, "mktClose");
5673
+ const response = await context.client.privatePost(
5674
+ "/api/v5/tradingBot/grid/close-position",
5675
+ compactObject({
5676
+ algoId: requireString(args, "algoId"),
5677
+ mktClose,
5678
+ sz: readString(args, "sz"),
5679
+ px: readString(args, "px")
5680
+ }),
5681
+ privateRateLimit("grid_close_position", 20)
5682
+ );
5683
+ return normalizeWrite(response);
5684
+ }
5548
5685
  }
5549
5686
  ];
5550
5687
  }
@@ -10771,9 +10908,9 @@ var CALENDAR_REGIONS = [
10771
10908
  "zimbabwe"
10772
10909
  ];
10773
10910
  var NEWS_LANGUAGE = ["en-US", "zh-CN"];
10774
- function langHeader(lang) {
10775
- if (lang === "zh-CN" || lang === "zh_CN") return { "Accept-Language": "zh-CN" };
10776
- return { "Accept-Language": "en-US" };
10911
+ function acceptLanguage(lang) {
10912
+ if (lang === "zh-CN" || lang === "zh_CN") return "zh_CN";
10913
+ return "en_US";
10777
10914
  }
10778
10915
  var NEWS_DETAIL_LVL = ["brief", "summary", "full"];
10779
10916
  var NEWS_IMPORTANCE = ["high", "low"];
@@ -10831,10 +10968,10 @@ function registerNewsTools() {
10831
10968
  end: readNumber(args, "end"),
10832
10969
  detailLvl: readString(args, "detailLvl"),
10833
10970
  limit: readNumber(args, "limit") ?? 10,
10834
- cursor: readString(args, "after")
10971
+ cursor: readString(args, "after"),
10972
+ acceptLanguage: acceptLanguage(readString(args, "language"))
10835
10973
  }),
10836
- publicRateLimit("news_get_latest", 20),
10837
- langHeader(readString(args, "language"))
10974
+ publicRateLimit("news_get_latest", 20)
10838
10975
  );
10839
10976
  return normalizeResponse(response);
10840
10977
  }
@@ -10875,10 +11012,10 @@ function registerNewsTools() {
10875
11012
  begin: readNumber(args, "begin"),
10876
11013
  end: readNumber(args, "end"),
10877
11014
  detailLvl: readString(args, "detailLvl"),
10878
- limit: readNumber(args, "limit") ?? 10
11015
+ limit: readNumber(args, "limit") ?? 10,
11016
+ acceptLanguage: acceptLanguage(readString(args, "language"))
10879
11017
  }),
10880
- publicRateLimit("news_get_by_coin", 20),
10881
- langHeader(readString(args, "language"))
11018
+ publicRateLimit("news_get_by_coin", 20)
10882
11019
  );
10883
11020
  return normalizeResponse(response);
10884
11021
  }
@@ -10933,10 +11070,10 @@ function registerNewsTools() {
10933
11070
  end: readNumber(args, "end"),
10934
11071
  detailLvl: readString(args, "detailLvl"),
10935
11072
  limit: readNumber(args, "limit") ?? 10,
10936
- cursor: readString(args, "after")
11073
+ cursor: readString(args, "after"),
11074
+ acceptLanguage: acceptLanguage(readString(args, "language"))
10937
11075
  }),
10938
- publicRateLimit("news_search", 20),
10939
- langHeader(readString(args, "language"))
11076
+ publicRateLimit("news_search", 20)
10940
11077
  );
10941
11078
  return normalizeResponse(response);
10942
11079
  }
@@ -10966,9 +11103,8 @@ function registerNewsTools() {
10966
11103
  }
10967
11104
  const response = await context.client.privateGet(
10968
11105
  NEWS_DETAIL,
10969
- { id },
10970
- publicRateLimit("news_get_detail", 20),
10971
- langHeader(readString(args, "language"))
11106
+ { id, acceptLanguage: acceptLanguage(readString(args, "language")) },
11107
+ publicRateLimit("news_get_detail", 20)
10972
11108
  );
10973
11109
  return normalizeResponse(response);
10974
11110
  }
@@ -14923,7 +15059,7 @@ async function cmdDiagnoseMcp(options = {}) {
14923
15059
 
14924
15060
  // src/commands/diagnose.ts
14925
15061
  var CLI_VERSION = readCliVersion();
14926
- var GIT_HASH = true ? "2b5e5c85" : "dev";
15062
+ var GIT_HASH = true ? "0a33fb41" : "dev";
14927
15063
  function maskKey2(key) {
14928
15064
  if (!key) return "(not set)";
14929
15065
  if (key.length <= 8) return "****";
@@ -16154,6 +16290,21 @@ var CLI_REGISTRY = {
16154
16290
  toolName: "grid_stop_order",
16155
16291
  usage: "okx bot grid stop --algoId <id> --algoOrdType <type> --instId <id> [--stopType <1|2>]",
16156
16292
  description: "Stop a running grid bot order"
16293
+ },
16294
+ positions: {
16295
+ toolName: "grid_get_positions",
16296
+ usage: "okx bot grid positions --algoId <id> --algoOrdType contract_grid",
16297
+ description: "Get open contract-grid positions (liquidation price, margin ratio, unrealized PnL)"
16298
+ },
16299
+ "liquidate-price": {
16300
+ toolName: "grid_get_liquidate_price",
16301
+ usage: "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>]",
16302
+ description: "Estimate liquidation price for a contract-grid bot"
16303
+ },
16304
+ "close-position": {
16305
+ toolName: "grid_close_position",
16306
+ usage: "okx bot grid close-position --algoId <id> (--mktClose | --no-mktClose) [--sz <size>] [--px <price>]",
16307
+ description: "Close remaining open position after bot stopped with stopType=2 (close mode is required: --mktClose for market, --no-mktClose --sz --px for limit)"
16157
16308
  }
16158
16309
  }
16159
16310
  },
@@ -17166,12 +17317,19 @@ var CLI_OPTIONS = {
17166
17317
  quoteSz: { type: "string" },
17167
17318
  baseSz: { type: "string" },
17168
17319
  direction: { type: "string" },
17169
- basePos: { type: "boolean", default: true },
17320
+ // No parser default: a global default:true would bleed into `liquidate-price`
17321
+ // (forcing basePos=true, wrong for neutral bots). `grid_create_order`'s handler
17322
+ // already applies the `?? true` default, so create is unaffected; liquidate-price
17323
+ // can now omit basePos. Use --basePos / --no-basePos to set it explicitly.
17324
+ basePos: { type: "boolean" },
17170
17325
  tpRatio: { type: "string" },
17171
17326
  slRatio: { type: "string" },
17172
17327
  algoClOrdId: { type: "string" },
17173
17328
  stopType: { type: "string" },
17174
17329
  topUpAmt: { type: "string" },
17330
+ // grid position management
17331
+ // Fund-moving: no default — close-position requires an explicit --mktClose/--no-mktClose.
17332
+ mktClose: { type: "boolean" },
17175
17333
  live: { type: "boolean", default: false },
17176
17334
  // grid sub-orders pending filter (separate from global --live trading mode,
17177
17335
  // which is mutually exclusive with --demo and so unusable in demo mode)
@@ -20492,6 +20650,66 @@ async function cmdGridStop(run, opts) {
20492
20650
  if (opts.json) return printJson(data);
20493
20651
  emitWriteResult5(data?.[0], "Grid bot stopped", "algoId");
20494
20652
  }
20653
+ async function cmdGridPositions(run, opts) {
20654
+ const result = await run("grid_get_positions", {
20655
+ algoId: opts.algoId,
20656
+ algoOrdType: opts.algoOrdType
20657
+ });
20658
+ const positions = getData8(result) ?? [];
20659
+ if (opts.json) return printJson(positions);
20660
+ if (!positions.length) {
20661
+ outputLine("No positions");
20662
+ return;
20663
+ }
20664
+ printTable(
20665
+ positions.map((p) => ({
20666
+ algoId: p["algoId"],
20667
+ instId: p["instId"],
20668
+ pos: p["pos"],
20669
+ posSide: p["posSide"],
20670
+ liqPx: p["liqPx"],
20671
+ mgnRatio: p["mgnRatio"],
20672
+ upl: p["upl"]
20673
+ }))
20674
+ );
20675
+ }
20676
+ async function cmdGridLiquidatePrice(run, opts) {
20677
+ const result = await run("grid_get_liquidate_price", {
20678
+ instId: opts.instId,
20679
+ sz: opts.sz,
20680
+ lever: opts.lever,
20681
+ direction: opts.direction,
20682
+ basePos: opts.basePos,
20683
+ maxPx: opts.maxPx,
20684
+ minPx: opts.minPx,
20685
+ gridNum: opts.gridNum,
20686
+ runType: opts.runType,
20687
+ triggerStrategy: opts.triggerStrategy
20688
+ });
20689
+ const data = getData8(result) ?? [];
20690
+ if (opts.json) return printJson(data);
20691
+ const item = data[0];
20692
+ if (!item) {
20693
+ outputLine("No data");
20694
+ return;
20695
+ }
20696
+ printKv({
20697
+ instId: item["instId"],
20698
+ liqPx: item["liqPx"],
20699
+ direction: item["direction"]
20700
+ });
20701
+ }
20702
+ async function cmdGridClosePosition(run, opts) {
20703
+ const result = await run("grid_close_position", {
20704
+ algoId: opts.algoId,
20705
+ mktClose: opts.mktClose,
20706
+ sz: opts.sz,
20707
+ px: opts.px
20708
+ });
20709
+ const data = getData8(result);
20710
+ if (opts.json) return printJson(data);
20711
+ emitWriteResult5(data?.[0], "Grid position closed", "algoId");
20712
+ }
20495
20713
  async function cmdDcaCreate(run, opts) {
20496
20714
  const result = await run("dca_create_order", {
20497
20715
  instId: opts.instId,
@@ -21822,7 +22040,7 @@ async function cmdEventCancel(run, opts) {
21822
22040
  // src/index.ts
21823
22041
  var _require3 = createRequire3(import.meta.url);
21824
22042
  var CLI_VERSION2 = _require3("../package.json").version;
21825
- var GIT_HASH2 = true ? "2b5e5c85" : "dev";
22043
+ var GIT_HASH2 = true ? "0a33fb41" : "dev";
21826
22044
  function handlePilotCommand(action, json, force, binaryPath) {
21827
22045
  if (action === "status") return cmdPilotStatus(json, binaryPath);
21828
22046
  if (action === "install") return cmdPilotInstall(json, binaryPath);
@@ -22764,7 +22982,41 @@ function handleBotGridCommand(run, v, rest, json) {
22764
22982
  stopType: v.stopType,
22765
22983
  json
22766
22984
  });
22767
- unknownSubcommand("bot grid", subAction, ["orders", "details", "sub-orders", "create", "amend", "stop"]);
22985
+ if (subAction === "positions")
22986
+ return cmdGridPositions(run, {
22987
+ algoId: v.algoId,
22988
+ algoOrdType: v.algoOrdType,
22989
+ json
22990
+ });
22991
+ if (subAction === "liquidate-price")
22992
+ return cmdGridLiquidatePrice(run, {
22993
+ instId: v.instId,
22994
+ sz: v.sz,
22995
+ lever: v.lever,
22996
+ direction: v.direction,
22997
+ basePos: v.basePos,
22998
+ maxPx: v.maxPx,
22999
+ minPx: v.minPx,
23000
+ gridNum: v.gridNum,
23001
+ runType: v.runType,
23002
+ triggerStrategy: v.triggerStrategy,
23003
+ json
23004
+ });
23005
+ if (subAction === "close-position") {
23006
+ if (v.mktClose === void 0) {
23007
+ errorLine("Missing required --mktClose/--no-mktClose: okx bot grid close-position --algoId <id> (--mktClose | --no-mktClose [--sz <size>] [--px <price>])");
23008
+ process.exitCode = 1;
23009
+ return;
23010
+ }
23011
+ return cmdGridClosePosition(run, {
23012
+ algoId: v.algoId,
23013
+ mktClose: v.mktClose,
23014
+ sz: v.sz,
23015
+ px: v.px,
23016
+ json
23017
+ });
23018
+ }
23019
+ unknownSubcommand("bot grid", subAction, ["orders", "details", "sub-orders", "create", "amend", "stop", "positions", "liquidate-price", "close-position"]);
22768
23020
  }
22769
23021
  function handleBotDcaCommand(run, subAction, v, json) {
22770
23022
  const algoOrdType = v.algoOrdType ?? "contract_dca";