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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1671,7 +1671,7 @@ function registerAccountTools() {
1671
1671
  {
1672
1672
  name: "account_get_asset_balance",
1673
1673
  module: "account",
1674
- description: "Get funding account balance (asset account). Different from account_get_balance which queries the trading account.",
1674
+ description: "Get funding account balance (asset account). Different from account_get_balance which queries the trading account. Optionally includes total asset valuation across all account types (trading, funding, earn, etc.).",
1675
1675
  isWrite: false,
1676
1676
  inputSchema: {
1677
1677
  type: "object",
@@ -1679,17 +1679,41 @@ function registerAccountTools() {
1679
1679
  ccy: {
1680
1680
  type: "string",
1681
1681
  description: "e.g. BTC or BTC,ETH. Omit for all."
1682
+ },
1683
+ showValuation: {
1684
+ type: "boolean",
1685
+ description: "Include total asset valuation breakdown by account type (trading/funding/earn). Default false."
1682
1686
  }
1683
1687
  }
1684
1688
  },
1685
1689
  handler: async (rawArgs, context) => {
1686
1690
  const args = asRecord(rawArgs);
1687
- const response = await context.client.privateGet(
1691
+ const ccy = readString(args, "ccy");
1692
+ const showValuation = readBoolean(args, "showValuation");
1693
+ if (showValuation) {
1694
+ const balanceResp2 = await context.client.privateGet(
1695
+ "/api/v5/asset/balances",
1696
+ compactObject({ ccy }),
1697
+ privateRateLimit("account_get_asset_balance", 6)
1698
+ );
1699
+ let valuationData = null;
1700
+ try {
1701
+ const valuationResp = await context.client.privateGet(
1702
+ "/api/v5/asset/asset-valuation",
1703
+ {},
1704
+ privateRateLimit("account_get_asset_valuation", 1)
1705
+ );
1706
+ valuationData = valuationResp.data;
1707
+ } catch {
1708
+ }
1709
+ return { ...normalizeResponse(balanceResp2), valuation: valuationData };
1710
+ }
1711
+ const balanceResp = await context.client.privateGet(
1688
1712
  "/api/v5/asset/balances",
1689
- compactObject({ ccy: readString(args, "ccy") }),
1713
+ compactObject({ ccy }),
1690
1714
  privateRateLimit("account_get_asset_balance", 6)
1691
1715
  );
1692
- return normalizeResponse(response);
1716
+ return normalizeResponse(balanceResp);
1693
1717
  }
1694
1718
  },
1695
1719
  {
@@ -3104,6 +3128,39 @@ function registerGridTools() {
3104
3128
  ];
3105
3129
  }
3106
3130
  var BASE = "/api/v5/tradingBot/dca";
3131
+ function buildTriggerParam(args, algoOrdType) {
3132
+ const triggerStrategy = readString(args, "triggerStrategy") ?? "instant";
3133
+ if (triggerStrategy === "price" && algoOrdType === "spot_dca") {
3134
+ throw new OkxApiError(
3135
+ "triggerStrategy 'price' is only supported for contract_dca. spot_dca supports: instant, rsi",
3136
+ { code: "VALIDATION", endpoint: `${BASE}/create` }
3137
+ );
3138
+ }
3139
+ const param = { triggerAction: "start", triggerStrategy };
3140
+ if (triggerStrategy === "price") {
3141
+ param["triggerPx"] = requireString(args, "triggerPx");
3142
+ const triggerCond = readString(args, "triggerCond");
3143
+ if (triggerCond) param["triggerCond"] = triggerCond;
3144
+ } else if (triggerStrategy === "rsi") {
3145
+ param["triggerCond"] = requireString(args, "triggerCond");
3146
+ param["thold"] = requireString(args, "thold");
3147
+ param["timeframe"] = requireString(args, "timeframe");
3148
+ param["timePeriod"] = readString(args, "timePeriod") ?? "14";
3149
+ }
3150
+ return param;
3151
+ }
3152
+ function validateSafetyOrderParams(args, maxSafetyOrds) {
3153
+ if (Number(maxSafetyOrds) <= 0) return;
3154
+ const required = ["safetyOrdAmt", "pxSteps", "pxStepsMult", "volMult"];
3155
+ for (const field of required) {
3156
+ if (!readString(args, field)) {
3157
+ throw new OkxApiError(`${field} is required when maxSafetyOrds > 0`, {
3158
+ code: "VALIDATION",
3159
+ endpoint: `${BASE}/create`
3160
+ });
3161
+ }
3162
+ }
3163
+ }
3107
3164
  function normalizeWrite2(response) {
3108
3165
  const data = response.data;
3109
3166
  if (Array.isArray(data) && data.length > 0) {
@@ -3173,57 +3230,11 @@ function registerDcaTools() {
3173
3230
  endpoint: `${BASE}/create`
3174
3231
  });
3175
3232
  }
3176
- const triggerStrategy = readString(args, "triggerStrategy") ?? "instant";
3177
- if (triggerStrategy === "price" && algoOrdType === "spot_dca") {
3178
- throw new OkxApiError("triggerStrategy 'price' is only supported for contract_dca. spot_dca supports: instant, rsi", {
3179
- code: "VALIDATION",
3180
- endpoint: `${BASE}/create`
3181
- });
3182
- }
3183
- const triggerParam = {
3184
- triggerAction: "start",
3185
- triggerStrategy
3186
- };
3187
- if (triggerStrategy === "price") {
3188
- triggerParam["triggerPx"] = requireString(args, "triggerPx");
3189
- const triggerCond = readString(args, "triggerCond");
3190
- if (triggerCond) {
3191
- triggerParam["triggerCond"] = triggerCond;
3192
- }
3193
- } else if (triggerStrategy === "rsi") {
3194
- triggerParam["triggerCond"] = requireString(args, "triggerCond");
3195
- triggerParam["thold"] = requireString(args, "thold");
3196
- triggerParam["timeframe"] = requireString(args, "timeframe");
3197
- const timePeriod = readString(args, "timePeriod");
3198
- triggerParam["timePeriod"] = timePeriod ?? "14";
3199
- }
3233
+ const triggerParam = buildTriggerParam(args, algoOrdType);
3200
3234
  const maxSafetyOrds = requireString(args, "maxSafetyOrds");
3201
- if (Number(maxSafetyOrds) > 0) {
3202
- if (!readString(args, "safetyOrdAmt")) {
3203
- throw new OkxApiError("safetyOrdAmt is required when maxSafetyOrds > 0", {
3204
- code: "VALIDATION",
3205
- endpoint: `${BASE}/create`
3206
- });
3207
- }
3208
- if (!readString(args, "pxSteps")) {
3209
- throw new OkxApiError("pxSteps is required when maxSafetyOrds > 0", {
3210
- code: "VALIDATION",
3211
- endpoint: `${BASE}/create`
3212
- });
3213
- }
3214
- if (!readString(args, "pxStepsMult")) {
3215
- throw new OkxApiError("pxStepsMult is required when maxSafetyOrds > 0", {
3216
- code: "VALIDATION",
3217
- endpoint: `${BASE}/create`
3218
- });
3219
- }
3220
- if (!readString(args, "volMult")) {
3221
- throw new OkxApiError("volMult is required when maxSafetyOrds > 0", {
3222
- code: "VALIDATION",
3223
- endpoint: `${BASE}/create`
3224
- });
3225
- }
3226
- }
3235
+ validateSafetyOrderParams(args, maxSafetyOrds);
3236
+ const allowReinvestRaw = args["allowReinvest"];
3237
+ const allowReinvest = allowReinvestRaw !== void 0 ? allowReinvestRaw === true || allowReinvestRaw === "true" : void 0;
3227
3238
  const response = await context.client.privatePost(
3228
3239
  `${BASE}/create`,
3229
3240
  compactObject({
@@ -3240,7 +3251,7 @@ function registerDcaTools() {
3240
3251
  tpPct: requireString(args, "tpPct"),
3241
3252
  slPct: readString(args, "slPct"),
3242
3253
  slMode: readString(args, "slMode"),
3243
- allowReinvest: args["allowReinvest"] !== void 0 ? args["allowReinvest"] === true || args["allowReinvest"] === "true" : void 0,
3254
+ allowReinvest,
3244
3255
  triggerParams: [triggerParam],
3245
3256
  tag: context.config.sourceTag,
3246
3257
  algoClOrdId: readString(args, "algoClOrdId"),
@@ -4800,6 +4811,7 @@ function registerFuturesTools() {
4800
4811
  }
4801
4812
  ];
4802
4813
  }
4814
+ var TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1e3;
4803
4815
  function registerMarketTools() {
4804
4816
  return [
4805
4817
  {
@@ -4899,7 +4911,7 @@ function registerMarketTools() {
4899
4911
  {
4900
4912
  name: "market_get_candles",
4901
4913
  module: "market",
4902
- description: "Get candlestick (OHLCV) data for an instrument. history=false (default): recent candles up to 1440 bars; history=true: older historical data.",
4914
+ description: "Get candlestick (OHLCV) data for an instrument. Automatically retrieves historical data (back to 2021) when requesting older time ranges. Use the `after` parameter to paginate back in time (the old `history` parameter has been removed). IMPORTANT: Before fetching with `after`/`before`, estimate the number of candles: time_range_ms / bar_interval_ms. If the estimate exceeds ~500 candles, inform the user of the estimated count and ask for confirmation before proceeding.",
4903
4915
  isWrite: false,
4904
4916
  inputSchema: {
4905
4917
  type: "object",
@@ -4924,29 +4936,29 @@ function registerMarketTools() {
4924
4936
  limit: {
4925
4937
  type: "number",
4926
4938
  description: "Max results (default 100)"
4927
- },
4928
- history: {
4929
- type: "boolean",
4930
- description: "true=older historical data beyond recent window"
4931
4939
  }
4932
4940
  },
4933
4941
  required: ["instId"]
4934
4942
  },
4935
4943
  handler: async (rawArgs, context) => {
4936
4944
  const args = asRecord(rawArgs);
4937
- const isHistory = readBoolean(args, "history") ?? false;
4938
- const path42 = isHistory ? "/api/v5/market/history-candles" : "/api/v5/market/candles";
4939
- const response = await context.client.publicGet(
4940
- path42,
4941
- compactObject({
4942
- instId: requireString(args, "instId"),
4943
- bar: readString(args, "bar"),
4944
- after: readString(args, "after"),
4945
- before: readString(args, "before"),
4946
- limit: readNumber(args, "limit")
4947
- }),
4948
- publicRateLimit("market_get_candles", 40)
4949
- );
4945
+ const afterTs = readString(args, "after");
4946
+ const beforeTs = readString(args, "before");
4947
+ const query = compactObject({
4948
+ instId: requireString(args, "instId"),
4949
+ bar: readString(args, "bar"),
4950
+ after: afterTs,
4951
+ before: beforeTs,
4952
+ limit: readNumber(args, "limit")
4953
+ });
4954
+ const rateLimit = publicRateLimit("market_get_candles", 40);
4955
+ const hasTimestamp = afterTs !== void 0 || beforeTs !== void 0;
4956
+ const useHistory = afterTs !== void 0 && Number(afterTs) < Date.now() - TWO_DAYS_MS;
4957
+ const path42 = useHistory ? "/api/v5/market/history-candles" : "/api/v5/market/candles";
4958
+ const response = await context.client.publicGet(path42, query, rateLimit);
4959
+ if (!useHistory && hasTimestamp && Array.isArray(response.data) && response.data.length === 0) {
4960
+ return normalizeResponse(await context.client.publicGet("/api/v5/market/history-candles", query, rateLimit));
4961
+ }
4950
4962
  return normalizeResponse(response);
4951
4963
  }
4952
4964
  },
@@ -5799,7 +5811,14 @@ function registerOptionTools() {
5799
5811
  handler: async (rawArgs, context) => {
5800
5812
  const args = asRecord(rawArgs);
5801
5813
  const status = readString(args, "status") ?? "live";
5802
- const path42 = status === "archive" ? "/api/v5/trade/orders-history-archive" : status === "history" ? "/api/v5/trade/orders-history" : "/api/v5/trade/orders-pending";
5814
+ let path42;
5815
+ if (status === "archive") {
5816
+ path42 = "/api/v5/trade/orders-history-archive";
5817
+ } else if (status === "history") {
5818
+ path42 = "/api/v5/trade/orders-history";
5819
+ } else {
5820
+ path42 = "/api/v5/trade/orders-pending";
5821
+ }
5803
5822
  const response = await context.client.privateGet(
5804
5823
  path42,
5805
5824
  compactObject({
@@ -7430,58 +7449,60 @@ function checkClaudeCodeConfig() {
7430
7449
  if (anyParseError) return "parse-error";
7431
7450
  return "not-configured";
7432
7451
  }
7452
+ function handleJsonClient(clientId, report, configuredClients) {
7453
+ const configPath = getConfigPath(clientId);
7454
+ if (!configPath) return false;
7455
+ const name = CLIENT_NAMES[clientId];
7456
+ const status = checkJsonMcpConfig(configPath);
7457
+ if (status === "missing") return false;
7458
+ if (status === "found") {
7459
+ ok(name, `configured (${sanitize(configPath)})`);
7460
+ report.add(`client_${clientId}`, `OK ${sanitize(configPath)}`);
7461
+ configuredClients.push(clientId);
7462
+ return false;
7463
+ }
7464
+ if (status === "not-configured") {
7465
+ fail(name, "okx-trade-mcp not found in mcpServers", [`Run: okx setup --client ${clientId}`]);
7466
+ report.add(`client_${clientId}`, "NOT_CONFIGURED");
7467
+ } else {
7468
+ fail(name, `JSON parse error in ${sanitize(configPath)}`, [
7469
+ `Check ${sanitize(configPath)} for JSON syntax errors`,
7470
+ `Then run: okx setup --client ${clientId}`
7471
+ ]);
7472
+ report.add(`client_${clientId}`, "PARSE_ERROR");
7473
+ }
7474
+ return true;
7475
+ }
7476
+ function handleClaudeCodeClient(report, configuredClients) {
7477
+ const status = checkClaudeCodeConfig();
7478
+ if (status === "missing") return false;
7479
+ const name = CLIENT_NAMES["claude-code"];
7480
+ if (status === "found") {
7481
+ ok(name, "configured");
7482
+ report.add("client_claude-code", "OK");
7483
+ configuredClients.push("claude-code");
7484
+ return false;
7485
+ }
7486
+ if (status === "not-configured") {
7487
+ warn(name, "installed but okx-trade-mcp not configured", [
7488
+ "Run: okx setup --client claude-code"
7489
+ ]);
7490
+ report.add("client_claude-code", "NOT_CONFIGURED");
7491
+ return false;
7492
+ }
7493
+ fail(name, "settings file has JSON parse error", ["Run: okx setup --client claude-code"]);
7494
+ report.add("client_claude-code", "PARSE_ERROR");
7495
+ return true;
7496
+ }
7433
7497
  function checkMcpClients(report) {
7434
7498
  section("MCP Client Config");
7435
7499
  const jsonClients = ["claude-desktop", "cursor", "windsurf"];
7436
7500
  const configuredClients = [];
7437
7501
  let anyFailed = false;
7438
7502
  for (const clientId of jsonClients) {
7439
- const configPath = getConfigPath(clientId);
7440
- if (!configPath) continue;
7441
- const name = CLIENT_NAMES[clientId];
7442
- const status = checkJsonMcpConfig(configPath);
7443
- if (status === "missing") {
7444
- continue;
7445
- }
7446
- if (status === "found") {
7447
- ok(name, `configured (${sanitize(configPath)})`);
7448
- report.add(`client_${clientId}`, `OK ${sanitize(configPath)}`);
7449
- configuredClients.push(clientId);
7450
- } else if (status === "not-configured") {
7451
- fail(name, "okx-trade-mcp not found in mcpServers", [
7452
- `Run: okx setup --client ${clientId}`
7453
- ]);
7454
- report.add(`client_${clientId}`, "NOT_CONFIGURED");
7455
- anyFailed = true;
7456
- } else {
7457
- fail(name, `JSON parse error in ${sanitize(configPath)}`, [
7458
- `Check ${sanitize(configPath)} for JSON syntax errors`,
7459
- `Then run: okx setup --client ${clientId}`
7460
- ]);
7461
- report.add(`client_${clientId}`, "PARSE_ERROR");
7462
- anyFailed = true;
7463
- }
7464
- }
7465
- const claudeCodeStatus = checkClaudeCodeConfig();
7466
- if (claudeCodeStatus !== "missing") {
7467
- const name = CLIENT_NAMES["claude-code"];
7468
- if (claudeCodeStatus === "found") {
7469
- ok(name, "configured");
7470
- report.add("client_claude-code", "OK");
7471
- configuredClients.push("claude-code");
7472
- } else if (claudeCodeStatus === "not-configured") {
7473
- warn(name, "installed but okx-trade-mcp not configured", [
7474
- "Run: okx setup --client claude-code"
7475
- ]);
7476
- report.add("client_claude-code", "NOT_CONFIGURED");
7477
- } else {
7478
- fail(name, "settings file has JSON parse error", [
7479
- "Run: okx setup --client claude-code"
7480
- ]);
7481
- report.add("client_claude-code", "PARSE_ERROR");
7482
- anyFailed = true;
7483
- }
7503
+ if (handleJsonClient(clientId, report, configuredClients)) anyFailed = true;
7484
7504
  }
7505
+ if (handleClaudeCodeClient(report, configuredClients)) anyFailed = true;
7485
7506
  if (configuredClients.length === 0 && !anyFailed) {
7486
7507
  fail("no client", "no MCP client configuration found", [
7487
7508
  "Run: okx setup --client <client>",
@@ -7755,7 +7776,7 @@ async function cmdDiagnoseMcp(options = {}) {
7755
7776
 
7756
7777
  // src/commands/diagnose.ts
7757
7778
  var CLI_VERSION = readCliVersion();
7758
- var GIT_HASH = true ? "475621d" : "dev";
7779
+ var GIT_HASH = true ? "f9ea608" : "dev";
7759
7780
  function maskKey2(key) {
7760
7781
  if (!key) return "(not set)";
7761
7782
  if (key.length <= 8) return "****";
@@ -8676,6 +8697,45 @@ function printGlobalHelp() {
8676
8697
  lines.push("", 'Run "okx <module> --help" for module details.', "");
8677
8698
  output(lines.join(EOL2));
8678
8699
  }
8700
+ function printSubgroupOnlyModule(lines, moduleName, group) {
8701
+ const subgroupNames = Object.keys(group.subgroups);
8702
+ const colWidth = Math.max(...subgroupNames.map((n) => n.length)) + 4;
8703
+ lines.push(`Usage: okx ${moduleName} <strategy> <action> [args...]`);
8704
+ lines.push("", `${group.description}.`, "");
8705
+ lines.push("Strategies:");
8706
+ for (const [sgName, sg] of Object.entries(group.subgroups)) {
8707
+ lines.push(` ${sgName.padEnd(colWidth)}${sg.description}`);
8708
+ }
8709
+ lines.push("", `Run "okx ${moduleName} <strategy> --help" for details.`);
8710
+ }
8711
+ function printMixedModule(lines, moduleName, group) {
8712
+ lines.push(`Usage: okx ${moduleName} <action> [args...]`);
8713
+ lines.push("", `${group.description}.`, "", "Commands:");
8714
+ printCommandList(lines, group.commands);
8715
+ lines.push("", "Subgroups:");
8716
+ const subgroupEntries = Object.entries(group.subgroups);
8717
+ const colWidth = Math.max(...subgroupEntries.map(([n]) => n.length)) + 4;
8718
+ for (const [sgName, sg] of subgroupEntries) {
8719
+ lines.push(` ${sgName.padEnd(colWidth)}${sg.description}`);
8720
+ }
8721
+ lines.push("", `Run "okx ${moduleName} <subgroup> --help" for subgroup details.`);
8722
+ }
8723
+ function printCommandsOnlyModule(lines, moduleName, group) {
8724
+ lines.push(`Usage: okx ${moduleName} <action> [args...]`);
8725
+ lines.push("", `${group.description}.`, "", "Commands:");
8726
+ printCommandList(lines, group.commands);
8727
+ }
8728
+ function printUsageModule(lines, group) {
8729
+ lines.push(`Usage: ${group.usage}`);
8730
+ lines.push("", `${group.description}.`);
8731
+ if (group.commands) {
8732
+ lines.push("");
8733
+ for (const cmd of Object.values(group.commands)) {
8734
+ lines.push(` ${cmd.description}`);
8735
+ lines.push(` Usage: ${cmd.usage}`);
8736
+ }
8737
+ }
8738
+ }
8679
8739
  function printModuleHelp(moduleName) {
8680
8740
  const group = HELP_TREE[moduleName];
8681
8741
  if (!group) {
@@ -8687,40 +8747,13 @@ function printModuleHelp(moduleName) {
8687
8747
  const hasCommands = group.commands && Object.keys(group.commands).length > 0;
8688
8748
  const lines = [""];
8689
8749
  if (hasSubgroups && !hasCommands) {
8690
- const subgroupNames = Object.keys(group.subgroups);
8691
- lines.push(`Usage: okx ${moduleName} <strategy> <action> [args...]`);
8692
- lines.push("", `${group.description}.`, "");
8693
- lines.push("Strategies:");
8694
- const colWidth = Math.max(...subgroupNames.map((n) => n.length)) + 4;
8695
- for (const [sgName, sg] of Object.entries(group.subgroups)) {
8696
- lines.push(` ${sgName.padEnd(colWidth)}${sg.description}`);
8697
- }
8698
- lines.push("", `Run "okx ${moduleName} <strategy> --help" for details.`);
8750
+ printSubgroupOnlyModule(lines, moduleName, group);
8699
8751
  } else if (hasSubgroups && hasCommands) {
8700
- lines.push(`Usage: okx ${moduleName} <action> [args...]`);
8701
- lines.push("", `${group.description}.`, "", "Commands:");
8702
- printCommandList(lines, group.commands);
8703
- lines.push("", "Subgroups:");
8704
- const subgroupEntries = Object.entries(group.subgroups);
8705
- const colWidth = Math.max(...subgroupEntries.map(([n]) => n.length)) + 4;
8706
- for (const [sgName, sg] of subgroupEntries) {
8707
- lines.push(` ${sgName.padEnd(colWidth)}${sg.description}`);
8708
- }
8709
- lines.push("", `Run "okx ${moduleName} <subgroup> --help" for subgroup details.`);
8752
+ printMixedModule(lines, moduleName, group);
8710
8753
  } else if (hasCommands) {
8711
- lines.push(`Usage: okx ${moduleName} <action> [args...]`);
8712
- lines.push("", `${group.description}.`, "", "Commands:");
8713
- printCommandList(lines, group.commands);
8754
+ printCommandsOnlyModule(lines, moduleName, group);
8714
8755
  } else if (group.usage) {
8715
- lines.push(`Usage: ${group.usage}`);
8716
- lines.push("", `${group.description}.`);
8717
- if (group.commands) {
8718
- lines.push("");
8719
- for (const cmd of Object.values(group.commands)) {
8720
- lines.push(` ${cmd.description}`);
8721
- lines.push(` Usage: ${cmd.usage}`);
8722
- }
8723
- }
8756
+ printUsageModule(lines, group);
8724
8757
  }
8725
8758
  lines.push("");
8726
8759
  output(lines.join(EOL2));
@@ -8791,6 +8824,8 @@ var CLI_OPTIONS = {
8791
8824
  bar: { type: "string" },
8792
8825
  limit: { type: "string" },
8793
8826
  sz: { type: "string" },
8827
+ after: { type: "string" },
8828
+ before: { type: "string" },
8794
8829
  // orders
8795
8830
  instId: { type: "string" },
8796
8831
  history: { type: "boolean", default: false },
@@ -8842,6 +8877,7 @@ var CLI_OPTIONS = {
8842
8877
  quoteCcy: { type: "string" },
8843
8878
  // account extras
8844
8879
  archive: { type: "boolean", default: false },
8880
+ valuation: { type: "boolean", default: false },
8845
8881
  posMode: { type: "string" },
8846
8882
  ccy: { type: "string" },
8847
8883
  from: { type: "string" },
@@ -9136,7 +9172,7 @@ async function cmdMarketOrderbook(run, instId, sz, json) {
9136
9172
  for (const [p, s] of bids) outputLine(` ${p.padStart(16)} ${s}`);
9137
9173
  }
9138
9174
  async function cmdMarketCandles(run, instId, opts) {
9139
- const result = await run("market_get_candles", { instId, bar: opts.bar, limit: opts.limit });
9175
+ const result = await run("market_get_candles", { instId, bar: opts.bar, limit: opts.limit, after: opts.after, before: opts.before });
9140
9176
  const candles = getData(result);
9141
9177
  if (opts.json) return printJson(candles);
9142
9178
  printTable(
@@ -9227,27 +9263,53 @@ async function cmdAccountBalance(run, ccy, json) {
9227
9263
  const data = getData2(result);
9228
9264
  if (json) return printJson(data);
9229
9265
  const details = data?.[0]?.["details"] ?? [];
9230
- printTable(
9231
- details.filter((d) => Number(d["eq"]) > 0).map((d) => ({
9232
- currency: d["ccy"],
9233
- equity: d["eq"],
9234
- available: d["availEq"],
9235
- frozen: d["frozenBal"]
9236
- }))
9237
- );
9266
+ const rows = details.filter((d) => Number(d["eq"]) > 0).map((d) => ({
9267
+ currency: d["ccy"],
9268
+ equity: d["eq"],
9269
+ available: d["availEq"],
9270
+ frozen: d["frozenBal"]
9271
+ }));
9272
+ if (rows.length === 0 && data?.[0]) {
9273
+ printTable([{ currency: "Total", equity: data[0]["totalEq"] ?? "0", available: data[0]["adjEq"] ?? "0", frozen: "-" }]);
9274
+ return;
9275
+ }
9276
+ printTable(rows);
9238
9277
  }
9239
- async function cmdAccountAssetBalance(run, ccy, json) {
9240
- const result = await run("account_get_asset_balance", { ccy });
9241
- const data = getData2(result);
9242
- if (json) return printJson(data);
9243
- printTable(
9244
- (data ?? []).filter((r) => Number(r["bal"]) > 0).map((r) => ({
9245
- ccy: r["ccy"],
9246
- bal: r["bal"],
9247
- availBal: r["availBal"],
9248
- frozenBal: r["frozenBal"]
9249
- }))
9250
- );
9278
+ async function cmdAccountAssetBalance(run, ccy, json, showValuation) {
9279
+ const result = await run("account_get_asset_balance", {
9280
+ ccy,
9281
+ ...showValuation ? { showValuation: true } : {}
9282
+ });
9283
+ const data = result.data ?? [];
9284
+ if (json) return printJson(showValuation ? { data, valuation: result.valuation } : data);
9285
+ const assetRows = data.filter((r) => Number(r["bal"]) > 0).map((r) => ({
9286
+ ccy: r["ccy"],
9287
+ bal: r["bal"],
9288
+ availBal: r["availBal"],
9289
+ frozenBal: r["frozenBal"]
9290
+ }));
9291
+ if (assetRows.length === 0 && data.length > 0) {
9292
+ outputLine("Total balance: 0");
9293
+ } else {
9294
+ printTable(assetRows);
9295
+ }
9296
+ if (showValuation && result.valuation) {
9297
+ const valuationData = result.valuation ?? [];
9298
+ outputLine("");
9299
+ outputLine("Asset Valuation by Account Type:");
9300
+ printTable(
9301
+ valuationData.map((v) => {
9302
+ const details = v["details"] ?? {};
9303
+ return {
9304
+ totalBal: v["totalBal"],
9305
+ classic: details["classic"],
9306
+ earn: details["earn"],
9307
+ funding: details["funding"],
9308
+ trading: details["trading"]
9309
+ };
9310
+ })
9311
+ );
9312
+ }
9251
9313
  }
9252
9314
  async function cmdAccountPositions(run, opts) {
9253
9315
  const result = await run("account_get_positions", { instType: opts.instType, instId: opts.instId });
@@ -10163,7 +10225,7 @@ async function cmdFuturesBatch(run, opts) {
10163
10225
  process.exitCode = 1;
10164
10226
  return;
10165
10227
  }
10166
- const result = await run(tool, tool === "futures_batch_orders" ? { orders: parsed } : { orders: parsed });
10228
+ const result = await run(tool, { orders: parsed });
10167
10229
  const data = getData5(result);
10168
10230
  if (opts.json) return printJson(data);
10169
10231
  emitBatchResults3(data ?? []);
@@ -10667,6 +10729,58 @@ function buildProfileEntry(siteKey, apiKey, secretKey, passphrase, demo) {
10667
10729
  }
10668
10730
  return entry;
10669
10731
  }
10732
+ function tryOpenUrl(url) {
10733
+ try {
10734
+ let opener;
10735
+ if (process.platform === "darwin") {
10736
+ opener = "open";
10737
+ } else if (process.platform === "win32") {
10738
+ opener = "start";
10739
+ } else {
10740
+ opener = "xdg-open";
10741
+ }
10742
+ spawnSync2(opener, [url], { stdio: "ignore", shell: process.platform === "win32" });
10743
+ } catch {
10744
+ }
10745
+ }
10746
+ async function promptCredentials(rl, t) {
10747
+ const apiKey = (await prompt(rl, "API Key: ")).trim();
10748
+ if (!apiKey) {
10749
+ errorLine(t.emptyApiKey);
10750
+ process.exitCode = 1;
10751
+ return null;
10752
+ }
10753
+ const secretKey = (await prompt(rl, "Secret Key: ")).trim();
10754
+ if (!secretKey) {
10755
+ errorLine(t.emptySecretKey);
10756
+ process.exitCode = 1;
10757
+ return null;
10758
+ }
10759
+ const passphrase = (await prompt(rl, "Passphrase: ")).trim();
10760
+ if (!passphrase) {
10761
+ errorLine(t.emptyPassphrase);
10762
+ process.exitCode = 1;
10763
+ return null;
10764
+ }
10765
+ return { apiKey, secretKey, passphrase };
10766
+ }
10767
+ function saveConfig(config, profileName, t) {
10768
+ const configPath = configFilePath();
10769
+ try {
10770
+ writeCliConfig(config);
10771
+ output(t.saved(configPath));
10772
+ output(t.defaultProfile(profileName));
10773
+ output(t.usage);
10774
+ } catch (err) {
10775
+ const message = err instanceof Error ? err.message : String(err);
10776
+ const isPermission = err instanceof Error && "code" in err && (err.code === "EACCES" || err.code === "EPERM");
10777
+ errorOutput(t.writeFailed(message));
10778
+ if (isPermission) errorOutput(t.permissionDenied(configPath));
10779
+ errorOutput(t.manualWrite(configPath));
10780
+ outputLine(stringify(config));
10781
+ process.exitCode = 1;
10782
+ }
10783
+ }
10670
10784
  async function cmdConfigInit(lang = "en") {
10671
10785
  const t = messages[lang];
10672
10786
  outputLine(t.title);
@@ -10682,14 +10796,9 @@ async function cmdConfigInit(lang = "en") {
10682
10796
  const demoRaw = (await prompt(rl, t.demoPrompt)).trim().toLowerCase();
10683
10797
  const demo = demoRaw !== "n";
10684
10798
  const apiUrl = buildApiUrl(siteKey, demo);
10685
- const hintText = demo ? t.hintDemo : t.hintLive;
10686
10799
  output(t.createApiKey(apiUrl));
10687
- output(t.hint(hintText));
10688
- try {
10689
- const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
10690
- spawnSync2(opener, [apiUrl], { stdio: "ignore", shell: process.platform === "win32" });
10691
- } catch {
10692
- }
10800
+ output(t.hint(demo ? t.hintDemo : t.hintLive));
10801
+ tryOpenUrl(apiUrl);
10693
10802
  const defaultProfileName = demo ? "okx-demo" : "okx-prod";
10694
10803
  const profileNameRaw = await prompt(rl, t.profilePrompt(defaultProfileName));
10695
10804
  const profileName = profileNameRaw.trim() || defaultProfileName;
@@ -10701,49 +10810,14 @@ async function cmdConfigInit(lang = "en") {
10701
10810
  return;
10702
10811
  }
10703
10812
  }
10704
- const apiKey = (await prompt(rl, "API Key: ")).trim();
10705
- if (!apiKey) {
10706
- errorLine(t.emptyApiKey);
10707
- process.exitCode = 1;
10708
- return;
10709
- }
10710
- const secretKey = (await prompt(rl, "Secret Key: ")).trim();
10711
- if (!secretKey) {
10712
- errorLine(t.emptySecretKey);
10713
- process.exitCode = 1;
10714
- return;
10715
- }
10716
- const passphrase = (await prompt(rl, "Passphrase: ")).trim();
10717
- if (!passphrase) {
10718
- errorLine(t.emptyPassphrase);
10719
- process.exitCode = 1;
10720
- return;
10721
- }
10722
- if (demo) {
10723
- outputLine(t.demoSelected);
10724
- }
10725
- const profileEntry = buildProfileEntry(siteKey, apiKey, secretKey, passphrase, demo);
10726
- config.profiles[profileName] = profileEntry;
10813
+ const credentials = await promptCredentials(rl, t);
10814
+ if (!credentials) return;
10815
+ if (demo) outputLine(t.demoSelected);
10816
+ config.profiles[profileName] = buildProfileEntry(siteKey, credentials.apiKey, credentials.secretKey, credentials.passphrase, demo);
10727
10817
  if (!config.default_profile || config.default_profile !== profileName) {
10728
10818
  config.default_profile = profileName;
10729
10819
  }
10730
- const configPath = configFilePath();
10731
- try {
10732
- writeCliConfig(config);
10733
- output(t.saved(configPath));
10734
- output(t.defaultProfile(profileName));
10735
- output(t.usage);
10736
- } catch (err) {
10737
- const message = err instanceof Error ? err.message : String(err);
10738
- const isPermission = err instanceof Error && "code" in err && (err.code === "EACCES" || err.code === "EPERM");
10739
- errorOutput(t.writeFailed(message));
10740
- if (isPermission) {
10741
- errorOutput(t.permissionDenied(configPath));
10742
- }
10743
- errorOutput(t.manualWrite(configPath));
10744
- outputLine(stringify(config));
10745
- process.exitCode = 1;
10746
- }
10820
+ saveConfig(config, profileName, t);
10747
10821
  } finally {
10748
10822
  rl.close();
10749
10823
  }
@@ -11119,7 +11193,6 @@ async function cmdGridCreate(run, opts) {
11119
11193
  });
11120
11194
  const data = getData7(result);
11121
11195
  if (opts.json) return printJson(data);
11122
- const r = data?.[0];
11123
11196
  emitWriteResult5(data?.[0], "Grid bot created", "algoId");
11124
11197
  }
11125
11198
  async function cmdGridStop(run, opts) {
@@ -11131,7 +11204,6 @@ async function cmdGridStop(run, opts) {
11131
11204
  });
11132
11205
  const data = getData7(result);
11133
11206
  if (opts.json) return printJson(data);
11134
- const r = data?.[0];
11135
11207
  emitWriteResult5(data?.[0], "Grid bot stopped", "algoId");
11136
11208
  }
11137
11209
  async function cmdDcaCreate(run, opts) {
@@ -11565,7 +11637,7 @@ async function cmdDcdQuoteAndBuy(run, opts) {
11565
11637
  // src/index.ts
11566
11638
  var _require3 = createRequire3(import.meta.url);
11567
11639
  var CLI_VERSION2 = _require3("../package.json").version;
11568
- var GIT_HASH2 = true ? "475621d" : "dev";
11640
+ var GIT_HASH2 = true ? "f9ea608" : "dev";
11569
11641
  function handleConfigCommand(action, rest, json, lang, force) {
11570
11642
  if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
11571
11643
  if (action === "show") return cmdConfigShow(json);
@@ -11626,7 +11698,7 @@ function handleMarketDataCommand(run, action, rest, v, json) {
11626
11698
  if (action === "orderbook")
11627
11699
  return cmdMarketOrderbook(run, rest[0], v.sz !== void 0 ? Number(v.sz) : void 0, json);
11628
11700
  if (action === "candles")
11629
- return cmdMarketCandles(run, rest[0], { bar: v.bar, limit, json });
11701
+ return cmdMarketCandles(run, rest[0], { bar: v.bar, limit, after: v.after, before: v.before, json });
11630
11702
  if (action === "funding-rate")
11631
11703
  return cmdMarketFundingRate(run, rest[0], { history: v.history ?? false, limit, json });
11632
11704
  if (action === "trades")
@@ -11661,7 +11733,7 @@ function handleAccountCommand(run, action, rest, v, json) {
11661
11733
  return cmdAccountAudit({ limit: v.limit, tool: v.tool, since: v.since, json });
11662
11734
  const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
11663
11735
  if (action === "balance") return cmdAccountBalance(run, rest[0], json);
11664
- if (action === "asset-balance") return cmdAccountAssetBalance(run, v.ccy, json);
11736
+ if (action === "asset-balance") return cmdAccountAssetBalance(run, v.ccy, json, v.valuation);
11665
11737
  if (action === "positions")
11666
11738
  return cmdAccountPositions(run, { instType: v.instType, instId: v.instId, json });
11667
11739
  if (action === "positions-history")