@okx_ai/okx-trade-cli 1.2.5 → 1.2.6

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
@@ -1019,9 +1019,9 @@ var OKX_CODE_BEHAVIORS = {
1019
1019
  "50100": { retry: false, suggestion: "API key lacks required permissions. Update API key permissions." },
1020
1020
  "50110": { retry: false, suggestion: "API key expired. Generate a new API key." },
1021
1021
  // Insufficient funds / margin → do not retry
1022
- "51008": { retry: false, suggestion: "Insufficient balance. Top up account before retrying." },
1023
- "51119": { retry: false, suggestion: "Insufficient margin. Add margin before retrying." },
1024
- "51127": { retry: false, suggestion: "Insufficient available margin. Reduce position or add margin." },
1022
+ "51008": { retry: false, suggestion: "Insufficient balance in trading account. Check funding account via account_get_asset_balance \u2014 funds may be there. Use account_transfer (from=18, to=6) to move funds to trading account, then retry." },
1023
+ "51119": { retry: false, suggestion: "Insufficient margin. Add margin or check funding account (account_get_asset_balance). Transfer via account_transfer (from=18, to=6) if needed." },
1024
+ "51127": { retry: false, suggestion: "Insufficient available margin. Reduce position, add margin, or transfer from funding account (account_transfer from=18 to=6)." },
1025
1025
  // Instrument unavailable → do not retry
1026
1026
  "51021": { retry: false, suggestion: "Instrument does not exist. Check instId." },
1027
1027
  "51022": { retry: false, suggestion: "Instrument not available for trading." },
@@ -1104,6 +1104,15 @@ var OkxRestClient = class {
1104
1104
  rateLimit
1105
1105
  });
1106
1106
  }
1107
+ async publicPost(path42, body, rateLimit) {
1108
+ return this.request({
1109
+ method: "POST",
1110
+ path: path42,
1111
+ auth: "public",
1112
+ body,
1113
+ rateLimit
1114
+ });
1115
+ }
1107
1116
  async privatePost(path42, body, rateLimit) {
1108
1117
  return this.request({
1109
1118
  method: "POST",
@@ -1258,46 +1267,6 @@ var OkxRestClient = class {
1258
1267
  return this.processResponse(rawText, response, elapsed, traceId, reqConfig, requestPath);
1259
1268
  }
1260
1269
  };
1261
- var DEFAULT_SOURCE_TAG = "MCP";
1262
- var OKX_SITES = {
1263
- global: {
1264
- label: "Global",
1265
- apiBaseUrl: "https://www.okx.com",
1266
- webUrl: "https://www.okx.com"
1267
- },
1268
- eea: {
1269
- label: "EEA",
1270
- apiBaseUrl: "https://eea.okx.com",
1271
- webUrl: "https://my.okx.com"
1272
- },
1273
- us: {
1274
- label: "US",
1275
- apiBaseUrl: "https://app.okx.com",
1276
- webUrl: "https://app.okx.com"
1277
- }
1278
- };
1279
- var SITE_IDS = Object.keys(OKX_SITES);
1280
- var BOT_SUB_MODULE_IDS = [
1281
- "bot.grid",
1282
- "bot.dca"
1283
- ];
1284
- var BOT_DEFAULT_SUB_MODULES = ["bot.grid"];
1285
- var EARN_SUB_MODULE_IDS = [
1286
- "earn.savings",
1287
- "earn.onchain",
1288
- "earn.dcd"
1289
- ];
1290
- var MODULES = [
1291
- "market",
1292
- "spot",
1293
- "swap",
1294
- "futures",
1295
- "option",
1296
- "account",
1297
- ...EARN_SUB_MODULE_IDS,
1298
- ...BOT_SUB_MODULE_IDS
1299
- ];
1300
- var DEFAULT_MODULES = ["spot", "swap", "option", "account", ...BOT_DEFAULT_SUB_MODULES];
1301
1270
  function asRecord(value) {
1302
1271
  if (!value || typeof value !== "object" || Array.isArray(value)) {
1303
1272
  return {};
@@ -1422,6 +1391,152 @@ function assertNotDemo(config, endpoint) {
1422
1391
  );
1423
1392
  }
1424
1393
  }
1394
+ var INDICATOR_BARS = [
1395
+ "3m",
1396
+ "5m",
1397
+ "15m",
1398
+ "1H",
1399
+ "4H",
1400
+ "12Hutc",
1401
+ "1Dutc",
1402
+ "3Dutc",
1403
+ "1Wutc"
1404
+ ];
1405
+ var INDICATOR_CODE_OVERRIDES = {
1406
+ "rainbow": "BTCRAINBOW",
1407
+ "range-filter": "RANGEFILTER",
1408
+ "stoch-rsi": "STOCHRSI",
1409
+ "pi-cycle-top": "PI_CYCLE_TOP",
1410
+ "pi-cycle-bottom": "PI_CYCLE_BOTTOM",
1411
+ // boll is an alias for bb; server supports BB not BOLL
1412
+ "boll": "BB"
1413
+ };
1414
+ function resolveIndicatorCode(name) {
1415
+ const lower = name.toLowerCase();
1416
+ return INDICATOR_CODE_OVERRIDES[lower] ?? name.toUpperCase().replace(/-/g, "_");
1417
+ }
1418
+ function readNumberArray(args, key) {
1419
+ const value = args[key];
1420
+ if (value === void 0 || value === null) return void 0;
1421
+ if (!Array.isArray(value)) return void 0;
1422
+ return value.map((item) => Number(item));
1423
+ }
1424
+ function registerIndicatorTools() {
1425
+ return [
1426
+ {
1427
+ name: "market_get_indicator",
1428
+ module: "market",
1429
+ description: "Get technical indicator values for an instrument (MA, EMA, RSI, MACD, BB, KDJ, SUPERTREND, AHR999, BTCRAINBOW, and more). No credentials required.",
1430
+ isWrite: false,
1431
+ inputSchema: {
1432
+ type: "object",
1433
+ properties: {
1434
+ instId: {
1435
+ type: "string",
1436
+ description: "Instrument ID, e.g. BTC-USDT"
1437
+ },
1438
+ indicator: {
1439
+ type: "string",
1440
+ description: "Indicator name (case-insensitive). Examples: ma, ema, rsi, macd, bb, kdj, supertrend, ahr999, rainbow, pi-cycle-top, pi-cycle-bottom, mayer, envelope, halftrend, alphatrend, pmax, waddah, tdi, qqe, range-filter"
1441
+ },
1442
+ bar: {
1443
+ type: "string",
1444
+ enum: [...INDICATOR_BARS],
1445
+ description: "Timeframe. Default: 1H"
1446
+ },
1447
+ params: {
1448
+ type: "array",
1449
+ items: { type: "number" },
1450
+ description: "Indicator parameters, e.g. [5, 20] for MA with periods 5 and 20"
1451
+ },
1452
+ returnList: {
1453
+ type: "boolean",
1454
+ description: "Return a historical list instead of the latest value only. Default: false"
1455
+ },
1456
+ limit: {
1457
+ type: "integer",
1458
+ minimum: 1,
1459
+ maximum: 100,
1460
+ description: "Number of historical records to return (only used when returnList=true). Default: 10"
1461
+ },
1462
+ backtestTime: {
1463
+ type: "integer",
1464
+ description: "Backtest timestamp in milliseconds. Omit for live (real-time) mode"
1465
+ }
1466
+ },
1467
+ required: ["instId", "indicator"]
1468
+ },
1469
+ handler: async (rawArgs, context) => {
1470
+ const args = asRecord(rawArgs);
1471
+ const instId = requireString(args, "instId");
1472
+ const indicator = requireString(args, "indicator");
1473
+ const bar = readString(args, "bar") ?? "1H";
1474
+ const params = readNumberArray(args, "params");
1475
+ const returnList = readBoolean(args, "returnList") ?? false;
1476
+ const limit = readNumber(args, "limit") ?? 10;
1477
+ const backtestTime = readNumber(args, "backtestTime");
1478
+ const apiCode = resolveIndicatorCode(indicator);
1479
+ const indicatorConfig = compactObject({
1480
+ paramList: params && params.length > 0 ? params : void 0,
1481
+ returnList,
1482
+ limit: returnList ? limit : void 0
1483
+ });
1484
+ const body = compactObject({
1485
+ instId,
1486
+ timeframes: [bar],
1487
+ indicators: { [apiCode]: indicatorConfig },
1488
+ backtestTime
1489
+ });
1490
+ const response = await context.client.publicPost(
1491
+ "/api/v5/aigc/mcp/indicators",
1492
+ body,
1493
+ publicRateLimit("market_get_indicator", 5)
1494
+ );
1495
+ return normalizeResponse(response);
1496
+ }
1497
+ }
1498
+ ];
1499
+ }
1500
+ var DEFAULT_SOURCE_TAG = "MCP";
1501
+ var OKX_SITES = {
1502
+ global: {
1503
+ label: "Global",
1504
+ apiBaseUrl: "https://www.okx.com",
1505
+ webUrl: "https://www.okx.com"
1506
+ },
1507
+ eea: {
1508
+ label: "EEA",
1509
+ apiBaseUrl: "https://eea.okx.com",
1510
+ webUrl: "https://my.okx.com"
1511
+ },
1512
+ us: {
1513
+ label: "US",
1514
+ apiBaseUrl: "https://app.okx.com",
1515
+ webUrl: "https://app.okx.com"
1516
+ }
1517
+ };
1518
+ var SITE_IDS = Object.keys(OKX_SITES);
1519
+ var BOT_SUB_MODULE_IDS = [
1520
+ "bot.grid",
1521
+ "bot.dca"
1522
+ ];
1523
+ var BOT_DEFAULT_SUB_MODULES = ["bot.grid"];
1524
+ var EARN_SUB_MODULE_IDS = [
1525
+ "earn.savings",
1526
+ "earn.onchain",
1527
+ "earn.dcd"
1528
+ ];
1529
+ var MODULES = [
1530
+ "market",
1531
+ "spot",
1532
+ "swap",
1533
+ "futures",
1534
+ "option",
1535
+ "account",
1536
+ ...EARN_SUB_MODULE_IDS,
1537
+ ...BOT_SUB_MODULE_IDS
1538
+ ];
1539
+ var DEFAULT_MODULES = ["spot", "swap", "option", "account", ...BOT_DEFAULT_SUB_MODULES];
1425
1540
  function registerAccountTools() {
1426
1541
  return [
1427
1542
  {
@@ -4059,7 +4174,12 @@ function buildContractTradeTools(cfg) {
4059
4174
  },
4060
4175
  sz: {
4061
4176
  type: "string",
4062
- description: "Contracts count (NOT USDT). Use market_get_instruments for ctVal."
4177
+ description: "Contracts count by default. Set tgtCcy=quote_ccy to use USDT amount instead."
4178
+ },
4179
+ tgtCcy: {
4180
+ type: "string",
4181
+ enum: ["base_ccy", "quote_ccy"],
4182
+ description: "Size unit. base_ccy(default): sz in contracts, quote_ccy: sz in USDT"
4063
4183
  },
4064
4184
  px: { type: "string", description: "Required for limit/post_only/fok/ioc" },
4065
4185
  reduceOnly: {
@@ -4087,6 +4207,7 @@ function buildContractTradeTools(cfg) {
4087
4207
  posSide: readString(args, "posSide"),
4088
4208
  ordType: requireString(args, "ordType"),
4089
4209
  sz: requireString(args, "sz"),
4210
+ tgtCcy: readString(args, "tgtCcy"),
4090
4211
  px: readString(args, "px"),
4091
4212
  reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
4092
4213
  clOrdId: readString(args, "clOrdId"),
@@ -5742,6 +5863,11 @@ function registerSpotTradeTools() {
5742
5863
  type: "string",
5743
5864
  description: "Buy market: quote amount, all others: base amount"
5744
5865
  },
5866
+ tgtCcy: {
5867
+ type: "string",
5868
+ enum: ["base_ccy", "quote_ccy"],
5869
+ description: "Size unit. base_ccy(default): sz in base (e.g. BTC), quote_ccy: sz in quote (e.g. USDT)"
5870
+ },
5745
5871
  px: {
5746
5872
  type: "string",
5747
5873
  description: "Required for limit/post_only/fok/ioc"
@@ -5780,6 +5906,7 @@ function registerSpotTradeTools() {
5780
5906
  side: requireString(args, "side"),
5781
5907
  ordType: requireString(args, "ordType"),
5782
5908
  sz: requireString(args, "sz"),
5909
+ tgtCcy: readString(args, "tgtCcy"),
5783
5910
  px: readString(args, "px"),
5784
5911
  clOrdId: readString(args, "clOrdId"),
5785
5912
  tag: context.config.sourceTag,
@@ -6508,6 +6635,7 @@ function registerSwapTradeTools() {
6508
6635
  function allToolSpecs() {
6509
6636
  return [
6510
6637
  ...registerMarketTools(),
6638
+ ...registerIndicatorTools(),
6511
6639
  ...registerSpotTradeTools(),
6512
6640
  ...registerSwapTradeTools(),
6513
6641
  ...registerFuturesTools(),
@@ -6539,20 +6667,38 @@ function readFullConfig() {
6539
6667
  const path42 = configFilePath();
6540
6668
  if (!existsSync(path42)) return { profiles: {} };
6541
6669
  const raw = readFileSync(path42, "utf-8");
6542
- return parse(raw);
6670
+ try {
6671
+ return parse(raw);
6672
+ } catch (err) {
6673
+ throw new ConfigError(
6674
+ `Failed to parse ${path42}: ${err instanceof Error ? err.message : String(err)}`,
6675
+ `If your passphrase or keys contain special characters:
6676
+ - Contains # \\ " \u2192 use single quotes: passphrase = 'your#pass'
6677
+ - Contains ' \u2192 use double quotes: passphrase = "your'pass"
6678
+ - Contains both \u2192 use triple quotes: passphrase = '''your'#pass'''
6679
+ Or re-run: okx config init`
6680
+ );
6681
+ }
6543
6682
  }
6544
6683
  function readTomlProfile(profileName) {
6545
6684
  const config = readFullConfig();
6546
6685
  const name = profileName ?? config.default_profile ?? "default";
6547
6686
  return config.profiles?.[name] ?? {};
6548
6687
  }
6688
+ var CONFIG_HEADER = `# OKX Trade Kit Configuration
6689
+ # If editing manually, wrap values containing special chars in quotes:
6690
+ # passphrase = 'value' (if value contains # \\ ")
6691
+ # passphrase = "value" (if value contains ')
6692
+ # passphrase = '''value''' (if value contains both)
6693
+
6694
+ `;
6549
6695
  function writeFullConfig(config) {
6550
6696
  const path42 = configFilePath();
6551
6697
  const dir = dirname(path42);
6552
6698
  if (!existsSync(dir)) {
6553
6699
  mkdirSync(dir, { recursive: true });
6554
6700
  }
6555
- writeFileSync(path42, stringify(config), "utf-8");
6701
+ writeFileSync(path42, CONFIG_HEADER + stringify(config), "utf-8");
6556
6702
  }
6557
6703
  function expandShorthand(moduleId) {
6558
6704
  if (moduleId === "all") return [...MODULES];
@@ -6877,6 +7023,73 @@ import tls from "tls";
6877
7023
  // src/commands/diagnose-utils.ts
6878
7024
  import fs2 from "fs";
6879
7025
  import { createRequire } from "module";
7026
+
7027
+ // src/formatter.ts
7028
+ import { EOL } from "os";
7029
+ var stdioOutput = {
7030
+ out: (message) => process.stdout.write(message),
7031
+ err: (message) => process.stderr.write(message)
7032
+ };
7033
+ var activeOutput = stdioOutput;
7034
+ function setOutput(impl) {
7035
+ activeOutput = impl;
7036
+ }
7037
+ function output(message) {
7038
+ activeOutput.out(message);
7039
+ }
7040
+ function errorOutput(message) {
7041
+ activeOutput.err(message);
7042
+ }
7043
+ function outputLine(message) {
7044
+ activeOutput.out(message + EOL);
7045
+ }
7046
+ function errorLine(message) {
7047
+ activeOutput.err(message + EOL);
7048
+ }
7049
+ function printJson(data) {
7050
+ activeOutput.out(JSON.stringify(data, null, 2) + EOL);
7051
+ }
7052
+ function printTable(rows) {
7053
+ if (rows.length === 0) {
7054
+ activeOutput.out("(no data)" + EOL);
7055
+ return;
7056
+ }
7057
+ const keys = Object.keys(rows[0]);
7058
+ const widths = keys.map(
7059
+ (k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? "").length))
7060
+ );
7061
+ const header = keys.map((k, i) => k.padEnd(widths[i])).join(" ");
7062
+ const divider = widths.map((w) => "-".repeat(w)).join(" ");
7063
+ activeOutput.out(header + EOL + divider + EOL);
7064
+ for (const row of rows) {
7065
+ activeOutput.out(keys.map((k, i) => String(row[k] ?? "").padEnd(widths[i])).join(" ") + EOL);
7066
+ }
7067
+ }
7068
+ function printKv(obj, indent = 0) {
7069
+ const pad = " ".repeat(indent);
7070
+ for (const [k, v] of Object.entries(obj)) {
7071
+ if (v !== null && typeof v === "object" && !Array.isArray(v)) {
7072
+ activeOutput.out(`${pad}${k}:${EOL}`);
7073
+ printKv(v, indent + 2);
7074
+ } else {
7075
+ activeOutput.out(`${pad}${k.padEnd(20 - indent)} ${v}${EOL}`);
7076
+ }
7077
+ }
7078
+ }
7079
+ function markFailedIfSCodeError(data) {
7080
+ if (!Array.isArray(data)) return;
7081
+ for (const item of data) {
7082
+ if (item !== null && typeof item === "object") {
7083
+ const sCode = item["sCode"];
7084
+ if (sCode !== void 0 && sCode !== "0" && sCode !== 0) {
7085
+ process.exitCode = 1;
7086
+ return;
7087
+ }
7088
+ }
7089
+ }
7090
+ }
7091
+
7092
+ // src/commands/diagnose-utils.ts
6880
7093
  var _require = createRequire(import.meta.url);
6881
7094
  function readCliVersion() {
6882
7095
  for (const rel of ["../package.json", "../../package.json"]) {
@@ -6893,18 +7106,14 @@ var Report = class {
6893
7106
  this.lines.push({ key, value });
6894
7107
  }
6895
7108
  print() {
6896
- const w = process.stdout.write.bind(process.stdout);
6897
7109
  const sep = "\u2500".repeat(52);
6898
- w(`
6899
- \u2500\u2500 Diagnostic Report (copy & share) ${sep.slice(35)}
6900
- `);
7110
+ outputLine("");
7111
+ outputLine(` \u2500\u2500 Diagnostic Report (copy & share) ${sep.slice(35)}`);
6901
7112
  for (const { key, value } of this.lines) {
6902
- w(` ${key.padEnd(14)} ${value}
6903
- `);
7113
+ outputLine(` ${key.padEnd(14)} ${value}`);
6904
7114
  }
6905
- w(` ${sep}
6906
-
6907
- `);
7115
+ outputLine(` ${sep}`);
7116
+ outputLine("");
6908
7117
  }
6909
7118
  /** Write report to a file path, returns true on success. */
6910
7119
  writeToFile(filePath) {
@@ -6925,31 +7134,25 @@ var Report = class {
6925
7134
  }
6926
7135
  };
6927
7136
  function ok(label, detail) {
6928
- process.stdout.write(` \u2713 ${label.padEnd(14)} ${detail}
6929
- `);
7137
+ outputLine(` \u2713 ${label.padEnd(14)} ${detail}`);
6930
7138
  }
6931
7139
  function fail(label, detail, hints) {
6932
- process.stdout.write(` \u2717 ${label.padEnd(14)} ${detail}
6933
- `);
7140
+ outputLine(` \u2717 ${label.padEnd(14)} ${detail}`);
6934
7141
  for (const hint of hints) {
6935
- process.stdout.write(` \u2192 ${hint}
6936
- `);
7142
+ outputLine(` \u2192 ${hint}`);
6937
7143
  }
6938
7144
  }
6939
7145
  function section(title) {
6940
- process.stdout.write(`
6941
- ${title}
6942
- `);
7146
+ outputLine("");
7147
+ outputLine(` ${title}`);
6943
7148
  }
6944
7149
  function writeReportIfRequested(report, outputPath) {
6945
7150
  if (!outputPath) return;
6946
7151
  const written = report.writeToFile(outputPath);
6947
7152
  if (written) {
6948
- process.stdout.write(` Report saved to: ${outputPath}
6949
- `);
7153
+ outputLine(` Report saved to: ${outputPath}`);
6950
7154
  } else {
6951
- process.stderr.write(` Warning: failed to write report to: ${outputPath}
6952
- `);
7155
+ errorLine(` Warning: failed to write report to: ${outputPath}`);
6953
7156
  }
6954
7157
  }
6955
7158
  function sanitize(value) {
@@ -7149,8 +7352,7 @@ function checkMcpLogs(report) {
7149
7352
  report.add("mcp_log", logPath);
7150
7353
  if (lines.length > 0) {
7151
7354
  ok("last lines", `(${lines.length} shown)`);
7152
- for (const line of lines) process.stdout.write(` ${sanitize(line)}
7153
- `);
7355
+ for (const line of lines) outputLine(` ${sanitize(line)}`);
7154
7356
  } else {
7155
7357
  ok("last lines", "(empty log)");
7156
7358
  }
@@ -7285,8 +7487,9 @@ function checkModuleLoading(entryPath, report) {
7285
7487
  }
7286
7488
  }
7287
7489
  async function cmdDiagnoseMcp(options = {}) {
7288
- process.stdout.write("\n OKX MCP Server Diagnostics\n");
7289
- process.stdout.write(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
7490
+ outputLine("");
7491
+ outputLine(" OKX MCP Server Diagnostics");
7492
+ outputLine(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
7290
7493
  const report = new Report();
7291
7494
  report.add("ts", (/* @__PURE__ */ new Date()).toISOString());
7292
7495
  report.add("mode", "mcp");
@@ -7307,11 +7510,11 @@ async function cmdDiagnoseMcp(options = {}) {
7307
7510
  handshakePassed = true;
7308
7511
  }
7309
7512
  const allPassed = nodePassed && entryPassed && cfgPassed && moduleLoadPassed && handshakePassed;
7310
- process.stdout.write("\n");
7513
+ outputLine("");
7311
7514
  if (allPassed) {
7312
- process.stdout.write(" Result: All checks passed \u2713\n");
7515
+ outputLine(" Result: All checks passed \u2713");
7313
7516
  } else {
7314
- process.stdout.write(" Result: Some checks failed \u2717\n");
7517
+ outputLine(" Result: Some checks failed \u2717");
7315
7518
  process.exitCode = 1;
7316
7519
  }
7317
7520
  report.add("result", allPassed ? "PASS" : "FAIL");
@@ -7321,7 +7524,7 @@ async function cmdDiagnoseMcp(options = {}) {
7321
7524
 
7322
7525
  // src/commands/diagnose.ts
7323
7526
  var CLI_VERSION = readCliVersion();
7324
- var GIT_HASH = true ? "c00f777" : "dev";
7527
+ var GIT_HASH = true ? "9f66f84" : "dev";
7325
7528
  function maskKey2(key) {
7326
7529
  if (!key) return "(not set)";
7327
7530
  if (key.length <= 8) return "****";
@@ -7563,22 +7766,52 @@ async function cmdDiagnose(config, profile, options = {}) {
7563
7766
  }
7564
7767
  return runCliChecks(config, profile, options.output);
7565
7768
  }
7769
+ function checkConfigFile(report) {
7770
+ section("Config File");
7771
+ const path5 = configFilePath();
7772
+ try {
7773
+ readFullConfig();
7774
+ ok("Config parse", `${path5} OK`);
7775
+ report.add("config_parse", "OK");
7776
+ return true;
7777
+ } catch (e) {
7778
+ const msg = e instanceof Error ? e.message : String(e);
7779
+ fail("Config parse", msg, [
7780
+ `If passphrase contains special characters (# \\ " '), wrap in quotes:`,
7781
+ ` Contains # \\ " \u2192 passphrase = 'value'`,
7782
+ ` Contains ' \u2192 passphrase = "value"`,
7783
+ " Contains both \u2192 passphrase = '''value'''",
7784
+ "Or re-run: okx config init"
7785
+ ]);
7786
+ report.add("config_parse", `FAIL ${msg}`);
7787
+ return false;
7788
+ }
7789
+ }
7566
7790
  async function runCliChecks(config, profile, outputPath) {
7567
7791
  process.stdout.write("\n OKX Trade CLI Diagnostics\n");
7568
7792
  process.stdout.write(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
7569
7793
  const report = new Report();
7570
7794
  report.add("ts", (/* @__PURE__ */ new Date()).toISOString());
7795
+ const configFilePassed = checkConfigFile(report);
7571
7796
  const envPassed = checkEnvironment(report);
7797
+ if (!config) {
7798
+ fail("Config", "Could not load config (see Config File check above)", []);
7799
+ report.add("result", "FAIL");
7800
+ report.print();
7801
+ writeReportIfRequested(report, outputPath);
7802
+ process.exitCode = 1;
7803
+ return;
7804
+ }
7572
7805
  const cfgPassed = checkConfig(config, profile, report);
7573
7806
  const client = new OkxRestClient(config);
7574
7807
  const netPassed = await checkNetwork(config, client, report);
7575
7808
  const authPassed = await checkAuth(client, config, report);
7576
- const allPassed = envPassed && cfgPassed && netPassed && authPassed;
7577
- process.stdout.write("\n");
7809
+ const allPassed = configFilePassed && envPassed && cfgPassed && netPassed && authPassed;
7810
+ outputLine("");
7578
7811
  if (allPassed) {
7579
- process.stdout.write(" Result: All checks passed \u2713\n");
7812
+ outputLine(" Result: All checks passed \u2713");
7580
7813
  } else {
7581
- process.stdout.write(" Result: Some checks failed \u2717\n");
7814
+ outputLine(" Result: Some checks failed \u2717");
7582
7815
  process.exitCode = 1;
7583
7816
  }
7584
7817
  report.add("result", allPassed ? "PASS" : "FAIL");
@@ -7600,6 +7833,9 @@ function loadProfileConfig(opts) {
7600
7833
  });
7601
7834
  }
7602
7835
 
7836
+ // src/help.ts
7837
+ import { EOL as EOL2 } from "os";
7838
+
7603
7839
  // src/commands/client-setup.ts
7604
7840
  import * as fs5 from "fs";
7605
7841
  var DETECTABLE_CLIENTS = ["claude-desktop", "cursor", "windsurf"];
@@ -7615,14 +7851,11 @@ function cmdSetupClients() {
7615
7851
  }
7616
7852
  }
7617
7853
  if (detected.length > 0) {
7618
- process.stdout.write(`Detected clients:
7619
- `);
7854
+ outputLine("Detected clients:");
7620
7855
  for (const { id, path: path5 } of detected) {
7621
- process.stdout.write(` ${id.padEnd(16)} ${path5}
7622
- `);
7856
+ outputLine(` ${id.padEnd(16)} ${path5}`);
7623
7857
  }
7624
- process.stdout.write(`
7625
- `);
7858
+ outputLine("");
7626
7859
  }
7627
7860
  printSetupUsage();
7628
7861
  }
@@ -8197,13 +8430,12 @@ function printGlobalHelp() {
8197
8430
  lines.push(` ${name.padEnd(colWidth)}${group.description}`);
8198
8431
  }
8199
8432
  lines.push("", 'Run "okx <module> --help" for module details.', "");
8200
- process.stdout.write(lines.join("\n"));
8433
+ output(lines.join(EOL2));
8201
8434
  }
8202
8435
  function printModuleHelp(moduleName) {
8203
8436
  const group = HELP_TREE[moduleName];
8204
8437
  if (!group) {
8205
- process.stderr.write(`Unknown module: ${moduleName}
8206
- `);
8438
+ errorLine(`Unknown module: ${moduleName}`);
8207
8439
  process.exitCode = 1;
8208
8440
  return;
8209
8441
  }
@@ -8247,20 +8479,18 @@ function printModuleHelp(moduleName) {
8247
8479
  }
8248
8480
  }
8249
8481
  lines.push("");
8250
- process.stdout.write(lines.join("\n"));
8482
+ output(lines.join(EOL2));
8251
8483
  }
8252
8484
  function printSubgroupHelp(moduleName, subgroupName) {
8253
8485
  const group = HELP_TREE[moduleName];
8254
8486
  if (!group) {
8255
- process.stderr.write(`Unknown module: ${moduleName}
8256
- `);
8487
+ errorLine(`Unknown module: ${moduleName}`);
8257
8488
  process.exitCode = 1;
8258
8489
  return;
8259
8490
  }
8260
8491
  const subgroup = group.subgroups?.[subgroupName];
8261
8492
  if (!subgroup) {
8262
- process.stderr.write(`Unknown subgroup: ${moduleName} ${subgroupName}
8263
- `);
8493
+ errorLine(`Unknown subgroup: ${moduleName} ${subgroupName}`);
8264
8494
  process.exitCode = 1;
8265
8495
  return;
8266
8496
  }
@@ -8276,7 +8506,7 @@ function printSubgroupHelp(moduleName, subgroupName) {
8276
8506
  printCommandList(lines, subgroup.commands);
8277
8507
  }
8278
8508
  lines.push("");
8279
- process.stdout.write(lines.join("\n"));
8509
+ output(lines.join(EOL2));
8280
8510
  }
8281
8511
  function printCommandList(lines, commands) {
8282
8512
  const names = Object.keys(commands);
@@ -8327,6 +8557,7 @@ var CLI_OPTIONS = {
8327
8557
  px: { type: "string" },
8328
8558
  posSide: { type: "string" },
8329
8559
  tdMode: { type: "string" },
8560
+ tgtCcy: { type: "string" },
8330
8561
  // leverage
8331
8562
  lever: { type: "string" },
8332
8563
  mgnMode: { type: "string" },
@@ -8427,6 +8658,10 @@ var CLI_OPTIONS = {
8427
8658
  maxTermDays: { type: "string" },
8428
8659
  expDate: { type: "string" },
8429
8660
  minAnnualizedYield: { type: "string" },
8661
+ // indicator
8662
+ params: { type: "string" },
8663
+ list: { type: "boolean", default: false },
8664
+ "backtest-time": { type: "string" },
8430
8665
  // diagnostics — cli/mcp/all/output are diagnose-specific; verbose is shared
8431
8666
  verbose: { type: "boolean", default: false },
8432
8667
  mcp: { type: "boolean", default: false },
@@ -8461,42 +8696,6 @@ function parseCli(argv) {
8461
8696
  return { values, positionals };
8462
8697
  }
8463
8698
 
8464
- // src/formatter.ts
8465
- function printJson(data) {
8466
- process.stdout.write(JSON.stringify(data, null, 2) + "\n");
8467
- }
8468
- function printTable(rows) {
8469
- if (rows.length === 0) {
8470
- process.stdout.write("(no data)\n");
8471
- return;
8472
- }
8473
- const keys = Object.keys(rows[0]);
8474
- const widths = keys.map(
8475
- (k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? "").length))
8476
- );
8477
- const header = keys.map((k, i) => k.padEnd(widths[i])).join(" ");
8478
- const divider = widths.map((w) => "-".repeat(w)).join(" ");
8479
- process.stdout.write(header + "\n" + divider + "\n");
8480
- for (const row of rows) {
8481
- process.stdout.write(
8482
- keys.map((k, i) => String(row[k] ?? "").padEnd(widths[i])).join(" ") + "\n"
8483
- );
8484
- }
8485
- }
8486
- function printKv(obj, indent = 0) {
8487
- const pad = " ".repeat(indent);
8488
- for (const [k, v] of Object.entries(obj)) {
8489
- if (v !== null && typeof v === "object" && !Array.isArray(v)) {
8490
- process.stdout.write(`${pad}${k}:
8491
- `);
8492
- printKv(v, indent + 2);
8493
- } else {
8494
- process.stdout.write(`${pad}${k.padEnd(20 - indent)} ${v}
8495
- `);
8496
- }
8497
- }
8498
- }
8499
-
8500
8699
  // src/commands/market.ts
8501
8700
  function getData(result) {
8502
8701
  return result.data;
@@ -8532,7 +8731,7 @@ async function cmdMarketFundingRate(run, instId, opts) {
8532
8731
  } else {
8533
8732
  const r = items?.[0];
8534
8733
  if (!r) {
8535
- process.stdout.write("No data\n");
8734
+ outputLine("No data");
8536
8735
  return;
8537
8736
  }
8538
8737
  printKv({
@@ -8605,7 +8804,7 @@ async function cmdMarketPriceLimit(run, instId, json) {
8605
8804
  if (json) return printJson(items);
8606
8805
  const r = items?.[0];
8607
8806
  if (!r) {
8608
- process.stdout.write("No data\n");
8807
+ outputLine("No data");
8609
8808
  return;
8610
8809
  }
8611
8810
  printKv({
@@ -8633,7 +8832,7 @@ async function cmdMarketTicker(run, instId, json) {
8633
8832
  const items = getData(result);
8634
8833
  if (json) return printJson(items);
8635
8834
  if (!items?.length) {
8636
- process.stdout.write("No data\n");
8835
+ outputLine("No data");
8637
8836
  return;
8638
8837
  }
8639
8838
  const t = items[0];
@@ -8667,17 +8866,16 @@ async function cmdMarketOrderbook(run, instId, sz, json) {
8667
8866
  if (json) return printJson(data);
8668
8867
  const book = data[0];
8669
8868
  if (!book) {
8670
- process.stdout.write("No data\n");
8869
+ outputLine("No data");
8671
8870
  return;
8672
8871
  }
8673
8872
  const asks = book["asks"].slice(0, 5);
8674
8873
  const bids = book["bids"].slice(0, 5);
8675
- process.stdout.write("Asks (price / size):\n");
8676
- for (const [p, s] of asks.reverse()) process.stdout.write(` ${p.padStart(16)} ${s}
8677
- `);
8678
- process.stdout.write("Bids (price / size):\n");
8679
- for (const [p, s] of bids) process.stdout.write(` ${p.padStart(16)} ${s}
8680
- `);
8874
+ outputLine("Asks (price / size):");
8875
+ asks.reverse();
8876
+ for (const [p, s] of asks) outputLine(` ${p.padStart(16)} ${s}`);
8877
+ outputLine("Bids (price / size):");
8878
+ for (const [p, s] of bids) outputLine(` ${p.padStart(16)} ${s}`);
8681
8879
  }
8682
8880
  async function cmdMarketCandles(run, instId, opts) {
8683
8881
  const result = await run("market_get_candles", { instId, bar: opts.bar, limit: opts.limit });
@@ -8694,6 +8892,54 @@ async function cmdMarketCandles(run, instId, opts) {
8694
8892
  }))
8695
8893
  );
8696
8894
  }
8895
+ async function cmdMarketIndicator(run, indicator, instId, opts) {
8896
+ const params = opts.params ? opts.params.split(",").map((p) => Number(p.trim())).filter((n) => !Number.isNaN(n)) : void 0;
8897
+ const result = await run("market_get_indicator", {
8898
+ instId,
8899
+ indicator,
8900
+ bar: opts.bar,
8901
+ params: params && params.length > 0 ? params : void 0,
8902
+ returnList: opts.list ?? false,
8903
+ limit: opts.limit,
8904
+ backtestTime: opts.backtestTime
8905
+ });
8906
+ const outerArray = getData(result);
8907
+ if (opts.json) return printJson(outerArray);
8908
+ if (!outerArray?.length) {
8909
+ process.stdout.write("No data\n");
8910
+ return;
8911
+ }
8912
+ const apiCode = resolveIndicatorCode(indicator);
8913
+ const response = outerArray[0];
8914
+ const innerArray = response["data"];
8915
+ const instData = innerArray?.[0];
8916
+ const timeframes = instData?.["timeframes"];
8917
+ if (!timeframes) {
8918
+ process.stdout.write(JSON.stringify(outerArray, null, 2) + "\n");
8919
+ return;
8920
+ }
8921
+ for (const [tf, tfData] of Object.entries(timeframes)) {
8922
+ const indicators = tfData?.["indicators"];
8923
+ const values = indicators?.[apiCode];
8924
+ if (!values?.length) continue;
8925
+ process.stdout.write(`${instId} \xB7 ${apiCode} \xB7 ${tf}
8926
+ `);
8927
+ process.stdout.write("\u2500".repeat(40) + "\n");
8928
+ if (opts.list) {
8929
+ const tableRows = values.map((entry) => ({
8930
+ ts: new Date(Number(entry["ts"])).toLocaleString(),
8931
+ ...entry["values"]
8932
+ }));
8933
+ printTable(tableRows);
8934
+ } else {
8935
+ const latest = values[0];
8936
+ printKv({
8937
+ ts: new Date(Number(latest["ts"])).toLocaleString(),
8938
+ ...latest["values"]
8939
+ });
8940
+ }
8941
+ }
8942
+ }
8697
8943
  async function cmdMarketStockTokens(run, opts) {
8698
8944
  const result = await run("market_get_stock_tokens", { instType: opts.instType, instId: opts.instId });
8699
8945
  const items = getData(result);
@@ -8751,7 +8997,7 @@ async function cmdAccountPositions(run, opts) {
8751
8997
  if (opts.json) return printJson(positions);
8752
8998
  const open = (positions ?? []).filter((p) => Number(p["pos"]) !== 0);
8753
8999
  if (!open.length) {
8754
- process.stdout.write("No open positions\n");
9000
+ outputLine("No open positions");
8755
9001
  return;
8756
9002
  }
8757
9003
  printTable(
@@ -8789,7 +9035,7 @@ async function cmdAccountFees(run, opts) {
8789
9035
  if (opts.json) return printJson(data);
8790
9036
  const fee = data?.[0];
8791
9037
  if (!fee) {
8792
- process.stdout.write("No data\n");
9038
+ outputLine("No data");
8793
9039
  return;
8794
9040
  }
8795
9041
  printKv({
@@ -8807,7 +9053,7 @@ async function cmdAccountConfig(run, json) {
8807
9053
  if (json) return printJson(data);
8808
9054
  const cfg = data?.[0];
8809
9055
  if (!cfg) {
8810
- process.stdout.write("No data\n");
9056
+ outputLine("No data");
8811
9057
  return;
8812
9058
  }
8813
9059
  printKv({
@@ -8825,8 +9071,7 @@ async function cmdAccountSetPositionMode(run, posMode, json) {
8825
9071
  const data = getData2(result);
8826
9072
  if (json) return printJson(data);
8827
9073
  const r = data?.[0];
8828
- process.stdout.write(`Position mode set: ${r?.["posMode"]}
8829
- `);
9074
+ outputLine(`Position mode set: ${r?.["posMode"]}`);
8830
9075
  }
8831
9076
  async function cmdAccountMaxSize(run, opts) {
8832
9077
  const result = await run("account_get_max_size", { instId: opts.instId, tdMode: opts.tdMode, px: opts.px });
@@ -8834,7 +9079,7 @@ async function cmdAccountMaxSize(run, opts) {
8834
9079
  if (opts.json) return printJson(data);
8835
9080
  const r = data?.[0];
8836
9081
  if (!r) {
8837
- process.stdout.write("No data\n");
9082
+ outputLine("No data");
8838
9083
  return;
8839
9084
  }
8840
9085
  printKv({ instId: r["instId"], maxBuy: r["maxBuy"], maxSell: r["maxSell"] });
@@ -8845,7 +9090,7 @@ async function cmdAccountMaxAvailSize(run, opts) {
8845
9090
  if (opts.json) return printJson(data);
8846
9091
  const r = data?.[0];
8847
9092
  if (!r) {
8848
- process.stdout.write("No data\n");
9093
+ outputLine("No data");
8849
9094
  return;
8850
9095
  }
8851
9096
  printKv({ instId: r["instId"], availBuy: r["availBuy"], availSell: r["availSell"] });
@@ -8889,8 +9134,7 @@ async function cmdAccountTransfer(run, opts) {
8889
9134
  const data = getData2(result);
8890
9135
  if (opts.json) return printJson(data);
8891
9136
  const r = data?.[0];
8892
- process.stdout.write(`Transfer: ${r?.["transId"]} (${r?.["ccy"]} ${r?.["amt"]})
8893
- `);
9137
+ outputLine(`Transfer: ${r?.["transId"]} (${r?.["ccy"]} ${r?.["amt"]})`);
8894
9138
  }
8895
9139
  function readAuditLogs(logDir, days = 7) {
8896
9140
  const entries = [];
@@ -8932,7 +9176,7 @@ function cmdAccountAudit(opts) {
8932
9176
  entries = entries.slice(0, limit);
8933
9177
  if (opts.json) return printJson(entries);
8934
9178
  if (!entries.length) {
8935
- process.stdout.write("No audit log entries\n");
9179
+ outputLine("No audit log entries");
8936
9180
  return;
8937
9181
  }
8938
9182
  printTable(
@@ -8950,6 +9194,25 @@ function cmdAccountAudit(opts) {
8950
9194
  function getData3(result) {
8951
9195
  return result.data;
8952
9196
  }
9197
+ function emitWriteResult(item, label, idKey) {
9198
+ const isError = item?.["sCode"] !== "0" && item?.["sCode"] !== 0;
9199
+ if (isError) {
9200
+ errorLine(`Error: ${item?.["sMsg"]} (sCode ${item?.["sCode"]})`);
9201
+ } else {
9202
+ outputLine(`${label}: ${item?.[idKey]} (OK)`);
9203
+ }
9204
+ }
9205
+ function emitBatchResults(items) {
9206
+ for (const r of items) {
9207
+ const isError = r["sCode"] !== "0" && r["sCode"] !== 0;
9208
+ const id = r["ordId"] ?? r["clOrdId"] ?? "?";
9209
+ if (isError) {
9210
+ errorLine(`${id}: ${r["sMsg"]} (sCode ${r["sCode"]})`);
9211
+ } else {
9212
+ outputLine(`${id}: OK`);
9213
+ }
9214
+ }
9215
+ }
8953
9216
  async function cmdSpotOrders(run, opts) {
8954
9217
  const result = await run("spot_get_orders", { instId: opts.instId, status: opts.status });
8955
9218
  const orders = getData3(result);
@@ -8974,6 +9237,7 @@ async function cmdSpotPlace(run, opts) {
8974
9237
  side: opts.side,
8975
9238
  ordType: opts.ordType,
8976
9239
  sz: opts.sz,
9240
+ tgtCcy: opts.tgtCcy,
8977
9241
  px: opts.px,
8978
9242
  tpTriggerPx: opts.tpTriggerPx,
8979
9243
  tpOrdPx: opts.tpOrdPx,
@@ -8982,9 +9246,7 @@ async function cmdSpotPlace(run, opts) {
8982
9246
  });
8983
9247
  const data = getData3(result);
8984
9248
  if (opts.json) return printJson(data);
8985
- const order = data?.[0];
8986
- process.stdout.write(`Order placed: ${order?.["ordId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
8987
- `);
9249
+ emitWriteResult(data?.[0], "Order placed", "ordId");
8988
9250
  }
8989
9251
  async function cmdSpotCancel(run, opts) {
8990
9252
  const { instId, ordId, clOrdId, json } = opts;
@@ -8992,9 +9254,7 @@ async function cmdSpotCancel(run, opts) {
8992
9254
  const result = await run("spot_cancel_order", { instId, ...ordId ? { ordId } : { clOrdId } });
8993
9255
  const data = getData3(result);
8994
9256
  if (json) return printJson(data);
8995
- const r = data?.[0];
8996
- process.stdout.write(`Cancelled: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
8997
- `);
9257
+ emitWriteResult(data?.[0], "Cancelled", "ordId");
8998
9258
  }
8999
9259
  async function cmdSpotAlgoPlace(run, opts) {
9000
9260
  const result = await run("spot_place_algo_order", {
@@ -9013,11 +9273,7 @@ async function cmdSpotAlgoPlace(run, opts) {
9013
9273
  });
9014
9274
  const data = getData3(result);
9015
9275
  if (opts.json) return printJson(data);
9016
- const order = data?.[0];
9017
- process.stdout.write(
9018
- `Algo order placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9019
- `
9020
- );
9276
+ emitWriteResult(data?.[0], "Algo order placed", "algoId");
9021
9277
  }
9022
9278
  async function cmdSpotAlgoAmend(run, opts) {
9023
9279
  const result = await run("spot_amend_algo_order", {
@@ -9031,21 +9287,13 @@ async function cmdSpotAlgoAmend(run, opts) {
9031
9287
  });
9032
9288
  const data = getData3(result);
9033
9289
  if (opts.json) return printJson(data);
9034
- const r = data?.[0];
9035
- process.stdout.write(
9036
- `Algo order amended: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9037
- `
9038
- );
9290
+ emitWriteResult(data?.[0], "Algo order amended", "algoId");
9039
9291
  }
9040
9292
  async function cmdSpotAlgoCancel(run, instId, algoId, json) {
9041
9293
  const result = await run("spot_cancel_algo_order", { instId, algoId });
9042
9294
  const data = getData3(result);
9043
9295
  if (json) return printJson(data);
9044
- const r = data?.[0];
9045
- process.stdout.write(
9046
- `Algo order cancelled: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9047
- `
9048
- );
9296
+ emitWriteResult(data?.[0], "Algo order cancelled", "algoId");
9049
9297
  }
9050
9298
  async function cmdSpotGet(run, opts) {
9051
9299
  const result = await run("spot_get_order", { instId: opts.instId, ordId: opts.ordId, clOrdId: opts.clOrdId });
@@ -9053,7 +9301,7 @@ async function cmdSpotGet(run, opts) {
9053
9301
  if (opts.json) return printJson(data);
9054
9302
  const o = data?.[0];
9055
9303
  if (!o) {
9056
- process.stdout.write("No data\n");
9304
+ outputLine("No data");
9057
9305
  return;
9058
9306
  }
9059
9307
  printKv({
@@ -9079,9 +9327,7 @@ async function cmdSpotAmend(run, opts) {
9079
9327
  });
9080
9328
  const data = getData3(result);
9081
9329
  if (opts.json) return printJson(data);
9082
- const r = data?.[0];
9083
- process.stdout.write(`Order amended: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9084
- `);
9330
+ emitWriteResult(data?.[0], "Order amended", "ordId");
9085
9331
  }
9086
9332
  async function cmdSpotAlgoOrders(run, opts) {
9087
9333
  const result = await run("spot_get_algo_orders", {
@@ -9092,7 +9338,7 @@ async function cmdSpotAlgoOrders(run, opts) {
9092
9338
  const orders = getData3(result);
9093
9339
  if (opts.json) return printJson(orders);
9094
9340
  if (!(orders ?? []).length) {
9095
- process.stdout.write("No algo orders\n");
9341
+ outputLine("No algo orders");
9096
9342
  return;
9097
9343
  }
9098
9344
  printTable(
@@ -9136,23 +9382,19 @@ async function cmdSpotAlgoTrailPlace(run, opts) {
9136
9382
  });
9137
9383
  const data = getData3(result);
9138
9384
  if (opts.json) return printJson(data);
9139
- const order = data?.[0];
9140
- process.stdout.write(
9141
- `Trailing stop placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9142
- `
9143
- );
9385
+ emitWriteResult(data?.[0], "Trailing stop placed", "algoId");
9144
9386
  }
9145
9387
  async function cmdSpotBatch(run, opts) {
9146
9388
  let parsed;
9147
9389
  try {
9148
9390
  parsed = JSON.parse(opts.orders);
9149
9391
  } catch {
9150
- process.stderr.write("Error: --orders must be a valid JSON array\n");
9392
+ errorLine("Error: --orders must be a valid JSON array");
9151
9393
  process.exitCode = 1;
9152
9394
  return;
9153
9395
  }
9154
9396
  if (!Array.isArray(parsed) || parsed.length === 0) {
9155
- process.stderr.write("Error: --orders must be a non-empty JSON array\n");
9397
+ errorLine("Error: --orders must be a non-empty JSON array");
9156
9398
  process.exitCode = 1;
9157
9399
  return;
9158
9400
  }
@@ -9163,31 +9405,46 @@ async function cmdSpotBatch(run, opts) {
9163
9405
  };
9164
9406
  const tool = toolMap[opts.action];
9165
9407
  if (!tool) {
9166
- process.stderr.write(`Error: --action must be one of: place, amend, cancel
9167
- `);
9408
+ errorLine("Error: --action must be one of: place, amend, cancel");
9168
9409
  process.exitCode = 1;
9169
9410
  return;
9170
9411
  }
9171
9412
  const result = await run(tool, tool === "spot_batch_orders" ? { action: opts.action, orders: parsed } : { orders: parsed });
9172
9413
  const data = getData3(result);
9173
9414
  if (opts.json) return printJson(data);
9174
- for (const r of data ?? []) {
9175
- process.stdout.write(`${r["ordId"] ?? r["clOrdId"] ?? "?"}: ${r["sCode"] === "0" ? "OK" : r["sMsg"]}
9176
- `);
9177
- }
9415
+ emitBatchResults(data ?? []);
9178
9416
  }
9179
9417
 
9180
9418
  // src/commands/swap.ts
9181
9419
  function getData4(result) {
9182
9420
  return result.data;
9183
9421
  }
9422
+ function emitWriteResult2(item, label, idKey) {
9423
+ const isError = item?.["sCode"] !== "0" && item?.["sCode"] !== 0;
9424
+ if (isError) {
9425
+ errorLine(`Error: ${item?.["sMsg"]} (sCode ${item?.["sCode"]})`);
9426
+ } else {
9427
+ outputLine(`${label}: ${item?.[idKey]} (OK)`);
9428
+ }
9429
+ }
9430
+ function emitBatchResults2(items) {
9431
+ for (const r of items) {
9432
+ const isError = r["sCode"] !== "0" && r["sCode"] !== 0;
9433
+ const id = r["ordId"] ?? r["clOrdId"] ?? "?";
9434
+ if (isError) {
9435
+ errorLine(`${id}: ${r["sMsg"]} (sCode ${r["sCode"]})`);
9436
+ } else {
9437
+ outputLine(`${id}: OK`);
9438
+ }
9439
+ }
9440
+ }
9184
9441
  async function cmdSwapPositions(run, instId, json) {
9185
9442
  const result = await run("swap_get_positions", { instId });
9186
9443
  const positions = getData4(result);
9187
9444
  if (json) return printJson(positions);
9188
9445
  const open = (positions ?? []).filter((p) => Number(p["pos"]) !== 0);
9189
9446
  if (!open.length) {
9190
- process.stdout.write("No open positions\n");
9447
+ outputLine("No open positions");
9191
9448
  return;
9192
9449
  }
9193
9450
  printTable(
@@ -9226,6 +9483,7 @@ async function cmdSwapPlace(run, opts) {
9226
9483
  side: opts.side,
9227
9484
  ordType: opts.ordType,
9228
9485
  sz: opts.sz,
9486
+ tgtCcy: opts.tgtCcy,
9229
9487
  posSide: opts.posSide,
9230
9488
  px: opts.px,
9231
9489
  tpTriggerPx: opts.tpTriggerPx,
@@ -9235,9 +9493,7 @@ async function cmdSwapPlace(run, opts) {
9235
9493
  });
9236
9494
  const data = getData4(result);
9237
9495
  if (opts.json) return printJson(data);
9238
- const order = data?.[0];
9239
- process.stdout.write(`Order placed: ${order?.["ordId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9240
- `);
9496
+ emitWriteResult2(data?.[0], "Order placed", "ordId");
9241
9497
  }
9242
9498
  async function cmdSwapCancel(run, opts) {
9243
9499
  const { instId, ordId, clOrdId, json } = opts;
@@ -9245,9 +9501,7 @@ async function cmdSwapCancel(run, opts) {
9245
9501
  const result = await run("swap_cancel_order", { instId, ...ordId ? { ordId } : { clOrdId } });
9246
9502
  const data = getData4(result);
9247
9503
  if (json) return printJson(data);
9248
- const r = data?.[0];
9249
- process.stdout.write(`Cancelled: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9250
- `);
9504
+ emitWriteResult2(data?.[0], "Cancelled", "ordId");
9251
9505
  }
9252
9506
  async function cmdSwapAlgoPlace(run, opts) {
9253
9507
  const result = await run("swap_place_algo_order", {
@@ -9268,11 +9522,7 @@ async function cmdSwapAlgoPlace(run, opts) {
9268
9522
  });
9269
9523
  const data = getData4(result);
9270
9524
  if (opts.json) return printJson(data);
9271
- const order = data?.[0];
9272
- process.stdout.write(
9273
- `Algo order placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9274
- `
9275
- );
9525
+ emitWriteResult2(data?.[0], "Algo order placed", "algoId");
9276
9526
  }
9277
9527
  async function cmdSwapAlgoAmend(run, opts) {
9278
9528
  const result = await run("swap_amend_algo_order", {
@@ -9286,11 +9536,7 @@ async function cmdSwapAlgoAmend(run, opts) {
9286
9536
  });
9287
9537
  const data = getData4(result);
9288
9538
  if (opts.json) return printJson(data);
9289
- const r = data?.[0];
9290
- process.stdout.write(
9291
- `Algo order amended: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9292
- `
9293
- );
9539
+ emitWriteResult2(data?.[0], "Algo order amended", "algoId");
9294
9540
  }
9295
9541
  async function cmdSwapAlgoTrailPlace(run, opts) {
9296
9542
  const result = await run("swap_place_move_stop_order", {
@@ -9306,21 +9552,13 @@ async function cmdSwapAlgoTrailPlace(run, opts) {
9306
9552
  });
9307
9553
  const data = getData4(result);
9308
9554
  if (opts.json) return printJson(data);
9309
- const order = data?.[0];
9310
- process.stdout.write(
9311
- `Trailing stop placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9312
- `
9313
- );
9555
+ emitWriteResult2(data?.[0], "Trailing stop placed", "algoId");
9314
9556
  }
9315
9557
  async function cmdSwapAlgoCancel(run, instId, algoId, json) {
9316
9558
  const result = await run("swap_cancel_algo_orders", { orders: [{ instId, algoId }] });
9317
9559
  const data = getData4(result);
9318
9560
  if (json) return printJson(data);
9319
- const r = data?.[0];
9320
- process.stdout.write(
9321
- `Algo order cancelled: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9322
- `
9323
- );
9561
+ emitWriteResult2(data?.[0], "Algo order cancelled", "algoId");
9324
9562
  }
9325
9563
  async function cmdSwapAlgoOrders(run, opts) {
9326
9564
  const result = await run("swap_get_algo_orders", {
@@ -9331,7 +9569,7 @@ async function cmdSwapAlgoOrders(run, opts) {
9331
9569
  const orders = getData4(result);
9332
9570
  if (opts.json) return printJson(orders);
9333
9571
  if (!(orders ?? []).length) {
9334
- process.stdout.write("No algo orders\n");
9572
+ outputLine("No algo orders");
9335
9573
  return;
9336
9574
  }
9337
9575
  printTable(
@@ -9368,7 +9606,7 @@ async function cmdSwapGet(run, opts) {
9368
9606
  if (opts.json) return printJson(data);
9369
9607
  const o = data?.[0];
9370
9608
  if (!o) {
9371
- process.stdout.write("No data\n");
9609
+ outputLine("No data");
9372
9610
  return;
9373
9611
  }
9374
9612
  printKv({
@@ -9395,8 +9633,7 @@ async function cmdSwapClose(run, opts) {
9395
9633
  const data = getData4(result);
9396
9634
  if (opts.json) return printJson(data);
9397
9635
  const r = data?.[0];
9398
- process.stdout.write(`Position closed: ${r?.["instId"]} ${r?.["posSide"] ?? ""}
9399
- `);
9636
+ outputLine(`Position closed: ${r?.["instId"]} ${r?.["posSide"] ?? ""}`);
9400
9637
  }
9401
9638
  async function cmdSwapGetLeverage(run, opts) {
9402
9639
  const result = await run("swap_get_leverage", { instId: opts.instId, mgnMode: opts.mgnMode });
@@ -9421,9 +9658,7 @@ async function cmdSwapAmend(run, opts) {
9421
9658
  });
9422
9659
  const data = getData4(result);
9423
9660
  if (opts.json) return printJson(data);
9424
- const r = data?.[0];
9425
- process.stdout.write(`Order amended: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9426
- `);
9661
+ emitWriteResult2(data?.[0], "Order amended", "ordId");
9427
9662
  }
9428
9663
  async function cmdSwapSetLeverage(run, opts) {
9429
9664
  const result = await run("swap_set_leverage", {
@@ -9435,20 +9670,19 @@ async function cmdSwapSetLeverage(run, opts) {
9435
9670
  const data = getData4(result);
9436
9671
  if (opts.json) return printJson(data);
9437
9672
  const r = data?.[0];
9438
- process.stdout.write(`Leverage set: ${r?.["lever"]}x ${r?.["instId"]}
9439
- `);
9673
+ outputLine(`Leverage set: ${r?.["lever"]}x ${r?.["instId"]}`);
9440
9674
  }
9441
9675
  async function cmdSwapBatch(run, opts) {
9442
9676
  let parsed;
9443
9677
  try {
9444
9678
  parsed = JSON.parse(opts.orders);
9445
9679
  } catch {
9446
- process.stderr.write("Error: --orders must be a valid JSON array\n");
9680
+ errorLine("Error: --orders must be a valid JSON array");
9447
9681
  process.exitCode = 1;
9448
9682
  return;
9449
9683
  }
9450
9684
  if (!Array.isArray(parsed) || parsed.length === 0) {
9451
- process.stderr.write("Error: --orders must be a non-empty JSON array\n");
9685
+ errorLine("Error: --orders must be a non-empty JSON array");
9452
9686
  process.exitCode = 1;
9453
9687
  return;
9454
9688
  }
@@ -9459,24 +9693,39 @@ async function cmdSwapBatch(run, opts) {
9459
9693
  };
9460
9694
  const tool = toolMap[opts.action];
9461
9695
  if (!tool) {
9462
- process.stderr.write(`Error: --action must be one of: place, amend, cancel
9463
- `);
9696
+ errorLine("Error: --action must be one of: place, amend, cancel");
9464
9697
  process.exitCode = 1;
9465
9698
  return;
9466
9699
  }
9467
9700
  const result = await run(tool, tool === "swap_batch_orders" ? { action: opts.action, orders: parsed } : { orders: parsed });
9468
9701
  const data = getData4(result);
9469
9702
  if (opts.json) return printJson(data);
9470
- for (const r of data ?? []) {
9471
- process.stdout.write(`${r["ordId"] ?? r["clOrdId"] ?? "?"}: ${r["sCode"] === "0" ? "OK" : r["sMsg"]}
9472
- `);
9473
- }
9703
+ emitBatchResults2(data ?? []);
9474
9704
  }
9475
9705
 
9476
9706
  // src/commands/futures.ts
9477
9707
  function getData5(result) {
9478
9708
  return result.data;
9479
9709
  }
9710
+ function emitWriteResult3(item, label, idKey) {
9711
+ const isError = item?.["sCode"] !== "0" && item?.["sCode"] !== 0;
9712
+ if (isError) {
9713
+ errorLine(`Error: ${item?.["sMsg"]} (sCode ${item?.["sCode"]})`);
9714
+ } else {
9715
+ outputLine(`${label}: ${item?.[idKey]} (OK)`);
9716
+ }
9717
+ }
9718
+ function emitBatchResults3(items) {
9719
+ for (const r of items) {
9720
+ const isError = r["sCode"] !== "0" && r["sCode"] !== 0;
9721
+ const id = r["ordId"] ?? r["clOrdId"] ?? "?";
9722
+ if (isError) {
9723
+ errorLine(`${id}: ${r["sMsg"]} (sCode ${r["sCode"]})`);
9724
+ } else {
9725
+ outputLine(`${id}: OK`);
9726
+ }
9727
+ }
9728
+ }
9480
9729
  async function cmdFuturesOrders(run, opts) {
9481
9730
  const result = await run("futures_get_orders", { instId: opts.instId, status: opts.status });
9482
9731
  const orders = getData5(result);
@@ -9500,7 +9749,7 @@ async function cmdFuturesPositions(run, instId, json) {
9500
9749
  if (json) return printJson(positions);
9501
9750
  const open = (positions ?? []).filter((p) => Number(p["pos"]) !== 0);
9502
9751
  if (!open.length) {
9503
- process.stdout.write("No open positions\n");
9752
+ outputLine("No open positions");
9504
9753
  return;
9505
9754
  }
9506
9755
  printTable(
@@ -9536,6 +9785,7 @@ async function cmdFuturesPlace(run, opts) {
9536
9785
  side: opts.side,
9537
9786
  ordType: opts.ordType,
9538
9787
  sz: opts.sz,
9788
+ tgtCcy: opts.tgtCcy,
9539
9789
  posSide: opts.posSide,
9540
9790
  px: opts.px,
9541
9791
  reduceOnly: opts.reduceOnly,
@@ -9546,9 +9796,7 @@ async function cmdFuturesPlace(run, opts) {
9546
9796
  });
9547
9797
  const data = getData5(result);
9548
9798
  if (opts.json) return printJson(data);
9549
- const order = data?.[0];
9550
- process.stdout.write(`Order placed: ${order?.["ordId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9551
- `);
9799
+ emitWriteResult3(data?.[0], "Order placed", "ordId");
9552
9800
  }
9553
9801
  async function cmdFuturesCancel(run, opts) {
9554
9802
  const { instId, ordId, clOrdId, json } = opts;
@@ -9556,9 +9804,7 @@ async function cmdFuturesCancel(run, opts) {
9556
9804
  const result = await run("futures_cancel_order", { instId, ...ordId ? { ordId } : { clOrdId } });
9557
9805
  const data = getData5(result);
9558
9806
  if (json) return printJson(data);
9559
- const r = data?.[0];
9560
- process.stdout.write(`Cancelled: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9561
- `);
9807
+ emitWriteResult3(data?.[0], "Cancelled", "ordId");
9562
9808
  }
9563
9809
  async function cmdFuturesGet(run, opts) {
9564
9810
  const result = await run("futures_get_order", { instId: opts.instId, ordId: opts.ordId });
@@ -9566,7 +9812,7 @@ async function cmdFuturesGet(run, opts) {
9566
9812
  if (opts.json) return printJson(data);
9567
9813
  const o = data?.[0];
9568
9814
  if (!o) {
9569
- process.stdout.write("No data\n");
9815
+ outputLine("No data");
9570
9816
  return;
9571
9817
  }
9572
9818
  printKv({
@@ -9593,9 +9839,7 @@ async function cmdFuturesAmend(run, opts) {
9593
9839
  });
9594
9840
  const data = getData5(result);
9595
9841
  if (opts.json) return printJson(data);
9596
- const r = data?.[0];
9597
- process.stdout.write(`Order amended: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9598
- `);
9842
+ emitWriteResult3(data?.[0], "Order amended", "ordId");
9599
9843
  }
9600
9844
  async function cmdFuturesClose(run, opts) {
9601
9845
  const result = await run("futures_close_position", {
@@ -9607,8 +9851,7 @@ async function cmdFuturesClose(run, opts) {
9607
9851
  const data = getData5(result);
9608
9852
  if (opts.json) return printJson(data);
9609
9853
  const r = data?.[0];
9610
- process.stdout.write(`Position closed: ${r?.["instId"]} ${r?.["posSide"] ?? ""}
9611
- `);
9854
+ outputLine(`Position closed: ${r?.["instId"]} ${r?.["posSide"] ?? ""}`);
9612
9855
  }
9613
9856
  async function cmdFuturesSetLeverage(run, opts) {
9614
9857
  const result = await run("futures_set_leverage", {
@@ -9620,8 +9863,7 @@ async function cmdFuturesSetLeverage(run, opts) {
9620
9863
  const data = getData5(result);
9621
9864
  if (opts.json) return printJson(data);
9622
9865
  const r = data?.[0];
9623
- process.stdout.write(`Leverage set: ${r?.["lever"]}x ${r?.["instId"]}
9624
- `);
9866
+ outputLine(`Leverage set: ${r?.["lever"]}x ${r?.["instId"]}`);
9625
9867
  }
9626
9868
  async function cmdFuturesGetLeverage(run, opts) {
9627
9869
  const result = await run("futures_get_leverage", { instId: opts.instId, mgnMode: opts.mgnMode });
@@ -9641,12 +9883,12 @@ async function cmdFuturesBatch(run, opts) {
9641
9883
  try {
9642
9884
  parsed = JSON.parse(opts.orders);
9643
9885
  } catch {
9644
- process.stderr.write("Error: --orders must be a valid JSON array\n");
9886
+ errorLine("Error: --orders must be a valid JSON array");
9645
9887
  process.exitCode = 1;
9646
9888
  return;
9647
9889
  }
9648
9890
  if (!Array.isArray(parsed) || parsed.length === 0) {
9649
- process.stderr.write("Error: --orders must be a non-empty JSON array\n");
9891
+ errorLine("Error: --orders must be a non-empty JSON array");
9650
9892
  process.exitCode = 1;
9651
9893
  return;
9652
9894
  }
@@ -9657,18 +9899,14 @@ async function cmdFuturesBatch(run, opts) {
9657
9899
  };
9658
9900
  const tool = toolMap[opts.action];
9659
9901
  if (!tool) {
9660
- process.stderr.write(`Error: --action must be one of: place, amend, cancel
9661
- `);
9902
+ errorLine("Error: --action must be one of: place, amend, cancel");
9662
9903
  process.exitCode = 1;
9663
9904
  return;
9664
9905
  }
9665
9906
  const result = await run(tool, tool === "futures_batch_orders" ? { orders: parsed } : { orders: parsed });
9666
9907
  const data = getData5(result);
9667
9908
  if (opts.json) return printJson(data);
9668
- for (const r of data ?? []) {
9669
- process.stdout.write(`${r["ordId"] ?? r["clOrdId"] ?? "?"}: ${r["sCode"] === "0" ? "OK" : r["sMsg"]}
9670
- `);
9671
- }
9909
+ emitBatchResults3(data ?? []);
9672
9910
  }
9673
9911
  async function cmdFuturesAlgoPlace(run, opts) {
9674
9912
  const result = await run("futures_place_algo_order", {
@@ -9689,11 +9927,7 @@ async function cmdFuturesAlgoPlace(run, opts) {
9689
9927
  });
9690
9928
  const data = getData5(result);
9691
9929
  if (opts.json) return printJson(data);
9692
- const order = data?.[0];
9693
- process.stdout.write(
9694
- `Algo order placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9695
- `
9696
- );
9930
+ emitWriteResult3(data?.[0], "Algo order placed", "algoId");
9697
9931
  }
9698
9932
  async function cmdFuturesAlgoTrailPlace(run, opts) {
9699
9933
  const result = await run("futures_place_move_stop_order", {
@@ -9709,11 +9943,7 @@ async function cmdFuturesAlgoTrailPlace(run, opts) {
9709
9943
  });
9710
9944
  const data = getData5(result);
9711
9945
  if (opts.json) return printJson(data);
9712
- const order = data?.[0];
9713
- process.stdout.write(
9714
- `Trailing stop placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9715
- `
9716
- );
9946
+ emitWriteResult3(data?.[0], "Trailing stop placed", "algoId");
9717
9947
  }
9718
9948
  async function cmdFuturesAlgoAmend(run, opts) {
9719
9949
  const result = await run("futures_amend_algo_order", {
@@ -9727,21 +9957,13 @@ async function cmdFuturesAlgoAmend(run, opts) {
9727
9957
  });
9728
9958
  const data = getData5(result);
9729
9959
  if (opts.json) return printJson(data);
9730
- const r = data?.[0];
9731
- process.stdout.write(
9732
- `Algo order amended: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9733
- `
9734
- );
9960
+ emitWriteResult3(data?.[0], "Algo order amended", "algoId");
9735
9961
  }
9736
9962
  async function cmdFuturesAlgoCancel(run, instId, algoId, json) {
9737
9963
  const result = await run("futures_cancel_algo_orders", { orders: [{ instId, algoId }] });
9738
9964
  const data = getData5(result);
9739
9965
  if (json) return printJson(data);
9740
- const r = data?.[0];
9741
- process.stdout.write(
9742
- `Algo order cancelled: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9743
- `
9744
- );
9966
+ emitWriteResult3(data?.[0], "Algo order cancelled", "algoId");
9745
9967
  }
9746
9968
  async function cmdFuturesAlgoOrders(run, opts) {
9747
9969
  const result = await run("futures_get_algo_orders", {
@@ -9752,7 +9974,7 @@ async function cmdFuturesAlgoOrders(run, opts) {
9752
9974
  const orders = getData5(result);
9753
9975
  if (opts.json) return printJson(orders);
9754
9976
  if (!(orders ?? []).length) {
9755
- process.stdout.write("No algo orders\n");
9977
+ outputLine("No algo orders");
9756
9978
  return;
9757
9979
  }
9758
9980
  printTable(
@@ -9773,6 +9995,25 @@ async function cmdFuturesAlgoOrders(run, opts) {
9773
9995
  function getData6(result) {
9774
9996
  return result.data;
9775
9997
  }
9998
+ function emitWriteResult4(item, label, idKey) {
9999
+ const isError = item?.["sCode"] !== "0" && item?.["sCode"] !== 0;
10000
+ if (isError) {
10001
+ errorLine(`Error: ${item?.["sMsg"]} (sCode ${item?.["sCode"]})`);
10002
+ } else {
10003
+ outputLine(`${label}: ${item?.[idKey]} (OK)`);
10004
+ }
10005
+ }
10006
+ function emitBatchResults4(items) {
10007
+ for (const r of items) {
10008
+ const isError = r["sCode"] !== "0" && r["sCode"] !== 0;
10009
+ const id = r["ordId"] ?? r["clOrdId"] ?? "?";
10010
+ if (isError) {
10011
+ errorLine(`${id}: ${r["sMsg"]} (sCode ${r["sCode"]})`);
10012
+ } else {
10013
+ outputLine(`${id}: OK`);
10014
+ }
10015
+ }
10016
+ }
9776
10017
  async function cmdOptionOrders(run, opts) {
9777
10018
  const result = await run("option_get_orders", {
9778
10019
  instId: opts.instId,
@@ -9803,7 +10044,7 @@ async function cmdOptionGet(run, opts) {
9803
10044
  if (opts.json) return printJson(data);
9804
10045
  const o = data?.[0];
9805
10046
  if (!o) {
9806
- process.stdout.write("No data\n");
10047
+ outputLine("No data");
9807
10048
  return;
9808
10049
  }
9809
10050
  printKv({
@@ -9828,7 +10069,7 @@ async function cmdOptionPositions(run, opts) {
9828
10069
  if (opts.json) return printJson(positions);
9829
10070
  const open = (positions ?? []).filter((p) => Number(p["pos"]) !== 0);
9830
10071
  if (!open.length) {
9831
- process.stdout.write("No open positions\n");
10072
+ outputLine("No open positions");
9832
10073
  return;
9833
10074
  }
9834
10075
  printTable(
@@ -9918,9 +10159,7 @@ async function cmdOptionPlace(run, opts) {
9918
10159
  });
9919
10160
  const data = getData6(result);
9920
10161
  if (opts.json) return printJson(data);
9921
- const order = data?.[0];
9922
- process.stdout.write(`Order placed: ${order?.["ordId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9923
- `);
10162
+ emitWriteResult4(data?.[0], "Order placed", "ordId");
9924
10163
  }
9925
10164
  async function cmdOptionCancel(run, opts) {
9926
10165
  const result = await run("option_cancel_order", {
@@ -9930,9 +10169,7 @@ async function cmdOptionCancel(run, opts) {
9930
10169
  });
9931
10170
  const data = getData6(result);
9932
10171
  if (opts.json) return printJson(data);
9933
- const r = data?.[0];
9934
- process.stdout.write(`Cancelled: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9935
- `);
10172
+ emitWriteResult4(data?.[0], "Cancelled", "ordId");
9936
10173
  }
9937
10174
  async function cmdOptionAmend(run, opts) {
9938
10175
  const result = await run("option_amend_order", {
@@ -9944,31 +10181,26 @@ async function cmdOptionAmend(run, opts) {
9944
10181
  });
9945
10182
  const data = getData6(result);
9946
10183
  if (opts.json) return printJson(data);
9947
- const r = data?.[0];
9948
- process.stdout.write(`Amended: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9949
- `);
10184
+ emitWriteResult4(data?.[0], "Amended", "ordId");
9950
10185
  }
9951
10186
  async function cmdOptionBatchCancel(run, opts) {
9952
10187
  let parsed;
9953
10188
  try {
9954
10189
  parsed = JSON.parse(opts.orders);
9955
10190
  } catch {
9956
- process.stderr.write("Error: --orders must be a valid JSON array\n");
10191
+ errorLine("Error: --orders must be a valid JSON array");
9957
10192
  process.exitCode = 1;
9958
10193
  return;
9959
10194
  }
9960
10195
  if (!Array.isArray(parsed) || parsed.length === 0) {
9961
- process.stderr.write("Error: --orders must be a non-empty JSON array\n");
10196
+ errorLine("Error: --orders must be a non-empty JSON array");
9962
10197
  process.exitCode = 1;
9963
10198
  return;
9964
10199
  }
9965
10200
  const result = await run("option_batch_cancel", { orders: parsed });
9966
10201
  const data = getData6(result);
9967
10202
  if (opts.json) return printJson(data);
9968
- for (const r of data ?? []) {
9969
- process.stdout.write(`${r["ordId"]}: ${r["sCode"] === "0" ? "OK" : r["sMsg"]}
9970
- `);
9971
- }
10203
+ emitBatchResults4(data ?? []);
9972
10204
  }
9973
10205
  async function cmdOptionAlgoPlace(run, opts) {
9974
10206
  const result = await run("option_place_algo_order", {
@@ -9986,11 +10218,7 @@ async function cmdOptionAlgoPlace(run, opts) {
9986
10218
  });
9987
10219
  const data = getData6(result);
9988
10220
  if (opts.json) return printJson(data);
9989
- const order = data?.[0];
9990
- process.stdout.write(
9991
- `Algo order placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9992
- `
9993
- );
10221
+ emitWriteResult4(data?.[0], "Algo order placed", "algoId");
9994
10222
  }
9995
10223
  async function cmdOptionAlgoAmend(run, opts) {
9996
10224
  const result = await run("option_amend_algo_order", {
@@ -10004,21 +10232,13 @@ async function cmdOptionAlgoAmend(run, opts) {
10004
10232
  });
10005
10233
  const data = getData6(result);
10006
10234
  if (opts.json) return printJson(data);
10007
- const r = data?.[0];
10008
- process.stdout.write(
10009
- `Algo order amended: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
10010
- `
10011
- );
10235
+ emitWriteResult4(data?.[0], "Algo order amended", "algoId");
10012
10236
  }
10013
10237
  async function cmdOptionAlgoCancel(run, opts) {
10014
10238
  const result = await run("option_cancel_algo_orders", { orders: [{ instId: opts.instId, algoId: opts.algoId }] });
10015
10239
  const data = getData6(result);
10016
10240
  if (opts.json) return printJson(data);
10017
- const r = data?.[0];
10018
- process.stdout.write(
10019
- `Algo order cancelled: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
10020
- `
10021
- );
10241
+ emitWriteResult4(data?.[0], "Algo order cancelled", "algoId");
10022
10242
  }
10023
10243
  async function cmdOptionAlgoOrders(run, opts) {
10024
10244
  const result = await run("option_get_algo_orders", {
@@ -10029,7 +10249,7 @@ async function cmdOptionAlgoOrders(run, opts) {
10029
10249
  const orders = getData6(result);
10030
10250
  if (opts.json) return printJson(orders);
10031
10251
  if (!(orders ?? []).length) {
10032
- process.stdout.write("No algo orders\n");
10252
+ outputLine("No algo orders");
10033
10253
  return;
10034
10254
  }
10035
10255
  printTable(
@@ -10130,21 +10350,18 @@ function prompt(rl, question) {
10130
10350
  function cmdConfigShow(json) {
10131
10351
  const config = readFullConfig();
10132
10352
  if (json) return printJson(config);
10133
- process.stdout.write(`Config: ${configFilePath()}
10134
-
10135
- `);
10136
- process.stdout.write(`default_profile: ${config.default_profile ?? "(not set)"}
10137
-
10138
- `);
10353
+ outputLine(`Config: ${configFilePath()}`);
10354
+ outputLine("");
10355
+ outputLine(`default_profile: ${config.default_profile ?? "(not set)"}`);
10356
+ outputLine("");
10139
10357
  for (const [name, profile] of Object.entries(config.profiles)) {
10140
- process.stdout.write(`[${name}]
10141
- `);
10358
+ outputLine(`[${name}]`);
10142
10359
  printKv({
10143
10360
  api_key: profile.api_key ? maskSecret(profile.api_key) : "(not set)",
10144
10361
  demo: profile.demo ?? false,
10145
10362
  base_url: profile.base_url ?? "(default)"
10146
10363
  }, 2);
10147
- process.stdout.write("\n");
10364
+ outputLine("");
10148
10365
  }
10149
10366
  }
10150
10367
  function cmdConfigSet(key, value) {
@@ -10152,11 +10369,9 @@ function cmdConfigSet(key, value) {
10152
10369
  if (key === "default_profile") {
10153
10370
  config.default_profile = value;
10154
10371
  writeCliConfig(config);
10155
- process.stdout.write(`default_profile set to "${value}"
10156
- `);
10372
+ outputLine(`default_profile set to "${value}"`);
10157
10373
  } else {
10158
- process.stderr.write(`Unknown config key: ${key}
10159
- `);
10374
+ errorLine(`Unknown config key: ${key}`);
10160
10375
  process.exitCode = 1;
10161
10376
  }
10162
10377
  }
@@ -10192,24 +10407,22 @@ function buildProfileEntry(siteKey, apiKey, secretKey, passphrase, demo) {
10192
10407
  }
10193
10408
  async function cmdConfigInit(lang = "en") {
10194
10409
  const t = messages[lang];
10195
- process.stdout.write(`${t.title}
10196
-
10197
- `);
10410
+ outputLine(t.title);
10411
+ outputLine("");
10198
10412
  const rl = createInterface({ input: process.stdin, output: process.stdout });
10199
10413
  try {
10200
- process.stdout.write(`${t.selectSite}
10201
- `);
10202
- process.stdout.write(" 1) Global (www.okx.com) [default]\n");
10203
- process.stdout.write(" 2) EEA (my.okx.com)\n");
10204
- process.stdout.write(" 3) US (app.okx.com)\n");
10414
+ outputLine(t.selectSite);
10415
+ outputLine(" 1) Global (www.okx.com) [default]");
10416
+ outputLine(" 2) EEA (my.okx.com)");
10417
+ outputLine(" 3) US (app.okx.com)");
10205
10418
  const siteRaw = (await prompt(rl, t.sitePrompt)).trim();
10206
10419
  const siteKey = parseSiteKey(siteRaw);
10207
10420
  const demoRaw = (await prompt(rl, t.demoPrompt)).trim().toLowerCase();
10208
10421
  const demo = demoRaw !== "n";
10209
10422
  const apiUrl = buildApiUrl(siteKey, demo);
10210
10423
  const hintText = demo ? t.hintDemo : t.hintLive;
10211
- process.stdout.write(t.createApiKey(apiUrl));
10212
- process.stdout.write(t.hint(hintText));
10424
+ output(t.createApiKey(apiUrl));
10425
+ output(t.hint(hintText));
10213
10426
  try {
10214
10427
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
10215
10428
  spawnSync2(opener, [apiUrl], { stdio: "ignore", shell: process.platform === "win32" });
@@ -10222,35 +10435,30 @@ async function cmdConfigInit(lang = "en") {
10222
10435
  if (config.profiles[profileName]) {
10223
10436
  const overwrite = (await prompt(rl, t.profileExists(profileName))).trim().toLowerCase();
10224
10437
  if (overwrite !== "y") {
10225
- process.stdout.write(`${t.cancelled}
10226
- `);
10438
+ outputLine(t.cancelled);
10227
10439
  return;
10228
10440
  }
10229
10441
  }
10230
10442
  const apiKey = (await prompt(rl, "API Key: ")).trim();
10231
10443
  if (!apiKey) {
10232
- process.stderr.write(`${t.emptyApiKey}
10233
- `);
10444
+ errorLine(t.emptyApiKey);
10234
10445
  process.exitCode = 1;
10235
10446
  return;
10236
10447
  }
10237
10448
  const secretKey = (await prompt(rl, "Secret Key: ")).trim();
10238
10449
  if (!secretKey) {
10239
- process.stderr.write(`${t.emptySecretKey}
10240
- `);
10450
+ errorLine(t.emptySecretKey);
10241
10451
  process.exitCode = 1;
10242
10452
  return;
10243
10453
  }
10244
10454
  const passphrase = (await prompt(rl, "Passphrase: ")).trim();
10245
10455
  if (!passphrase) {
10246
- process.stderr.write(`${t.emptyPassphrase}
10247
- `);
10456
+ errorLine(t.emptyPassphrase);
10248
10457
  process.exitCode = 1;
10249
10458
  return;
10250
10459
  }
10251
10460
  if (demo) {
10252
- process.stdout.write(`${t.demoSelected}
10253
- `);
10461
+ outputLine(t.demoSelected);
10254
10462
  }
10255
10463
  const profileEntry = buildProfileEntry(siteKey, apiKey, secretKey, passphrase, demo);
10256
10464
  config.profiles[profileName] = profileEntry;
@@ -10260,18 +10468,18 @@ async function cmdConfigInit(lang = "en") {
10260
10468
  const configPath = configFilePath();
10261
10469
  try {
10262
10470
  writeCliConfig(config);
10263
- process.stdout.write(t.saved(configPath));
10264
- process.stdout.write(t.defaultProfile(profileName));
10265
- process.stdout.write(t.usage);
10471
+ output(t.saved(configPath));
10472
+ output(t.defaultProfile(profileName));
10473
+ output(t.usage);
10266
10474
  } catch (err) {
10267
10475
  const message = err instanceof Error ? err.message : String(err);
10268
10476
  const isPermission = err instanceof Error && "code" in err && (err.code === "EACCES" || err.code === "EPERM");
10269
- process.stderr.write(t.writeFailed(message));
10477
+ errorOutput(t.writeFailed(message));
10270
10478
  if (isPermission) {
10271
- process.stderr.write(t.permissionDenied(configPath));
10479
+ errorOutput(t.permissionDenied(configPath));
10272
10480
  }
10273
- process.stderr.write(t.manualWrite(configPath));
10274
- process.stdout.write(stringify(config) + "\n");
10481
+ errorOutput(t.manualWrite(configPath));
10482
+ outputLine(stringify(config));
10275
10483
  process.exitCode = 1;
10276
10484
  }
10277
10485
  } finally {
@@ -10295,9 +10503,8 @@ function cmdConfigAddProfile(kvPairs, force) {
10295
10503
  if (!sk) missing.push("SK");
10296
10504
  if (!pp) missing.push("PP");
10297
10505
  if (missing.length > 0) {
10298
- process.stderr.write(`Error: missing required parameter(s): ${missing.join(", ")}
10299
- `);
10300
- process.stderr.write("Usage: okx config add-profile AK=<key> SK=<secret> PP=<passphrase> [site=global|eea|us] [demo=true|false] [name=<name>] [--force]\n");
10506
+ errorLine(`Error: missing required parameter(s): ${missing.join(", ")}`);
10507
+ errorLine("Usage: okx config add-profile AK=<key> SK=<secret> PP=<passphrase> [site=global|eea|us] [demo=true|false] [name=<name>] [--force]");
10301
10508
  process.exitCode = 1;
10302
10509
  return;
10303
10510
  }
@@ -10307,8 +10514,7 @@ function cmdConfigAddProfile(kvPairs, force) {
10307
10514
  const profileName = params["NAME"] ?? defaultName;
10308
10515
  const config = readFullConfig();
10309
10516
  if (config.profiles[profileName] && !force) {
10310
- process.stderr.write(`Error: profile "${profileName}" already exists. Use --force to overwrite.
10311
- `);
10517
+ errorLine(`Error: profile "${profileName}" already exists. Use --force to overwrite.`);
10312
10518
  process.exitCode = 1;
10313
10519
  return;
10314
10520
  }
@@ -10317,65 +10523,54 @@ function cmdConfigAddProfile(kvPairs, force) {
10317
10523
  config.profiles[profileName] = entry;
10318
10524
  config.default_profile = profileName;
10319
10525
  writeCliConfig(config);
10320
- process.stdout.write(`Profile "${profileName}" saved to ${configFilePath()}
10321
- `);
10322
- process.stdout.write(`Default profile set to: ${profileName}
10323
- `);
10526
+ outputLine(`Profile "${profileName}" saved to ${configFilePath()}`);
10527
+ outputLine(`Default profile set to: ${profileName}`);
10324
10528
  }
10325
10529
  function cmdConfigListProfile() {
10326
10530
  const config = readFullConfig();
10327
10531
  const entries = Object.entries(config.profiles);
10328
10532
  if (entries.length === 0) {
10329
- process.stdout.write("No profiles found. Run: okx config add-profile AK=<key> SK=<secret> PP=<passphrase>\n");
10533
+ outputLine("No profiles found. Run: okx config add-profile AK=<key> SK=<secret> PP=<passphrase>");
10330
10534
  return;
10331
10535
  }
10332
- process.stdout.write(`Config: ${configFilePath()}
10333
-
10334
- `);
10536
+ outputLine(`Config: ${configFilePath()}`);
10537
+ outputLine("");
10335
10538
  for (const [name, profile] of entries) {
10336
10539
  const isDefault = name === config.default_profile;
10337
10540
  const marker = isDefault ? " *" : "";
10338
10541
  const site = profile.site ?? inferSiteFromBaseUrl(profile.base_url);
10339
10542
  const mode = profile.demo !== false ? "demo (\u6A21\u62DF\u76D8)" : "live (\u5B9E\u76D8)";
10340
- process.stdout.write(`[${name}]${marker}
10341
- `);
10342
- process.stdout.write(` api_key: ${maskSecret(profile.api_key)}
10343
- `);
10344
- process.stdout.write(` secret_key: ${maskSecret(profile.secret_key)}
10345
- `);
10346
- process.stdout.write(` passphrase: ${maskSecret(profile.passphrase)}
10347
- `);
10348
- process.stdout.write(` site: ${site}
10349
- `);
10350
- process.stdout.write(` mode: ${mode}
10351
- `);
10352
- process.stdout.write("\n");
10543
+ outputLine(`[${name}]${marker}`);
10544
+ outputLine(` api_key: ${maskSecret(profile.api_key)}`);
10545
+ outputLine(` secret_key: ${maskSecret(profile.secret_key)}`);
10546
+ outputLine(` passphrase: ${maskSecret(profile.passphrase)}`);
10547
+ outputLine(` site: ${site}`);
10548
+ outputLine(` mode: ${mode}`);
10549
+ outputLine("");
10353
10550
  }
10354
10551
  }
10355
10552
  function cmdConfigUse(profileName) {
10356
10553
  if (!profileName) {
10357
- process.stderr.write("Error: profile name is required.\nUsage: okx config use <profile-name>\n");
10554
+ errorLine("Error: profile name is required.");
10555
+ errorLine("Usage: okx config use <profile-name>");
10358
10556
  process.exitCode = 1;
10359
10557
  return;
10360
10558
  }
10361
10559
  const config = readFullConfig();
10362
10560
  const available = Object.keys(config.profiles);
10363
10561
  if (!config.profiles[profileName]) {
10364
- process.stderr.write(`Error: profile "${profileName}" does not exist.
10365
- `);
10562
+ errorLine(`Error: profile "${profileName}" does not exist.`);
10366
10563
  if (available.length > 0) {
10367
- process.stderr.write(`Available profiles: ${available.join(", ")}
10368
- `);
10564
+ errorLine(`Available profiles: ${available.join(", ")}`);
10369
10565
  } else {
10370
- process.stderr.write("No profiles configured. Run: okx config add-profile AK=<key> SK=<secret> PP=<passphrase>\n");
10566
+ errorLine("No profiles configured. Run: okx config add-profile AK=<key> SK=<secret> PP=<passphrase>");
10371
10567
  }
10372
10568
  process.exitCode = 1;
10373
10569
  return;
10374
10570
  }
10375
10571
  config.default_profile = profileName;
10376
10572
  writeCliConfig(config);
10377
- process.stdout.write(`Default profile set to: "${profileName}"
10378
- `);
10573
+ outputLine(`Default profile set to: "${profileName}"`);
10379
10574
  }
10380
10575
 
10381
10576
  // src/commands/earn.ts
@@ -10392,7 +10587,7 @@ function printDataList(data, json, emptyMsg, mapper) {
10392
10587
  return;
10393
10588
  }
10394
10589
  if (!data.length) {
10395
- process.stdout.write(emptyMsg + "\n");
10590
+ outputLine(emptyMsg);
10396
10591
  return;
10397
10592
  }
10398
10593
  printTable(data.map(mapper));
@@ -10416,7 +10611,7 @@ async function cmdEarnSavingsPurchase(run, opts) {
10416
10611
  }
10417
10612
  const r = data[0];
10418
10613
  if (!r) {
10419
- process.stdout.write("No response data\n");
10614
+ outputLine("No response data");
10420
10615
  return;
10421
10616
  }
10422
10617
  printKv({ ccy: r["ccy"], amt: r["amt"], side: r["side"], rate: r["rate"] });
@@ -10429,7 +10624,7 @@ async function cmdEarnSavingsRedeem(run, opts) {
10429
10624
  }
10430
10625
  const r = data[0];
10431
10626
  if (!r) {
10432
- process.stdout.write("No response data\n");
10627
+ outputLine("No response data");
10433
10628
  return;
10434
10629
  }
10435
10630
  printKv({ ccy: r["ccy"], amt: r["amt"], side: r["side"] });
@@ -10441,8 +10636,7 @@ async function cmdEarnSetLendingRate(run, opts) {
10441
10636
  return;
10442
10637
  }
10443
10638
  const r = data[0];
10444
- process.stdout.write(`Lending rate set: ${r?.["ccy"]} \u2192 ${r?.["rate"]}
10445
- `);
10639
+ outputLine(`Lending rate set: ${r?.["ccy"]} \u2192 ${r?.["rate"]}`);
10446
10640
  }
10447
10641
  async function cmdEarnLendingHistory(run, opts) {
10448
10642
  const data = extractData(await run("earn_get_lending_history", { ccy: opts.ccy, limit: opts.limit }));
@@ -10474,6 +10668,14 @@ async function cmdEarnLendingRateHistory(run, opts) {
10474
10668
  }
10475
10669
 
10476
10670
  // src/commands/bot.ts
10671
+ function emitWriteResult5(item, label, idKey) {
10672
+ const isError = item?.["sCode"] !== "0" && item?.["sCode"] !== 0;
10673
+ if (isError) {
10674
+ errorLine(`Error: ${item?.["sMsg"]} (sCode ${item?.["sCode"]})`);
10675
+ } else {
10676
+ outputLine(`${label}: ${item?.[idKey]} (OK)`);
10677
+ }
10678
+ }
10477
10679
  function getData7(result) {
10478
10680
  return result.data;
10479
10681
  }
@@ -10487,7 +10689,7 @@ async function cmdGridOrders(run, opts) {
10487
10689
  const orders = getData7(result) ?? [];
10488
10690
  if (opts.json) return printJson(orders);
10489
10691
  if (!orders.length) {
10490
- process.stdout.write("No grid bots\n");
10692
+ outputLine("No grid bots");
10491
10693
  return;
10492
10694
  }
10493
10695
  printTable(
@@ -10511,7 +10713,7 @@ async function cmdGridDetails(run, opts) {
10511
10713
  });
10512
10714
  const detail = (getData7(result) ?? [])[0];
10513
10715
  if (!detail) {
10514
- process.stdout.write("Bot not found\n");
10716
+ outputLine("Bot not found");
10515
10717
  return;
10516
10718
  }
10517
10719
  if (opts.json) return printJson(detail);
@@ -10540,7 +10742,7 @@ async function cmdGridSubOrders(run, opts) {
10540
10742
  const orders = getData7(result) ?? [];
10541
10743
  if (opts.json) return printJson(orders);
10542
10744
  if (!orders.length) {
10543
- process.stdout.write("No sub-orders\n");
10745
+ outputLine("No sub-orders");
10544
10746
  return;
10545
10747
  }
10546
10748
  printTable(
@@ -10574,10 +10776,7 @@ async function cmdGridCreate(run, opts) {
10574
10776
  const data = getData7(result);
10575
10777
  if (opts.json) return printJson(data);
10576
10778
  const r = data?.[0];
10577
- process.stdout.write(
10578
- `Grid bot created: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
10579
- `
10580
- );
10779
+ emitWriteResult5(data?.[0], "Grid bot created", "algoId");
10581
10780
  }
10582
10781
  async function cmdGridStop(run, opts) {
10583
10782
  const result = await run("grid_stop_order", {
@@ -10589,10 +10788,7 @@ async function cmdGridStop(run, opts) {
10589
10788
  const data = getData7(result);
10590
10789
  if (opts.json) return printJson(data);
10591
10790
  const r = data?.[0];
10592
- process.stdout.write(
10593
- `Grid bot stopped: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
10594
- `
10595
- );
10791
+ emitWriteResult5(data?.[0], "Grid bot stopped", "algoId");
10596
10792
  }
10597
10793
  async function cmdDcaCreate(run, opts) {
10598
10794
  const result = await run("dca_create_order", {
@@ -10615,10 +10811,7 @@ async function cmdDcaCreate(run, opts) {
10615
10811
  const data = getData7(result);
10616
10812
  if (opts.json) return printJson(data);
10617
10813
  const r = data?.[0];
10618
- process.stdout.write(
10619
- `DCA bot created: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
10620
- `
10621
- );
10814
+ emitWriteResult5(data?.[0], "DCA bot created", "algoId");
10622
10815
  }
10623
10816
  async function cmdDcaStop(run, opts) {
10624
10817
  const result = await run("dca_stop_order", {
@@ -10627,10 +10820,7 @@ async function cmdDcaStop(run, opts) {
10627
10820
  const data = getData7(result);
10628
10821
  if (opts.json) return printJson(data);
10629
10822
  const r = data?.[0];
10630
- process.stdout.write(
10631
- `DCA bot stopped: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
10632
- `
10633
- );
10823
+ emitWriteResult5(data?.[0], "DCA bot stopped", "algoId");
10634
10824
  }
10635
10825
  async function cmdDcaOrders(run, opts) {
10636
10826
  const result = await run("dca_get_orders", {
@@ -10641,7 +10831,7 @@ async function cmdDcaOrders(run, opts) {
10641
10831
  const orders = getData7(result) ?? [];
10642
10832
  if (opts.json) return printJson(orders);
10643
10833
  if (!orders.length) {
10644
- process.stdout.write("No DCA bots\n");
10834
+ outputLine("No DCA bots");
10645
10835
  return;
10646
10836
  }
10647
10837
  printTable(
@@ -10661,7 +10851,7 @@ async function cmdDcaDetails(run, opts) {
10661
10851
  });
10662
10852
  const detail = (getData7(result) ?? [])[0];
10663
10853
  if (!detail) {
10664
- process.stdout.write("DCA bot not found\n");
10854
+ outputLine("DCA bot not found");
10665
10855
  return;
10666
10856
  }
10667
10857
  if (opts.json) return printJson(detail);
@@ -10689,7 +10879,7 @@ async function cmdDcaSubOrders(run, opts) {
10689
10879
  const orders = getData7(result) ?? [];
10690
10880
  if (opts.json) return printJson(orders);
10691
10881
  if (!orders.length) {
10692
- process.stdout.write("No sub-orders\n");
10882
+ outputLine("No sub-orders");
10693
10883
  return;
10694
10884
  }
10695
10885
  printTable(
@@ -10778,7 +10968,7 @@ async function cmdDcdPairs(run, json) {
10778
10968
  return;
10779
10969
  }
10780
10970
  if (!data.length) {
10781
- process.stdout.write("No currency pairs available\n");
10971
+ outputLine("No currency pairs available");
10782
10972
  return;
10783
10973
  }
10784
10974
  printTable(data.map((r) => ({
@@ -10843,7 +11033,7 @@ async function cmdDcdProducts(run, opts) {
10843
11033
  return;
10844
11034
  }
10845
11035
  if (!data.length) {
10846
- process.stdout.write("No products matched\n");
11036
+ outputLine("No products matched");
10847
11037
  return;
10848
11038
  }
10849
11039
  printTable(data.map((r) => ({
@@ -10863,7 +11053,7 @@ async function cmdDcdRedeemExecute(run, opts) {
10863
11053
  const quoteData = extractArray(quoteResult);
10864
11054
  const q = quoteData[0];
10865
11055
  if (!q) {
10866
- process.stdout.write("Failed to get redeem quote\n");
11056
+ outputLine("Failed to get redeem quote");
10867
11057
  return;
10868
11058
  }
10869
11059
  const redeemResult = await run("dcd_redeem", {
@@ -10873,7 +11063,7 @@ async function cmdDcdRedeemExecute(run, opts) {
10873
11063
  const redeemData = extractArray(redeemResult);
10874
11064
  const r = redeemData[0];
10875
11065
  if (!r) {
10876
- process.stdout.write("No response data\n");
11066
+ outputLine("No response data");
10877
11067
  return;
10878
11068
  }
10879
11069
  if (opts.json) {
@@ -10896,7 +11086,7 @@ async function cmdDcdOrderState(run, opts) {
10896
11086
  }
10897
11087
  const r = data[0];
10898
11088
  if (!r) {
10899
- process.stdout.write("Order not found\n");
11089
+ outputLine("Order not found");
10900
11090
  return;
10901
11091
  }
10902
11092
  printKv({
@@ -10926,7 +11116,7 @@ async function cmdDcdOrders(run, opts) {
10926
11116
  return;
10927
11117
  }
10928
11118
  if (!data.length) {
10929
- process.stdout.write("No orders found\n");
11119
+ outputLine("No orders found");
10930
11120
  return;
10931
11121
  }
10932
11122
  printTable(data.map((r) => ({
@@ -10957,7 +11147,7 @@ async function cmdDcdQuoteAndBuy(run, opts) {
10957
11147
  const r = tradeData[0];
10958
11148
  const q = result["quote"];
10959
11149
  if (!r) {
10960
- process.stdout.write("No quote returned\n");
11150
+ outputLine("No quote returned");
10961
11151
  return;
10962
11152
  }
10963
11153
  const ordId = r["ordId"];
@@ -10974,7 +11164,7 @@ async function cmdDcdQuoteAndBuy(run, opts) {
10974
11164
  return;
10975
11165
  }
10976
11166
  if (q) {
10977
- process.stdout.write("Quote:\n");
11167
+ outputLine("Quote:");
10978
11168
  printKv({
10979
11169
  quoteId: q["quoteId"],
10980
11170
  annualizedYield: q["annualizedYield"] ? `${q["annualizedYield"]}%` : "\u2014",
@@ -10982,12 +11172,13 @@ async function cmdDcdQuoteAndBuy(run, opts) {
10982
11172
  notionalSz: q["notionalSz"],
10983
11173
  notionalCcy: q["notionalCcy"]
10984
11174
  });
10985
- process.stdout.write("\n");
11175
+ outputLine("");
10986
11176
  }
10987
- process.stdout.write("Order placed:\n");
11177
+ outputLine("Order placed:");
10988
11178
  printKv({ ordId: r["ordId"], quoteId: r["quoteId"], state: r["state"] ?? r["status"] });
10989
11179
  if (stateRow) {
10990
- process.stdout.write("\nOrder state:\n");
11180
+ outputLine("");
11181
+ outputLine("Order state:");
10991
11182
  printKv({
10992
11183
  ordId: stateRow["ordId"],
10993
11184
  state: stateRow["state"],
@@ -11002,7 +11193,7 @@ async function cmdDcdQuoteAndBuy(run, opts) {
11002
11193
  // src/index.ts
11003
11194
  var _require3 = createRequire3(import.meta.url);
11004
11195
  var CLI_VERSION2 = _require3("../package.json").version;
11005
- var GIT_HASH2 = true ? "c00f777" : "dev";
11196
+ var GIT_HASH2 = true ? "9f66f84" : "dev";
11006
11197
  function handleConfigCommand(action, rest, json, lang, force) {
11007
11198
  if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
11008
11199
  if (action === "show") return cmdConfigShow(json);
@@ -11011,8 +11202,7 @@ function handleConfigCommand(action, rest, json, lang, force) {
11011
11202
  if (action === "add-profile") return cmdConfigAddProfile(rest, force ?? false);
11012
11203
  if (action === "list-profile") return cmdConfigListProfile();
11013
11204
  if (action === "use") return cmdConfigUse(rest[0]);
11014
- process.stderr.write(`Unknown config command: ${action}
11015
- `);
11205
+ errorLine(`Unknown config command: ${action}`);
11016
11206
  process.exitCode = 1;
11017
11207
  }
11018
11208
  function handleSetupCommand(v) {
@@ -11021,11 +11211,8 @@ function handleSetupCommand(v) {
11021
11211
  return;
11022
11212
  }
11023
11213
  if (!SUPPORTED_CLIENTS.includes(v.client)) {
11024
- process.stderr.write(
11025
- `Unknown client: "${v.client}"
11026
- Supported: ${SUPPORTED_CLIENTS.join(", ")}
11027
- `
11028
- );
11214
+ errorLine(`Unknown client: "${v.client}"`);
11215
+ errorLine(`Supported: ${SUPPORTED_CLIENTS.join(", ")}`);
11029
11216
  process.exitCode = 1;
11030
11217
  return;
11031
11218
  }
@@ -11049,6 +11236,18 @@ function handleMarketPublicCommand(run, action, rest, v, json) {
11049
11236
  return cmdMarketOpenInterest(run, { instType: v.instType, instId: v.instId, json });
11050
11237
  if (action === "stock-tokens")
11051
11238
  return cmdMarketStockTokens(run, { instType: v.instType, instId: v.instId, json });
11239
+ if (action === "indicator") {
11240
+ const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
11241
+ const backtestTime = v["backtest-time"] !== void 0 ? Number(v["backtest-time"]) : void 0;
11242
+ return cmdMarketIndicator(run, rest[0], rest[1], {
11243
+ bar: v.bar,
11244
+ params: v.params,
11245
+ list: v.list,
11246
+ limit,
11247
+ backtestTime,
11248
+ json
11249
+ });
11250
+ }
11052
11251
  }
11053
11252
  function handleMarketDataCommand(run, action, rest, v, json) {
11054
11253
  const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
@@ -11189,6 +11388,7 @@ function handleSpotCommand(run, action, rest, v, json) {
11189
11388
  side: v.side,
11190
11389
  ordType: v.ordType,
11191
11390
  sz: v.sz,
11391
+ tgtCcy: v.tgtCcy,
11192
11392
  px: v.px,
11193
11393
  tpTriggerPx: v.tpTriggerPx,
11194
11394
  tpOrdPx: v.tpOrdPx,
@@ -11298,6 +11498,7 @@ function handleSwapCommand(run, action, rest, v, json) {
11298
11498
  posSide: v.posSide,
11299
11499
  px: v.px,
11300
11500
  tdMode: v.tdMode ?? "cross",
11501
+ tgtCcy: v.tgtCcy,
11301
11502
  tpTriggerPx: v.tpTriggerPx,
11302
11503
  tpOrdPx: v.tpOrdPx,
11303
11504
  slTriggerPx: v.slTriggerPx,
@@ -11499,6 +11700,7 @@ function handleFuturesCommand(run, action, rest, v, json) {
11499
11700
  ordType: v.ordType,
11500
11701
  sz: v.sz,
11501
11702
  tdMode: v.tdMode ?? "cross",
11703
+ tgtCcy: v.tgtCcy,
11502
11704
  posSide: v.posSide,
11503
11705
  px: v.px,
11504
11706
  reduceOnly: v.reduceOnly,
@@ -11627,9 +11829,8 @@ function handleEarnCommand(run, submodule, rest, v, json) {
11627
11829
  if (submodule === "savings") return handleEarnSavingsCommand(run, action, innerRest, v, json);
11628
11830
  if (submodule === "onchain") return handleEarnOnchainCommand(run, action, v, json);
11629
11831
  if (submodule === "dcd") return handleEarnDcdCommand(run, action, v, json);
11630
- process.stderr.write(`Unknown earn sub-module: ${submodule}
11631
- Valid: savings, onchain, dcd
11632
- `);
11832
+ errorLine(`Unknown earn sub-module: ${submodule}`);
11833
+ errorLine("Valid: savings, onchain, dcd");
11633
11834
  process.exitCode = 1;
11634
11835
  }
11635
11836
  function handleEarnSavingsCommand(run, action, rest, v, json) {
@@ -11641,8 +11842,7 @@ function handleEarnSavingsCommand(run, action, rest, v, json) {
11641
11842
  if (action === "lending-history") return cmdEarnLendingHistory(run, { ccy: v.ccy, limit, json });
11642
11843
  if (action === "rate-summary") return cmdEarnLendingRateSummary(run, rest[0] ?? v.ccy, json);
11643
11844
  if (action === "rate-history") return cmdEarnLendingRateHistory(run, { ccy: v.ccy, limit, json });
11644
- process.stderr.write(`Unknown earn savings command: ${action}
11645
- `);
11845
+ errorLine(`Unknown earn savings command: ${action}`);
11646
11846
  process.exitCode = 1;
11647
11847
  }
11648
11848
  function handleEarnOnchainCommand(run, action, v, json) {
@@ -11652,8 +11852,7 @@ function handleEarnOnchainCommand(run, action, v, json) {
11652
11852
  if (action === "cancel") return cmdOnchainEarnCancel(run, v).then((r) => outputResult(r, json));
11653
11853
  if (action === "orders") return cmdOnchainEarnActiveOrders(run, v).then((r) => outputResult(r, json));
11654
11854
  if (action === "history") return cmdOnchainEarnOrderHistory(run, v).then((r) => outputResult(r, json));
11655
- process.stderr.write(`Unknown earn onchain command: ${action}
11656
- `);
11855
+ errorLine(`Unknown earn onchain command: ${action}`);
11657
11856
  process.exitCode = 1;
11658
11857
  }
11659
11858
  function parseDcdOpts(v) {
@@ -11708,16 +11907,15 @@ function handleEarnDcdCommand(run, action, v, json) {
11708
11907
  limit,
11709
11908
  json
11710
11909
  });
11711
- process.stderr.write(`Unknown earn dcd command: ${action}
11712
- Valid: pairs, products, quote-and-buy, redeem-execute, order, orders
11713
- `);
11910
+ errorLine(`Unknown earn dcd command: ${action}`);
11911
+ errorLine("Valid: pairs, products, quote-and-buy, redeem-execute, order, orders");
11714
11912
  process.exitCode = 1;
11715
11913
  }
11716
11914
  function outputResult(result, json) {
11717
11915
  if (json) {
11718
- process.stdout.write(JSON.stringify(result, null, 2) + "\n");
11916
+ outputLine(JSON.stringify(result, null, 2));
11719
11917
  } else {
11720
- process.stdout.write(JSON.stringify(result.data, null, 2) + "\n");
11918
+ outputLine(JSON.stringify(result.data, null, 2));
11721
11919
  }
11722
11920
  }
11723
11921
  function printHelpForLevel(positionals) {
@@ -11726,24 +11924,15 @@ function printHelpForLevel(positionals) {
11726
11924
  else if (!subgroup) printHelp(module);
11727
11925
  else printHelp(module, subgroup);
11728
11926
  }
11729
- function printVerboseConfigSummary(config, profile) {
11730
- let authLabel = "\u2717";
11731
- if (config.hasAuth && config.apiKey) {
11732
- authLabel = `\u2713(${config.apiKey.slice(0, 3)}***${config.apiKey.slice(-3)})`;
11733
- } else if (config.hasAuth) {
11734
- authLabel = "\u2713";
11735
- }
11736
- process.stderr.write(
11737
- `[verbose] config: profile=${profile ?? "default"} site=${config.site} base=${config.baseUrl} auth=${authLabel} demo=${config.demo ? "on" : "off"} modules=${config.modules.join(",")}
11738
- `
11739
- );
11740
- }
11741
11927
  async function main() {
11928
+ setOutput({
11929
+ out: (m) => process.stdout.write(m),
11930
+ err: (m) => process.stderr.write(m)
11931
+ });
11742
11932
  checkForUpdates("@okx_ai/okx-trade-cli", CLI_VERSION2);
11743
11933
  const { values, positionals } = parseCli(process.argv.slice(2));
11744
11934
  if (values.version) {
11745
- process.stdout.write(`${CLI_VERSION2} (${GIT_HASH2})
11746
- `);
11935
+ outputLine(`${CLI_VERSION2} (${GIT_HASH2})`);
11747
11936
  return;
11748
11937
  }
11749
11938
  if (values.help || positionals.length === 0) {
@@ -11755,11 +11944,25 @@ async function main() {
11755
11944
  const json = v.json ?? false;
11756
11945
  if (module === "config") return handleConfigCommand(action, rest, json, v.lang, v.force);
11757
11946
  if (module === "setup") return handleSetupCommand(v);
11947
+ if (module === "diagnose") {
11948
+ let config2;
11949
+ try {
11950
+ config2 = loadProfileConfig({ profile: v.profile, demo: v.demo, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
11951
+ } catch {
11952
+ }
11953
+ return cmdDiagnose(config2, v.profile ?? "default", { mcp: v.mcp, cli: v.cli, all: v.all, output: v.output });
11954
+ }
11758
11955
  const config = loadProfileConfig({ profile: v.profile, demo: v.demo, verbose: v.verbose, userAgent: `okx-trade-cli/${CLI_VERSION2}`, sourceTag: "CLI" });
11759
- if (config.verbose) printVerboseConfigSummary(config, v.profile);
11760
- if (module === "diagnose") return cmdDiagnose(config, v.profile ?? "default", { mcp: v.mcp, cli: v.cli, all: v.all, output: v.output });
11761
11956
  const client = new OkxRestClient(config);
11762
- const run = createToolRunner(client, config);
11957
+ const baseRunner = createToolRunner(client, config);
11958
+ const writeToolNames = new Set(allToolSpecs().filter((t) => t.isWrite).map((t) => t.name));
11959
+ const run = async (toolName, args) => {
11960
+ const result = await baseRunner(toolName, args);
11961
+ if (writeToolNames.has(toolName)) {
11962
+ markFailedIfSCodeError(result.data);
11963
+ }
11964
+ return result;
11965
+ };
11763
11966
  const moduleHandlers = {
11764
11967
  market: () => handleMarketCommand(run, action, rest, v, json),
11765
11968
  account: () => handleAccountCommand(run, action, rest, v, json),
@@ -11772,20 +11975,15 @@ async function main() {
11772
11975
  };
11773
11976
  const handler = moduleHandlers[module];
11774
11977
  if (handler) return handler();
11775
- process.stderr.write(`Unknown command: ${module} ${action ?? ""}
11776
- `);
11978
+ errorLine(`Unknown command: ${module} ${action ?? ""}`);
11777
11979
  process.exitCode = 1;
11778
11980
  }
11779
11981
  main().catch((error) => {
11780
11982
  const payload = toToolErrorPayload(error);
11781
- process.stderr.write(`Error: ${payload.message}
11782
- `);
11783
- if (payload.traceId) process.stderr.write(`TraceId: ${payload.traceId}
11784
- `);
11785
- if (payload.suggestion) process.stderr.write(`Hint: ${payload.suggestion}
11786
- `);
11787
- process.stderr.write(`Version: @okx_ai/okx-trade-cli@${CLI_VERSION2}
11788
- `);
11983
+ errorLine(`Error: ${payload.message}`);
11984
+ if (payload.traceId) errorLine(`TraceId: ${payload.traceId}`);
11985
+ if (payload.suggestion) errorLine(`Hint: ${payload.suggestion}`);
11986
+ errorLine(`Version: @okx_ai/okx-trade-cli@${CLI_VERSION2}`);
11789
11987
  process.exitCode = 1;
11790
11988
  });
11791
11989
  export {