@okx_ai/okx-trade-cli 1.3.1 → 1.3.2-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
@@ -892,19 +892,19 @@ import { get as httpsGet } from "https";
892
892
  import { get as httpGet } from "http";
893
893
  var EXEC_TIMEOUT_MS = 3e4;
894
894
  var ALLOWED_DOMAIN_RE = /^[\w.-]+\.okx\.com$/;
895
- var DOH_BIN_DIR = join(homedir(), ".okx", "bin");
896
- function getDohBinaryPath() {
897
- if (process.env.OKX_DOH_BINARY_PATH) {
898
- return process.env.OKX_DOH_BINARY_PATH;
895
+ var PILOT_BIN_DIR = join(homedir(), ".okx", "bin");
896
+ function getPilotBinaryPath() {
897
+ if (process.env.OKX_PILOT_BINARY_PATH) {
898
+ return process.env.OKX_PILOT_BINARY_PATH;
899
899
  }
900
900
  const ext = process.platform === "win32" ? ".exe" : "";
901
- return join(DOH_BIN_DIR, `okx-pilot${ext}`);
901
+ return join(PILOT_BIN_DIR, `okx-pilot${ext}`);
902
902
  }
903
- function execDohBinary(domain, exclude = [], userAgent) {
903
+ function execPilotBinary(domain, exclude = [], userAgent) {
904
904
  if (!ALLOWED_DOMAIN_RE.test(domain)) {
905
905
  return Promise.resolve(null);
906
906
  }
907
- const binPath = getDohBinaryPath();
907
+ const binPath = getPilotBinaryPath();
908
908
  const args = ["--domain", domain];
909
909
  if (exclude.length > 0) {
910
910
  args.push("--exclude", exclude.join(","));
@@ -937,7 +937,7 @@ function execDohBinary(domain, exclude = [], userAgent) {
937
937
  });
938
938
  }
939
939
  function getDefaultCachePath() {
940
- return process.env.OKX_DOH_CACHE_PATH || join2(homedir2(), ".okx", "doh-cache.json");
940
+ return process.env.OKX_PILOT_CACHE_PATH || join2(homedir2(), ".okx", "pilot-cache.json");
941
941
  }
942
942
  function readCache(hostname, cachePath = getDefaultCachePath()) {
943
943
  try {
@@ -991,7 +991,7 @@ function getActiveFailedNodes(nodes) {
991
991
  const now = Date.now();
992
992
  return nodes.filter((n) => now - n.failedAt < FAILED_NODE_TTL_MS);
993
993
  }
994
- function resolveDoh(hostname, cachePath) {
994
+ function resolvePilot(hostname, cachePath) {
995
995
  const entry = readCache(hostname, cachePath);
996
996
  if (entry) {
997
997
  if (entry.mode === "direct") {
@@ -1003,53 +1003,53 @@ function resolveDoh(hostname, cachePath) {
1003
1003
  }
1004
1004
  return { mode: null, node: null };
1005
1005
  }
1006
- async function reResolveDoh(hostname, failedIp, userAgent, cachePath) {
1006
+ async function reResolvePilot(hostname, failedIp, userAgent, cachePath) {
1007
1007
  const entry = readCache(hostname, cachePath);
1008
1008
  const active = getActiveFailedNodes(entry?.failedNodes);
1009
1009
  const now = Date.now();
1010
1010
  const alreadyFailed = failedIp && active.some((n) => n.ip === failedIp);
1011
1011
  const failedNodes = failedIp && !alreadyFailed ? [...active, { ip: failedIp, failedAt: now }] : active;
1012
1012
  const excludeIps = failedNodes.map((n) => n.ip);
1013
- const node = await execDohBinary(hostname, excludeIps, userAgent);
1013
+ const node = await execPilotBinary(hostname, excludeIps, userAgent);
1014
1014
  return classifyAndCache(node, hostname, failedNodes, cachePath);
1015
1015
  }
1016
1016
  function vlog(message) {
1017
1017
  process.stderr.write(`[verbose] ${message}
1018
1018
  `);
1019
1019
  }
1020
- var DohManager = class {
1020
+ var PilotManager = class {
1021
1021
  opts;
1022
- // DoH proxy state (lazy-resolved on first request)
1023
- dohResolved = false;
1024
- dohRetried = false;
1022
+ // Pilot proxy state (lazy-resolved on first request)
1023
+ pilotResolved = false;
1024
+ pilotRetried = false;
1025
1025
  directUnverified = false;
1026
1026
  // The first direct connection has not yet been verified
1027
- dohNode = null;
1028
- dohAgent = null;
1029
- dohBaseUrl = null;
1027
+ pilotNode = null;
1028
+ pilotAgent = null;
1029
+ pilotBaseUrl = null;
1030
1030
  constructor(opts) {
1031
1031
  this.opts = opts;
1032
1032
  }
1033
1033
  /**
1034
- * Lazily resolve the DoH proxy node on the first request.
1034
+ * Lazily resolve the Pilot proxy node on the first request.
1035
1035
  * Uses cache-first strategy via the resolver.
1036
1036
  */
1037
- prepareDoh() {
1038
- if (this.dohResolved || this.opts.hasCustomProxy) return;
1039
- this.dohResolved = true;
1037
+ preparePilot() {
1038
+ if (this.pilotResolved || this.opts.hasCustomProxy) return;
1039
+ this.pilotResolved = true;
1040
1040
  try {
1041
1041
  const { hostname, protocol } = new URL(this.opts.baseUrl);
1042
- const result = resolveDoh(hostname);
1042
+ const result = resolvePilot(hostname);
1043
1043
  if (!result.mode) {
1044
1044
  this.directUnverified = true;
1045
1045
  if (this.opts.verbose) {
1046
- vlog("DoH: no cache, trying direct connection first");
1046
+ vlog("Pilot: no cache, trying direct connection first");
1047
1047
  }
1048
1048
  return;
1049
1049
  }
1050
1050
  if (result.mode === "direct") {
1051
1051
  if (this.opts.verbose) {
1052
- vlog("DoH: mode=direct (overseas or cached), using direct connection");
1052
+ vlog("Pilot: mode=direct (overseas or cached), using direct connection");
1053
1053
  }
1054
1054
  return;
1055
1055
  }
@@ -1059,57 +1059,57 @@ var DohManager = class {
1059
1059
  } catch (err) {
1060
1060
  if (this.opts.verbose) {
1061
1061
  const cause = err instanceof Error ? err.message : String(err);
1062
- vlog(`DoH resolution failed, falling back to direct: ${cause}`);
1062
+ vlog(`Pilot resolution failed, falling back to direct: ${cause}`);
1063
1063
  }
1064
1064
  }
1065
1065
  }
1066
1066
  /** Get connection parameters for the current request. */
1067
1067
  getConnectionParams() {
1068
- const baseUrl = this.dohNode ? this.dohBaseUrl : this.opts.baseUrl;
1068
+ const baseUrl = this.pilotNode ? this.pilotBaseUrl : this.opts.baseUrl;
1069
1069
  const result = { baseUrl };
1070
- if (this.dohAgent) {
1071
- result.dispatcher = this.dohAgent;
1070
+ if (this.pilotAgent) {
1071
+ result.dispatcher = this.pilotAgent;
1072
1072
  }
1073
- if (this.dohNode) {
1074
- result.userAgent = this.dohUserAgent;
1073
+ if (this.pilotNode) {
1074
+ result.userAgent = this.pilotUserAgent;
1075
1075
  }
1076
1076
  return result;
1077
1077
  }
1078
- /** Whether a DoH proxy node is currently active. */
1078
+ /** Whether a Pilot proxy node is currently active. */
1079
1079
  get isProxyActive() {
1080
- return this.dohNode !== null;
1080
+ return this.pilotNode !== null;
1081
1081
  }
1082
1082
  /** Whether we have already retried after network failure. */
1083
1083
  get hasRetried() {
1084
- return this.dohRetried;
1084
+ return this.pilotRetried;
1085
1085
  }
1086
1086
  /**
1087
1087
  * Handle network failure: re-resolve with --exclude and retry once.
1088
1088
  * Returns true if retry should proceed, false if already retried.
1089
1089
  */
1090
1090
  async handleNetworkFailure() {
1091
- if (this.dohRetried) return false;
1092
- this.dohRetried = true;
1093
- const failedIp = this.dohNode?.ip ?? "";
1091
+ if (this.pilotRetried) return false;
1092
+ this.pilotRetried = true;
1093
+ const failedIp = this.pilotNode?.ip ?? "";
1094
1094
  const { hostname, protocol } = new URL(this.opts.baseUrl);
1095
- this.dohNode = null;
1096
- this.dohAgent = null;
1097
- this.dohBaseUrl = null;
1095
+ this.pilotNode = null;
1096
+ this.pilotAgent = null;
1097
+ this.pilotBaseUrl = null;
1098
1098
  if (!failedIp) this.directUnverified = false;
1099
1099
  if (this.opts.verbose) {
1100
- vlog(failedIp ? `DoH: proxy node ${failedIp} failed, re-resolving with --exclude` : "DoH: direct connection failed, calling binary for DoH resolution");
1100
+ vlog(failedIp ? `Pilot: proxy node ${failedIp} failed, re-resolving with --exclude` : "Pilot: direct connection failed, calling binary for Pilot resolution");
1101
1101
  }
1102
1102
  try {
1103
- const result = await reResolveDoh(hostname, failedIp, this.dohUserAgent);
1103
+ const result = await reResolvePilot(hostname, failedIp, this.pilotUserAgent);
1104
1104
  if (result.mode === "proxy" && result.node) {
1105
1105
  this.applyNode(result.node, protocol);
1106
- this.dohRetried = false;
1106
+ this.pilotRetried = false;
1107
1107
  return true;
1108
1108
  }
1109
1109
  } catch {
1110
1110
  }
1111
1111
  if (this.opts.verbose) {
1112
- vlog("DoH: re-resolution failed or switched to direct, retrying with direct connection");
1112
+ vlog("Pilot: re-resolution failed or switched to direct, retrying with direct connection");
1113
1113
  }
1114
1114
  return true;
1115
1115
  }
@@ -1118,7 +1118,7 @@ var DohManager = class {
1118
1118
  * (Even if the business response is an error, the network path is valid.)
1119
1119
  */
1120
1120
  cacheDirectIfNeeded() {
1121
- if (!this.directUnverified || this.dohNode) return;
1121
+ if (!this.directUnverified || this.pilotNode) return;
1122
1122
  this.directUnverified = false;
1123
1123
  const { hostname } = new URL(this.opts.baseUrl);
1124
1124
  writeCache(hostname, {
@@ -1128,25 +1128,25 @@ var DohManager = class {
1128
1128
  updatedAt: Date.now()
1129
1129
  });
1130
1130
  if (this.opts.verbose) {
1131
- vlog("DoH: direct connection succeeded, cached mode=direct");
1131
+ vlog("Pilot: direct connection succeeded, cached mode=direct");
1132
1132
  }
1133
1133
  }
1134
- /** User-Agent for DoH proxy requests: OKX/@okx_ai/{packageName}/{version} */
1135
- get dohUserAgent() {
1134
+ /** User-Agent for Pilot proxy requests: OKX/@okx_ai/{packageName}/{version} */
1135
+ get pilotUserAgent() {
1136
1136
  return `OKX/@okx_ai/${this.opts.packageUserAgent ?? "unknown"}`;
1137
1137
  }
1138
1138
  /**
1139
- * Apply a DoH node: set up the custom Agent + base URL.
1139
+ * Apply a Pilot node: set up the custom Agent + base URL.
1140
1140
  *
1141
1141
  * node.ip may be a real IP or a domain (CNAME like *.aliyunddos1021.com).
1142
1142
  * - Real IP → use directly in lookup callback
1143
1143
  * - Domain → dns.lookup on every connection to get a fresh IP
1144
1144
  */
1145
1145
  applyNode(node, protocol) {
1146
- this.dohNode = node;
1147
- this.dohBaseUrl = `${protocol}//${node.host}`;
1146
+ this.pilotNode = node;
1147
+ this.pilotBaseUrl = `${protocol}//${node.host}`;
1148
1148
  const nodeIpIsRealIp = !!isIP(node.ip);
1149
- this.dohAgent = new Agent({
1149
+ this.pilotAgent = new Agent({
1150
1150
  connect: {
1151
1151
  lookup: (_hostname, options, callback) => {
1152
1152
  if (nodeIpIsRealIp) {
@@ -1170,7 +1170,7 @@ var DohManager = class {
1170
1170
  }
1171
1171
  });
1172
1172
  if (this.opts.verbose) {
1173
- vlog(`DoH proxy active: \u2192 ${node.host} (${node.ip}), ttl=${node.ttl}s`);
1173
+ vlog(`Pilot proxy active: \u2192 ${node.host} (${node.ip}), ttl=${node.ttl}s`);
1174
1174
  }
1175
1175
  }
1176
1176
  };
@@ -1392,14 +1392,14 @@ var OkxRestClient = class _OkxRestClient {
1392
1392
  config;
1393
1393
  rateLimiter;
1394
1394
  dispatcher;
1395
- doh;
1395
+ pilot;
1396
1396
  constructor(config) {
1397
1397
  this.config = config;
1398
1398
  this.rateLimiter = new RateLimiter(3e4, config.verbose);
1399
1399
  if (config.proxyUrl) {
1400
1400
  this.dispatcher = new ProxyAgent(config.proxyUrl);
1401
1401
  }
1402
- this.doh = new DohManager({
1402
+ this.pilot = new PilotManager({
1403
1403
  baseUrl: config.baseUrl,
1404
1404
  packageUserAgent: config.userAgent,
1405
1405
  verbose: config.verbose,
@@ -1453,13 +1453,14 @@ var OkxRestClient = class _OkxRestClient {
1453
1453
  rateLimit
1454
1454
  });
1455
1455
  }
1456
- async privatePost(path42, body, rateLimit) {
1456
+ async privatePost(path42, body, rateLimit, retryOnNetworkError) {
1457
1457
  return this.request({
1458
1458
  method: "POST",
1459
1459
  path: path42,
1460
1460
  auth: "private",
1461
1461
  body,
1462
- rateLimit
1462
+ rateLimit,
1463
+ retryOnNetworkError
1463
1464
  });
1464
1465
  }
1465
1466
  setAuthHeaders(headers, method, requestPath, bodyJson, timestamp) {
@@ -1581,12 +1582,12 @@ var OkxRestClient = class _OkxRestClient {
1581
1582
  * Security: validates Content-Type and enforces maxBytes limit.
1582
1583
  */
1583
1584
  async privatePostBinary(path42, body, opts) {
1584
- this.doh.prepareDoh();
1585
+ this.pilot.preparePilot();
1585
1586
  const maxBytes = opts?.maxBytes ?? _OkxRestClient.DEFAULT_MAX_BYTES;
1586
1587
  const expectedCT = opts?.expectedContentType ?? "application/octet-stream";
1587
1588
  const bodyJson = body ? JSON.stringify(body) : "";
1588
1589
  const endpoint = `POST ${path42}`;
1589
- const conn = this.doh.getConnectionParams();
1590
+ const conn = this.pilot.getConnectionParams();
1590
1591
  this.logRequest("POST", `${conn.baseUrl}${path42}`, "private");
1591
1592
  const reqConfig = { method: "POST", path: path42, auth: "private" };
1592
1593
  const headers = this.buildHeaders(reqConfig, path42, bodyJson, getNow());
@@ -1598,13 +1599,15 @@ var OkxRestClient = class _OkxRestClient {
1598
1599
  try {
1599
1600
  response = await this.fetchBinary(path42, endpoint, headers, bodyJson, t0);
1600
1601
  } catch (error) {
1601
- this.doh.handleNetworkFailure().catch(() => {
1602
- });
1602
+ try {
1603
+ await this.pilot.handleNetworkFailure();
1604
+ } catch {
1605
+ }
1603
1606
  throw error;
1604
1607
  }
1605
1608
  const elapsed = Date.now() - t0;
1606
1609
  const traceId = extractTraceId(response.headers);
1607
- this.doh.cacheDirectIfNeeded();
1610
+ this.pilot.cacheDirectIfNeeded();
1608
1611
  if (!response.ok) {
1609
1612
  const text = await response.text();
1610
1613
  this.logResponse(response.status, text.length, elapsed, traceId, String(response.status));
@@ -1630,15 +1633,15 @@ var OkxRestClient = class _OkxRestClient {
1630
1633
  /**
1631
1634
  * Send an unauthenticated GET request and return the raw binary response.
1632
1635
  * Used for pre-signed download URLs where auth is embedded in the token.
1633
- * Inherits proxy, timeout, DoH, and verbose capabilities from the client.
1636
+ * Inherits proxy, timeout, Pilot, and verbose capabilities from the client.
1634
1637
  */
1635
1638
  async publicGetBinary(path42, query, opts) {
1636
- this.doh.prepareDoh();
1639
+ this.pilot.preparePilot();
1637
1640
  const maxBytes = opts?.maxBytes ?? _OkxRestClient.DEFAULT_MAX_BYTES;
1638
1641
  const expectedCT = opts?.expectedContentType ?? "application/octet-stream";
1639
1642
  const queryString = buildQueryString(query);
1640
1643
  const requestPath = queryString ? `${path42}?${queryString}` : path42;
1641
- const conn = this.doh.getConnectionParams();
1644
+ const conn = this.pilot.getConnectionParams();
1642
1645
  const url = `${conn.baseUrl}${requestPath}`;
1643
1646
  this.logRequest("GET", url, "public");
1644
1647
  const headers = new Headers({ Accept: "application/octet-stream" });
@@ -1654,13 +1657,15 @@ var OkxRestClient = class _OkxRestClient {
1654
1657
  dispatcher: this.dispatcher ?? conn.dispatcher
1655
1658
  });
1656
1659
  } catch (error) {
1657
- this.doh.handleNetworkFailure().catch(() => {
1658
- });
1660
+ try {
1661
+ await this.pilot.handleNetworkFailure();
1662
+ } catch {
1663
+ }
1659
1664
  throw new NetworkError(`Failed to call OKX endpoint GET ${path42}.`, `GET ${path42}`, error);
1660
1665
  }
1661
1666
  const elapsed = Date.now() - t0;
1662
1667
  const traceId = extractTraceId(response.headers);
1663
- this.doh.cacheDirectIfNeeded();
1668
+ this.pilot.cacheDirectIfNeeded();
1664
1669
  if (!response.ok) {
1665
1670
  const text = await response.text();
1666
1671
  this.logResponse(response.status, text.length, elapsed, traceId, String(response.status));
@@ -1685,7 +1690,7 @@ var OkxRestClient = class _OkxRestClient {
1685
1690
  }
1686
1691
  /** Execute fetch for binary endpoint, wrapping network errors. */
1687
1692
  async fetchBinary(path42, endpoint, headers, bodyJson, t0) {
1688
- const conn = this.doh.getConnectionParams();
1693
+ const conn = this.pilot.getConnectionParams();
1689
1694
  try {
1690
1695
  const fetchOptions = {
1691
1696
  method: "POST",
@@ -1732,17 +1737,17 @@ var OkxRestClient = class _OkxRestClient {
1732
1737
  // JSON request
1733
1738
  // ---------------------------------------------------------------------------
1734
1739
  /**
1735
- * Handle network error during a JSON request: refresh DoH and maybe retry.
1740
+ * Handle network error during a JSON request: refresh Pilot and maybe retry.
1736
1741
  * Always either returns a retry result or throws NetworkError.
1737
1742
  */
1738
1743
  async handleRequestNetworkError(error, reqConfig, requestPath, t0) {
1739
- if (!this.doh.hasRetried) {
1744
+ if (!this.pilot.hasRetried) {
1740
1745
  if (this.config.verbose) {
1741
1746
  const cause = error instanceof Error ? error.message : String(error);
1742
- vlog2(`Network failure, refreshing DoH: ${cause}`);
1747
+ vlog2(`Network failure, refreshing Pilot: ${cause}`);
1743
1748
  }
1744
- const shouldRetry = await this.doh.handleNetworkFailure();
1745
- if (shouldRetry && reqConfig.method === "GET") {
1749
+ const shouldRetry = await this.pilot.handleNetworkFailure();
1750
+ if (shouldRetry && (reqConfig.method === "GET" || reqConfig.retryOnNetworkError)) {
1746
1751
  return this.request(reqConfig);
1747
1752
  }
1748
1753
  }
@@ -1758,10 +1763,10 @@ var OkxRestClient = class _OkxRestClient {
1758
1763
  );
1759
1764
  }
1760
1765
  async request(reqConfig) {
1761
- this.doh.prepareDoh();
1766
+ this.pilot.preparePilot();
1762
1767
  const queryString = buildQueryString(reqConfig.query);
1763
1768
  const requestPath = queryString.length > 0 ? `${reqConfig.path}?${queryString}` : reqConfig.path;
1764
- const conn = this.doh.getConnectionParams();
1769
+ const conn = this.pilot.getConnectionParams();
1765
1770
  const url = `${conn.baseUrl}${requestPath}`;
1766
1771
  const bodyJson = reqConfig.body ? JSON.stringify(reqConfig.body) : "";
1767
1772
  const timestamp = getNow();
@@ -1790,7 +1795,7 @@ var OkxRestClient = class _OkxRestClient {
1790
1795
  const rawText = await response.text();
1791
1796
  const elapsed = Date.now() - t0;
1792
1797
  const traceId = extractTraceId(response.headers);
1793
- this.doh.cacheDirectIfNeeded();
1798
+ this.pilot.cacheDirectIfNeeded();
1794
1799
  return this.processResponse(rawText, response, elapsed, traceId, reqConfig, requestPath);
1795
1800
  }
1796
1801
  };
@@ -2218,6 +2223,7 @@ var MODULES = [
2218
2223
  "account",
2219
2224
  "event",
2220
2225
  "news",
2226
+ "smartmoney",
2221
2227
  ...EARN_SUB_MODULE_IDS,
2222
2228
  ...BOT_SUB_MODULE_IDS,
2223
2229
  "skills"
@@ -2240,12 +2246,13 @@ var MODULE_DESCRIPTIONS = {
2240
2246
  "bot.grid": "Grid trading bot \u2014 create, monitor, and stop grid orders",
2241
2247
  "bot.dca": "DCA (Martingale) bot \u2014 spot or contract recurring buys",
2242
2248
  news: "Crypto news, sentiment analysis, and coin trend tracking",
2249
+ smartmoney: "Smart money signals \u2014 trader leaderboard, consensus signals, and position analysis",
2243
2250
  skills: SKILLS_MARKETPLACE_DESC,
2244
2251
  earn: "Earn products \u2014 Simple Earn, On-chain Earn, DCD, Flash Earn, and Auto-Earn",
2245
2252
  bot: "Trading bot strategies (grid, dca)",
2246
2253
  config: "Manage CLI configuration profiles",
2247
2254
  setup: "Set up client integrations (Cursor, Windsurf, Claude, etc.)",
2248
- doh: "Manage DoH (DNS-over-HTTPS) resolver binary",
2255
+ pilot: "Manage Pilot proxy resolver binary",
2249
2256
  diagnose: "Run network / MCP server diagnostics",
2250
2257
  upgrade: "Upgrade okx CLI and MCP server to the latest stable version",
2251
2258
  skill: SKILLS_MARKETPLACE_DESC
@@ -2395,6 +2402,10 @@ function registerAccountTools() {
2395
2402
  showValuation: {
2396
2403
  type: "boolean",
2397
2404
  description: "Include total asset valuation breakdown by account type (trading/funding/earn). Default false."
2405
+ },
2406
+ valuationCcy: {
2407
+ type: "string",
2408
+ description: "Currency used to denominate the total asset valuation (e.g. USDT, BTC). Default USDT. Only applies when showValuation=true."
2398
2409
  }
2399
2410
  }
2400
2411
  },
@@ -2402,6 +2413,7 @@ function registerAccountTools() {
2402
2413
  const args = asRecord(rawArgs);
2403
2414
  const ccy = readString(args, "ccy");
2404
2415
  const showValuation = readBoolean(args, "showValuation");
2416
+ const valuationCcy = readString(args, "valuationCcy") ?? "USDT";
2405
2417
  if (showValuation) {
2406
2418
  const balanceResp2 = await context.client.privateGet(
2407
2419
  "/api/v5/asset/balances",
@@ -2409,16 +2421,26 @@ function registerAccountTools() {
2409
2421
  privateRateLimit("account_get_asset_balance", 6)
2410
2422
  );
2411
2423
  let valuationData = null;
2424
+ let valuationError;
2412
2425
  try {
2413
2426
  const valuationResp = await context.client.privateGet(
2414
2427
  "/api/v5/asset/asset-valuation",
2415
- {},
2428
+ { ccy: valuationCcy },
2416
2429
  privateRateLimit("account_get_asset_valuation", 1)
2417
2430
  );
2418
2431
  valuationData = valuationResp.data;
2419
- } catch {
2432
+ } catch (err) {
2433
+ valuationError = err instanceof Error ? err.message : String(err);
2434
+ }
2435
+ const valuationResult = {
2436
+ ...normalizeResponse(balanceResp2),
2437
+ valuation: valuationData,
2438
+ valuationCcy
2439
+ };
2440
+ if (valuationError !== void 0) {
2441
+ valuationResult["valuationError"] = valuationError;
2420
2442
  }
2421
- return { ...normalizeResponse(balanceResp2), valuation: valuationData };
2443
+ return valuationResult;
2422
2444
  }
2423
2445
  const balanceResp = await context.client.privateGet(
2424
2446
  "/api/v5/asset/balances",
@@ -4246,10 +4268,133 @@ function registerGridTools() {
4246
4268
  return normalizeWrite(response);
4247
4269
  }
4248
4270
  },
4271
+ {
4272
+ name: "grid_amend_order",
4273
+ module: "bot.grid",
4274
+ description: "Amend a running grid bot. [CAUTION] Modifies a running bot. Use grid_list_orders to confirm the bot is running and obtain the algoId before calling.\nSupports two modes, which can be combined in a single call:\n\u2022 Price-range mode (maxPx+minPx+gridNum): change upper/lower price boundary and grid count. Contract grid: if new range requires more margin, pass topUpAmt; omit to auto-use the minimum required. Spot grid: topUpAmt is not supported.\n\u2022 TP/SL mode (instId + any of tpTriggerPx/slTriggerPx/tpRatio/slRatio): update take-profit and/or stop-loss. Pass '-1' to explicitly clear an existing TP or SL. tpTriggerPx/slTriggerPx are absolute prices; tpRatio/slRatio are profit ratios (e.g. '0.1' = 10%).\nWhen both sets of params are provided, both APIs are called sequentially.\nDo NOT use to create a new grid bot \u2014 use grid_create_order instead. Do NOT use to stop a grid bot \u2014 use grid_stop_order instead.",
4275
+ isWrite: true,
4276
+ inputSchema: {
4277
+ type: "object",
4278
+ properties: {
4279
+ algoId: {
4280
+ type: "string",
4281
+ description: "Grid bot algo order ID (required)"
4282
+ },
4283
+ // ── Price-range mode ──────────────────────────────────────────────
4284
+ maxPx: {
4285
+ type: "string",
4286
+ description: "[Price-range mode] New upper price boundary. Triggers amend-algo-basic-param when provided."
4287
+ },
4288
+ minPx: {
4289
+ type: "string",
4290
+ description: "[Price-range mode] New lower price boundary. Required when maxPx is set."
4291
+ },
4292
+ gridNum: {
4293
+ type: "string",
4294
+ description: "[Price-range mode] New number of grid intervals (integer). Required when maxPx is set."
4295
+ },
4296
+ // ── TP/SL mode ────────────────────────────────────────────────────
4297
+ instId: {
4298
+ type: "string",
4299
+ description: "[TP/SL mode] Instrument ID, e.g. BTC-USDT. Required when setting TP/SL."
4300
+ },
4301
+ tpTriggerPx: {
4302
+ type: "string",
4303
+ description: "[TP/SL mode] Take-profit trigger price (absolute). Pass '-1' to clear."
4304
+ },
4305
+ slTriggerPx: {
4306
+ type: "string",
4307
+ description: "[TP/SL mode] Stop-loss trigger price (absolute). Pass '-1' to clear."
4308
+ },
4309
+ tpRatio: {
4310
+ type: "string",
4311
+ description: "[TP/SL mode] Take-profit ratio, e.g. '0.1' = 10% profit. Pass '-1' to clear."
4312
+ },
4313
+ slRatio: {
4314
+ type: "string",
4315
+ description: "[TP/SL mode] Stop-loss ratio, e.g. '0.1' = 10% drawdown. Pass '-1' to clear."
4316
+ },
4317
+ // ── Shared optional ───────────────────────────────────────────────
4318
+ topUpAmt: {
4319
+ type: "string",
4320
+ description: "Top-up amount. In price-range mode maps to topupAmount (contract grid only; omit to use minimum required). In TP/SL mode maps to topUpAmt."
4321
+ }
4322
+ },
4323
+ required: ["algoId"]
4324
+ },
4325
+ handler: async (rawArgs, context) => {
4326
+ const args = asRecord(rawArgs);
4327
+ const algoId = requireString(args, "algoId");
4328
+ const maxPx = readString(args, "maxPx");
4329
+ const instId = readString(args, "instId");
4330
+ const hasTpsl = readString(args, "tpTriggerPx") || readString(args, "slTriggerPx") || readString(args, "tpRatio") || readString(args, "slRatio");
4331
+ if (!maxPx && !hasTpsl) {
4332
+ throw new OkxApiError(
4333
+ "Nothing to amend. Provide maxPx+minPx+gridNum for price-range mode, or any of tpTriggerPx/slTriggerPx/tpRatio/slRatio (instId also required) for TP/SL mode (both can be combined).",
4334
+ { code: "", endpoint: "grid_amend_order" }
4335
+ );
4336
+ }
4337
+ if (hasTpsl && !instId) {
4338
+ throw new OkxApiError(
4339
+ "TP/SL mode requires instId. Provide instId alongside the TP/SL parameters.",
4340
+ { code: "", endpoint: "grid_amend_order" }
4341
+ );
4342
+ }
4343
+ const results = [];
4344
+ if (maxPx) {
4345
+ results.push(normalizeWrite(await context.client.privatePost(
4346
+ "/api/v5/tradingBot/grid/amend-algo-basic-param",
4347
+ compactObject({
4348
+ algoId,
4349
+ maxPx,
4350
+ minPx: requireString(args, "minPx"),
4351
+ gridNum: requireString(args, "gridNum"),
4352
+ // API field is "topupAmount" (lowercase u) — different from TP/SL mode's "topUpAmt"
4353
+ // Contract grid only; omitting lets the API use the minimum required
4354
+ topupAmount: readString(args, "topUpAmt")
4355
+ }),
4356
+ privateRateLimit("grid_amend_order", 20),
4357
+ true
4358
+ // retryOnNetworkError: amend sets fixed values, safe to retry
4359
+ )));
4360
+ }
4361
+ if (hasTpsl) {
4362
+ try {
4363
+ results.push(normalizeWrite(await context.client.privatePost(
4364
+ "/api/v5/tradingBot/grid/amend-order-algo",
4365
+ compactObject({
4366
+ algoId,
4367
+ instId,
4368
+ tpTriggerPx: readString(args, "tpTriggerPx"),
4369
+ slTriggerPx: readString(args, "slTriggerPx"),
4370
+ tpRatio: readString(args, "tpRatio"),
4371
+ slRatio: readString(args, "slRatio"),
4372
+ topUpAmt: readString(args, "topUpAmt")
4373
+ // API field is "topUpAmt" (uppercase U) — different from price-range mode's "topupAmount"
4374
+ }),
4375
+ privateRateLimit("grid_amend_order", 20),
4376
+ true
4377
+ // retryOnNetworkError: amend sets fixed values, safe to retry
4378
+ )));
4379
+ } catch (err) {
4380
+ if (results.length > 0) {
4381
+ const msg = err instanceof Error ? err.message : String(err);
4382
+ throw new OkxApiError(
4383
+ `TP/SL amend failed (price-range amend already succeeded): ${msg}`,
4384
+ { code: "", endpoint: "grid_amend_order" }
4385
+ );
4386
+ }
4387
+ throw err;
4388
+ }
4389
+ }
4390
+ const merged = results.flatMap((r) => Array.isArray(r.data) ? r.data : [r.data]);
4391
+ return { endpoint: results[0].endpoint, requestTime: results[0].requestTime, data: merged };
4392
+ }
4393
+ },
4249
4394
  {
4250
4395
  name: "grid_stop_order",
4251
4396
  module: "bot.grid",
4252
- description: "Stop a grid bot. [CAUTION] Closes or cancels orders. For contract: stopType controls close ('1') vs cancel-only ('2').",
4397
+ description: "Stop a running grid bot. [CAUTION] This stops the strategy and handles open orders/positions according to stopType. Default (stopType='1') closes all positions immediately \u2014 use this for a clean exit. stopType='2' stops the strategy without selling: spot grid keeps all base assets as-is (no sell-back to quote); contract grid cancels all grid orders but leaves the position open for manual close later.",
4253
4398
  isWrite: true,
4254
4399
  inputSchema: {
4255
4400
  type: "object",
@@ -4258,13 +4403,13 @@ function registerGridTools() {
4258
4403
  algoOrdType: {
4259
4404
  type: "string",
4260
4405
  enum: ["grid", "contract_grid"],
4261
- description: "grid=Spot, contract_grid=Contract"
4406
+ description: "grid=Spot grid, contract_grid=Contract grid"
4262
4407
  },
4263
- instId: { type: "string", description: "e.g. BTC-USDT, BTC-USD-SWAP" },
4408
+ instId: { type: "string", description: "Instrument ID, e.g. BTC-USDT, BTC-USDT-SWAP" },
4264
4409
  stopType: {
4265
4410
  type: "string",
4266
- enum: ["1", "2", "3", "5", "6"],
4267
- description: "1=close all (default); 2=keep assets; 3=limit close; 5=partial; 6=no sell"
4411
+ enum: ["1", "2"],
4412
+ description: "'1' (default): stop strategy and sell \u2014 spot grid sells all base assets back to quote; contract grid market-closes all positions. '2': stop strategy without selling \u2014 spot grid keeps base assets as-is; contract grid cancels all grid orders but leaves the position open. After stopType='2', the remaining position can be closed manually from the Positions page."
4268
4413
  }
4269
4414
  },
4270
4415
  required: ["algoId", "algoOrdType", "instId"]
@@ -4279,7 +4424,9 @@ function registerGridTools() {
4279
4424
  instId: requireString(args, "instId"),
4280
4425
  stopType: readString(args, "stopType") ?? "1"
4281
4426
  })],
4282
- privateRateLimit("grid_stop_order", 20)
4427
+ privateRateLimit("grid_stop_order", 20),
4428
+ true
4429
+ // retryOnNetworkError: safe to retry — already-stopped returns an error but does not harm state
4283
4430
  );
4284
4431
  return normalizeWrite(response);
4285
4432
  }
@@ -6426,6 +6573,384 @@ function registerEventContractTools() {
6426
6573
  }
6427
6574
  ];
6428
6575
  }
6576
+ var PATH_LEADERBOARD = "/api/v5/orbit/public/leaderboard";
6577
+ var PATH_POSITION_CURRENT = "/api/v5/orbit/public/position-current";
6578
+ var PATH_TRADE_RECORDS = "/api/v5/orbit/public/trade-records";
6579
+ var PATH_OVERVIEW = "/api/v5/journal/smartmoney/overview";
6580
+ var PATH_SIGNAL = "/api/v5/journal/smartmoney/signal";
6581
+ var PATH_SIGNAL_HISTORY = "/api/v5/journal/smartmoney/signal-history";
6582
+ var SIGNAL_POOL_FILTER_PROPS = {
6583
+ sortType: {
6584
+ type: "string",
6585
+ description: "pnl or pnlRatio"
6586
+ },
6587
+ period: {
6588
+ type: "string",
6589
+ description: "3|7|30|90 days"
6590
+ },
6591
+ pnl: {
6592
+ type: "string",
6593
+ description: "PNL_ANY|PNL_TOP50|PNL_TOP20|PNL_TOP5"
6594
+ },
6595
+ winRatio: {
6596
+ type: "string",
6597
+ description: "WR_ANY|WR_GE_50|WR_GE_80"
6598
+ },
6599
+ maxRetreat: {
6600
+ type: "string",
6601
+ description: "MR_ANY|MR_LE_20|MR_LE_50"
6602
+ },
6603
+ asset: {
6604
+ type: "string",
6605
+ description: "AUM_ANY|AUM_TOP50|AUM_TOP20|AUM_TOP5"
6606
+ }
6607
+ };
6608
+ var LEADERBOARD_POOL_FILTER_PROPS = {
6609
+ sortType: {
6610
+ type: "string",
6611
+ description: "pnl or pnl_ratio"
6612
+ },
6613
+ period: {
6614
+ type: "string",
6615
+ description: "3|7|30|90 days, empty=all"
6616
+ },
6617
+ pnl: {
6618
+ type: "string",
6619
+ description: "Min PnL USD"
6620
+ },
6621
+ winRatio: {
6622
+ type: "string",
6623
+ description: "Min ratio (0.8=80%)"
6624
+ },
6625
+ maxRetreat: {
6626
+ type: "string",
6627
+ description: "Max DD (0.1=10%)"
6628
+ },
6629
+ asset: {
6630
+ type: "string",
6631
+ description: "Min AUM USD"
6632
+ }
6633
+ };
6634
+ var POOL_FILTER_KEYS = ["sortType", "period", "pnl", "winRatio", "maxRetreat", "asset"];
6635
+ function readPoolFilters(args) {
6636
+ const result = {};
6637
+ for (const key of POOL_FILTER_KEYS) {
6638
+ const val = readString(args, key);
6639
+ if (val) result[key] = val;
6640
+ }
6641
+ return result;
6642
+ }
6643
+ function extractLeaderboardData(data) {
6644
+ if (Array.isArray(data)) return data;
6645
+ if (data && typeof data === "object") {
6646
+ const inner = data.data;
6647
+ if (Array.isArray(inner)) return inner;
6648
+ }
6649
+ return [];
6650
+ }
6651
+ function registerSmartmoneyTools() {
6652
+ const tools = [
6653
+ /* ---------- 1. Overview ---------- */
6654
+ {
6655
+ name: "smartmoney_get_overview",
6656
+ module: "smartmoney",
6657
+ description: "Multi-currency smart money overview ranked by most-watched currencies. Pass ts=Date.now() for latest data, or dataVersion (yyyyMMddHHmm) from a prior call. For single-currency signal with entry prices and trend, use smartmoney_get_signal.",
6658
+ isWrite: false,
6659
+ inputSchema: {
6660
+ type: "object",
6661
+ properties: {
6662
+ dataVersion: {
6663
+ type: "string",
6664
+ description: "yyyyMMddHHmm UTC (or use ts)"
6665
+ },
6666
+ ts: {
6667
+ type: "string",
6668
+ description: "Timestamp ms (or use dataVersion)"
6669
+ },
6670
+ instType: {
6671
+ type: "string",
6672
+ description: "SPOT|MARGIN|FUTURES|SWAP|OPTION"
6673
+ },
6674
+ ...SIGNAL_POOL_FILTER_PROPS,
6675
+ lmtNum: {
6676
+ type: "string",
6677
+ description: "Trader pool size 1-500"
6678
+ },
6679
+ instCcyList: {
6680
+ type: "string",
6681
+ description: "Comma-separated e.g. BTC,ETH,SOL"
6682
+ },
6683
+ instCcy: {
6684
+ type: "string",
6685
+ description: "Single currency e.g. BTC"
6686
+ },
6687
+ topInstruments: {
6688
+ type: "string",
6689
+ description: "Top N instruments 1-100"
6690
+ }
6691
+ }
6692
+ },
6693
+ handler: async (rawArgs, context) => {
6694
+ const args = asRecord(rawArgs);
6695
+ const dv = readString(args, "dataVersion");
6696
+ const ts = readString(args, "ts");
6697
+ if (!dv && !ts) {
6698
+ throw new ValidationError('Either "dataVersion" or "ts" is required for smartmoney_get_overview.');
6699
+ }
6700
+ const response = await context.client.privateGet(
6701
+ PATH_OVERVIEW,
6702
+ compactObject({
6703
+ dataVersion: dv,
6704
+ ts,
6705
+ instType: readString(args, "instType"),
6706
+ ...readPoolFilters(args),
6707
+ lmtNum: readString(args, "lmtNum"),
6708
+ instCcyList: readString(args, "instCcyList"),
6709
+ instCcy: readString(args, "instCcy"),
6710
+ topInstruments: readString(args, "topInstruments")
6711
+ }),
6712
+ publicRateLimit("smartmoney_get_overview", 5)
6713
+ );
6714
+ return normalizeResponse(response);
6715
+ }
6716
+ },
6717
+ /* ---------- 2. Signal ---------- */
6718
+ {
6719
+ name: "smartmoney_get_signal",
6720
+ module: "smartmoney",
6721
+ description: "Single-currency consensus signal: long/short ratio, entry prices, trend, capital flow. Prefer instId (e.g. BTC-USDT-SWAP); instCcy is accepted but may return empty \u2014 use instId for reliable results. Pass ts=Date.now() for latest data, or dataVersion from a prior call. For multi-currency overview, use smartmoney_get_overview. For timeline, use smartmoney_get_signal_history.",
6722
+ isWrite: false,
6723
+ inputSchema: {
6724
+ type: "object",
6725
+ properties: {
6726
+ instId: {
6727
+ type: "string",
6728
+ description: "Recommended. e.g. BTC-USDT-SWAP"
6729
+ },
6730
+ instCcy: {
6731
+ type: "string",
6732
+ description: "e.g. BTC, SPOT/SWAP only. May return empty \u2014 prefer instId."
6733
+ },
6734
+ dataVersion: {
6735
+ type: "string",
6736
+ description: "yyyyMMddHHmm UTC (or use ts)"
6737
+ },
6738
+ ts: {
6739
+ type: "string",
6740
+ description: "Timestamp ms (or use dataVersion)"
6741
+ },
6742
+ ...SIGNAL_POOL_FILTER_PROPS,
6743
+ lmtNum: {
6744
+ type: "string",
6745
+ description: "Trader pool size 1-500"
6746
+ },
6747
+ authorIds: {
6748
+ type: "string",
6749
+ description: "Comma-separated user IDs e.g. 1001,1002"
6750
+ }
6751
+ }
6752
+ },
6753
+ handler: async (rawArgs, context) => {
6754
+ const args = asRecord(rawArgs);
6755
+ const instId = readString(args, "instId");
6756
+ const instCcy = readString(args, "instCcy");
6757
+ if (!instId && !instCcy) {
6758
+ throw new ValidationError('Either "instId" or "instCcy" is required for smartmoney_get_signal.');
6759
+ }
6760
+ const dv = readString(args, "dataVersion");
6761
+ const ts = readString(args, "ts");
6762
+ if (!dv && !ts) {
6763
+ throw new ValidationError('Either "dataVersion" or "ts" is required for smartmoney_get_signal.');
6764
+ }
6765
+ const response = await context.client.privateGet(
6766
+ PATH_SIGNAL,
6767
+ compactObject({
6768
+ instId,
6769
+ instCcy,
6770
+ dataVersion: dv,
6771
+ ts,
6772
+ ...readPoolFilters(args),
6773
+ lmtNum: readString(args, "lmtNum"),
6774
+ authorIds: readString(args, "authorIds")
6775
+ }),
6776
+ publicRateLimit("smartmoney_get_signal", 5)
6777
+ );
6778
+ return normalizeResponse(response);
6779
+ }
6780
+ },
6781
+ /* ---------- 3. Signal History ---------- */
6782
+ {
6783
+ name: "smartmoney_get_signal_history",
6784
+ module: "smartmoney",
6785
+ description: "Signal history timeline sorted by ts DESC for trend analysis. Requires instId. Pass ts=Date.now() for latest data, or dataVersion from a prior call. For current snapshot, use smartmoney_get_signal.",
6786
+ isWrite: false,
6787
+ inputSchema: {
6788
+ type: "object",
6789
+ properties: {
6790
+ instId: {
6791
+ type: "string",
6792
+ description: "e.g. BTC-USDT-SWAP"
6793
+ },
6794
+ dataVersion: {
6795
+ type: "string",
6796
+ description: "yyyyMMddHHmm UTC (or use ts)"
6797
+ },
6798
+ ts: {
6799
+ type: "string",
6800
+ description: "Timestamp ms (or use dataVersion)"
6801
+ },
6802
+ granularity: {
6803
+ type: "string",
6804
+ description: "1h or 1d (default 1h)"
6805
+ },
6806
+ limit: {
6807
+ type: "string",
6808
+ description: "Data points 1-500 (default 24)"
6809
+ },
6810
+ ...SIGNAL_POOL_FILTER_PROPS
6811
+ },
6812
+ required: ["instId"]
6813
+ },
6814
+ handler: async (rawArgs, context) => {
6815
+ const args = asRecord(rawArgs);
6816
+ const dv = readString(args, "dataVersion");
6817
+ const ts = readString(args, "ts");
6818
+ if (!dv && !ts) {
6819
+ throw new ValidationError('Either "dataVersion" or "ts" is required for smartmoney_get_signal_history.');
6820
+ }
6821
+ const response = await context.client.privateGet(
6822
+ PATH_SIGNAL_HISTORY,
6823
+ compactObject({
6824
+ instId: requireString(args, "instId"),
6825
+ dataVersion: dv,
6826
+ ts,
6827
+ granularity: readString(args, "granularity"),
6828
+ limit: readString(args, "limit"),
6829
+ ...readPoolFilters(args)
6830
+ }),
6831
+ publicRateLimit("smartmoney_get_signal_history", 5)
6832
+ );
6833
+ return normalizeResponse(response);
6834
+ }
6835
+ },
6836
+ /* ---------- 4. Traders (list) ---------- */
6837
+ {
6838
+ name: "smartmoney_get_traders",
6839
+ module: "smartmoney",
6840
+ description: "List/filter leaderboard traders. For single trader detail: smartmoney_get_trader_detail.",
6841
+ isWrite: false,
6842
+ inputSchema: {
6843
+ type: "object",
6844
+ properties: {
6845
+ dataVersion: {
6846
+ type: "string",
6847
+ description: "yyyyMMddHHmm, omit=latest"
6848
+ },
6849
+ ...LEADERBOARD_POOL_FILTER_PROPS,
6850
+ authorIds: {
6851
+ type: "string",
6852
+ description: "Comma-separated author IDs"
6853
+ },
6854
+ after: {
6855
+ type: "string",
6856
+ description: "Cursor after this authorId"
6857
+ },
6858
+ before: {
6859
+ type: "string",
6860
+ description: "Cursor before this authorId"
6861
+ },
6862
+ limit: {
6863
+ type: "string",
6864
+ description: "Max results 1-100"
6865
+ }
6866
+ }
6867
+ },
6868
+ handler: async (rawArgs, context) => {
6869
+ const args = asRecord(rawArgs);
6870
+ const response = await context.client.privateGet(
6871
+ PATH_LEADERBOARD,
6872
+ compactObject({
6873
+ dataVersion: readString(args, "dataVersion"),
6874
+ ...readPoolFilters(args),
6875
+ authorIds: readString(args, "authorIds"),
6876
+ after: readString(args, "after"),
6877
+ before: readString(args, "before"),
6878
+ limit: readString(args, "limit")
6879
+ }),
6880
+ publicRateLimit("smartmoney_get_traders", 5)
6881
+ );
6882
+ const normalized = normalizeResponse(response);
6883
+ return { ...normalized, data: extractLeaderboardData(normalized.data) };
6884
+ }
6885
+ },
6886
+ /* ---------- 5. Trader Detail (composite) ---------- */
6887
+ {
6888
+ name: "smartmoney_get_trader_detail",
6889
+ module: "smartmoney",
6890
+ description: "Trader portrait: profile + positions + trades. Requires authorId from smartmoney_get_traders. Do NOT use for listing \u2014 use smartmoney_get_traders.",
6891
+ isWrite: false,
6892
+ inputSchema: {
6893
+ type: "object",
6894
+ properties: {
6895
+ authorId: {
6896
+ type: "string",
6897
+ description: "Trader author ID"
6898
+ },
6899
+ period: {
6900
+ type: "string",
6901
+ description: "3|7|30|90 days, omit=all"
6902
+ },
6903
+ instCcy: {
6904
+ type: "string",
6905
+ description: "Currency filter e.g. BTC"
6906
+ },
6907
+ tradeLimit: {
6908
+ type: "string",
6909
+ description: "Max trades 1-100"
6910
+ }
6911
+ },
6912
+ required: ["authorId"]
6913
+ },
6914
+ handler: async (rawArgs, context) => {
6915
+ const args = asRecord(rawArgs);
6916
+ const authorId = requireString(args, "authorId");
6917
+ const period = readString(args, "period");
6918
+ const instCcy = readString(args, "instCcy");
6919
+ const tradeLimit = readString(args, "tradeLimit");
6920
+ const [profileRes, positionsRes, tradesRes] = await Promise.all([
6921
+ context.client.privateGet(
6922
+ PATH_LEADERBOARD,
6923
+ compactObject({ authorIds: authorId, period }),
6924
+ publicRateLimit("smartmoney_get_traders", 5)
6925
+ ),
6926
+ context.client.privateGet(
6927
+ PATH_POSITION_CURRENT,
6928
+ compactObject({ authorId, instCcy }),
6929
+ publicRateLimit("smartmoney_trader_positions", 5)
6930
+ ),
6931
+ context.client.privateGet(
6932
+ PATH_TRADE_RECORDS,
6933
+ compactObject({ authorId, instCcy, limit: tradeLimit }),
6934
+ publicRateLimit("smartmoney_trade_records", 5)
6935
+ )
6936
+ ]);
6937
+ const profileNorm = normalizeResponse(profileRes);
6938
+ const positionsNorm = normalizeResponse(positionsRes);
6939
+ const tradesNorm = normalizeResponse(tradesRes);
6940
+ return {
6941
+ endpoint: "smartmoney_get_trader_detail (composite)",
6942
+ requestTime: (/* @__PURE__ */ new Date()).toISOString(),
6943
+ data: {
6944
+ profile: extractLeaderboardData(profileNorm.data),
6945
+ positions: positionsNorm.data,
6946
+ trades: tradesNorm.data
6947
+ }
6948
+ };
6949
+ }
6950
+ }
6951
+ ];
6952
+ return tools;
6953
+ }
6429
6954
  function buildContractTradeTools(cfg) {
6430
6955
  const { prefix, module, label, instTypes, instIdExample } = cfg;
6431
6956
  const [defaultType, otherType] = instTypes;
@@ -6767,31 +7292,58 @@ function buildContractTradeTools(cfg) {
6767
7292
  {
6768
7293
  name: n("set_leverage"),
6769
7294
  module,
6770
- description: `Set leverage for a ${label} instrument or position. [CAUTION] Changes risk parameters.`,
7295
+ description: `Set leverage for a ${label} instrument or position. [CAUTION] Changes risk parameters.
7296
+ Scenarios (SWAP/FUTURES only):
7297
+ \u2022 cross + any instId under the index \u2192 sets leverage at the index level
7298
+ \u2022 isolated + buy-sell (net) posMode \u2192 instId only
7299
+ \u2022 isolated + long-short (hedge) posMode \u2192 instId + posSide=long|short (BOTH directions must be set separately)
7300
+ Not supported: PORTFOLIO MARGIN accounts cannot adjust cross leverage for SWAP/FUTURES \u2014 the request will be rejected by OKX. Use account_get_config first if unsure of the account's margin mode.`,
6771
7301
  isWrite: true,
6772
7302
  inputSchema: {
6773
7303
  type: "object",
6774
7304
  properties: {
6775
7305
  instId: { type: "string", description: instIdExample },
6776
- lever: { type: "string", description: "Leverage, e.g. '10'" },
7306
+ lever: {
7307
+ type: "string",
7308
+ description: "Leverage multiplier as a positive number string, e.g. '10'. Max value depends on the instrument (query market_get_instruments \u2192 lever)."
7309
+ },
6777
7310
  mgnMode: { type: "string", enum: ["cross", "isolated"] },
6778
7311
  posSide: {
6779
7312
  type: "string",
6780
- enum: ["long", "short", "net"],
6781
- description: "Required for isolated margin in hedge mode"
7313
+ enum: ["long", "short"],
7314
+ description: "REQUIRED when mgnMode=isolated AND the account is in hedge (long/short) position mode. Use 'long' or 'short' \u2014 setting one side does NOT auto-apply to the other. Omit entirely for one-way (net) position mode or for cross margin."
6782
7315
  }
6783
7316
  },
6784
7317
  required: ["instId", "lever", "mgnMode"]
6785
7318
  },
6786
7319
  handler: async (rawArgs, context) => {
6787
7320
  const args = asRecord(rawArgs);
7321
+ const instId = requireString(args, "instId");
7322
+ const leverRaw = requireString(args, "lever");
7323
+ const leverNum = Number(leverRaw);
7324
+ if (!Number.isFinite(leverNum) || leverNum <= 0) {
7325
+ throw new ValidationError(
7326
+ `Parameter "lever" must be a positive number string, got "${leverRaw}".`
7327
+ );
7328
+ }
7329
+ const mgnMode = requireString(args, "mgnMode");
7330
+ assertEnum(mgnMode, "mgnMode", ["cross", "isolated"]);
7331
+ const posSide = readString(args, "posSide");
7332
+ if (posSide !== void 0) {
7333
+ assertEnum(posSide, "posSide", ["long", "short"]);
7334
+ if (mgnMode === "cross") {
7335
+ throw new ValidationError(
7336
+ `posSide="${posSide}" is only valid with mgnMode="isolated" in hedge mode. Omit posSide for cross margin.`
7337
+ );
7338
+ }
7339
+ }
6788
7340
  const response = await context.client.privatePost(
6789
7341
  "/api/v5/account/set-leverage",
6790
7342
  compactObject({
6791
- instId: requireString(args, "instId"),
6792
- lever: requireString(args, "lever"),
6793
- mgnMode: requireString(args, "mgnMode"),
6794
- posSide: readString(args, "posSide")
7343
+ instId,
7344
+ lever: leverRaw,
7345
+ mgnMode,
7346
+ posSide
6795
7347
  }),
6796
7348
  privateRateLimit(n("set_leverage"), 20)
6797
7349
  );
@@ -7664,7 +8216,7 @@ function registerMarketFilterTools() {
7664
8216
  sortBy: {
7665
8217
  type: "string",
7666
8218
  enum: ["last", "chg24hPct", "marketCapUsd", "volUsd24h", "fundingRate", "oiUsd", "listTime"],
7667
- description: "Sort field. Default: volUsd24h. Note: marketCapUsd is only meaningful for SPOT (null for SWAP/FUTURES)."
8219
+ description: "Sort field. Default: volUsd24h. Note: marketCapUsd is only meaningful for SPOT (null for SWAP/FUTURES). To rank by OI *change* (oiDeltaPct / absOiDeltaPct), use market_filter_oi_change \u2014 market_filter only sorts by the current snapshot."
7668
8220
  },
7669
8221
  sortOrder: {
7670
8222
  type: "string",
@@ -7777,7 +8329,7 @@ function registerMarketFilterTools() {
7777
8329
  bar: {
7778
8330
  type: "string",
7779
8331
  enum: [...OI_BARS],
7780
- description: "Bar window for OI change computation: 5m, 15m, 1H, 4H, 1D. Default: 1H"
8332
+ description: "Bar window for OI change computation: 5m, 15m, 1H, 4H, 1D (case-insensitive on server, but send canonical form here). Default: 1H"
7781
8333
  },
7782
8334
  // Filters
7783
8335
  minOiUsd: {
@@ -7795,8 +8347,8 @@ function registerMarketFilterTools() {
7795
8347
  // Sort / pagination
7796
8348
  sortBy: {
7797
8349
  type: "string",
7798
- enum: ["oiUsd", "oiDeltaUsd", "oiDeltaPct", "volUsd24h", "last"],
7799
- description: "Sort field. Default: oiDeltaPct (largest movers first)"
8350
+ enum: ["oiUsd", "oiDeltaUsd", "oiDeltaPct", "absOiDeltaPct", "volUsd24h", "fundingRate", "last"],
8351
+ description: "Sort field. Default: oiDeltaPct (largest movers first, signed \u2014 longs and shorts separate). Use absOiDeltaPct to sort by |oiDeltaPct| (largest-magnitude moves regardless of direction). fundingRate is also supported for SWAP. Do NOT use the market_filter tool's sort fields (chg24hPct, marketCapUsd, listTime) here \u2014 they are not in the OI-change Row."
7800
8352
  },
7801
8353
  sortOrder: {
7802
8354
  type: "string",
@@ -7852,7 +8404,7 @@ var D_COINS_SENTIMENT = 'Comma-separated uppercase ticker symbols, max 20 (e.g.
7852
8404
  var D_LANGUAGE = "Content language: zh-CN or en-US. Infer from user's message. No server default.";
7853
8405
  var D_BEGIN = "Start time, Unix epoch milliseconds. API defaults to 72 hours ago when omitted. Pass explicitly for older topics (e.g. 'last 30 days'). Max range: 180 days. Parse relative time if given.";
7854
8406
  var D_END = "End time, Unix epoch milliseconds. Parse relative time if given. Omit for no upper bound.";
7855
- var D_IMPORTANCE = "Importance filter: high (server default) or low. Omit unless user wants broader coverage.";
8407
+ var D_IMPORTANCE = "Importance filter: 'low' returns all news (both low and high importance); 'high' narrows to major/breaking news only. Omitted \u2192 server default (high-only). Default to 'low' for broad browsing; pass 'high' only when the user explicitly asks for major news.";
7856
8408
  var D_PLATFORM = "Filter by news source. Use values from news_get_domains (e.g. blockbeats, odaily_flash). Omit for all sources.";
7857
8409
  var D_LIMIT = "Number of results (default 10, max 50).";
7858
8410
  function registerNewsTools() {
@@ -7863,7 +8415,7 @@ function registerNewsTools() {
7863
8415
  {
7864
8416
  name: "news_get_latest",
7865
8417
  module: "news",
7866
- description: "Get crypto news sorted by time. Omitting importance still returns only high-importance news (server default). Pass importance='low' explicitly to broaden results. Use when user asks 'what happened recently', 'latest news', 'any big news today', or wants to browse without a keyword. For coin-specific news, use news_get_by_coin instead.",
8418
+ description: "Get crypto news sorted by time. For broad browsing ('what happened recently', 'latest news', 'any big news today'), pass importance='low' to include both high and low importance. Server default (when importance omitted) returns only high-importance news. For coin-specific news, use news_get_by_coin instead.",
7867
8419
  isWrite: false,
7868
8420
  inputSchema: {
7869
8421
  type: "object",
@@ -9524,6 +10076,82 @@ function registerSpotTradeTools() {
9524
10076
  );
9525
10077
  return normalizeResponse(response);
9526
10078
  }
10079
+ },
10080
+ // ── set_leverage (SPOT margin: instId-level isolated OR ccy-level cross) ──
10081
+ // Covers OKX scenarios 1–5 (everything except SWAP/FUTURES, which are in
10082
+ // contract-trade.ts). Callers supply exactly one of {instId, ccy}:
10083
+ // • instId + isolated → scenario 1 (pair-level margin)
10084
+ // • instId + cross → scenario 3 (contract-mode pair-level cross margin)
10085
+ // • ccy + cross → scenarios 2 / 4 / 5 (spot/multi-ccy/PM currency-level cross)
10086
+ // Not applicable: posSide (spot has no long/short hedge).
10087
+ {
10088
+ name: "spot_set_leverage",
10089
+ module: "spot",
10090
+ description: "Set leverage for SPOT margin trading. Provide exactly ONE of instId (pair-level) or ccy (currency-level cross, requires borrow-enabled account / multi-ccy / portfolio margin). [CAUTION] Changes risk parameters.\nScenarios:\n \u2022 instId + mgnMode=isolated \u2192 pair-level isolated margin\n \u2022 instId + mgnMode=cross \u2192 pair-level cross margin (contract-mode account)\n \u2022 ccy + mgnMode=cross \u2192 currency-level cross margin (spot-with-borrow / multi-ccy / portfolio margin)\nWhen ccy is supplied, mgnMode MUST be cross. posSide is never applicable to spot margin.",
10091
+ isWrite: true,
10092
+ inputSchema: {
10093
+ type: "object",
10094
+ properties: {
10095
+ instId: {
10096
+ type: "string",
10097
+ description: "Spot pair, e.g. BTC-USDT. Provide instId OR ccy, not both."
10098
+ },
10099
+ ccy: {
10100
+ type: "string",
10101
+ description: "Margin currency, e.g. BTC. Required only for currency-level cross margin (borrow-enabled / multi-ccy / portfolio margin). Mutually exclusive with instId."
10102
+ },
10103
+ lever: {
10104
+ type: "string",
10105
+ description: "Leverage multiplier as a positive number string, e.g. '3'. Max depends on the pair (query market_get_instruments \u2192 lever) or the account policy for ccy-level."
10106
+ },
10107
+ mgnMode: {
10108
+ type: "string",
10109
+ enum: ["cross", "isolated"],
10110
+ description: "cross or isolated. Must be cross when ccy is supplied."
10111
+ }
10112
+ },
10113
+ required: ["lever", "mgnMode"]
10114
+ },
10115
+ handler: async (rawArgs, context) => {
10116
+ const args = asRecord(rawArgs);
10117
+ const instId = readString(args, "instId");
10118
+ const ccy = readString(args, "ccy");
10119
+ if (!instId && !ccy) {
10120
+ throw new ValidationError(
10121
+ `Missing required parameter: provide either "instId" (pair-level) or "ccy" (currency-level cross margin).`
10122
+ );
10123
+ }
10124
+ if (instId && ccy) {
10125
+ throw new ValidationError(
10126
+ `Parameters "instId" and "ccy" are mutually exclusive \u2014 provide only one. instId sets pair-level leverage; ccy sets currency-level cross margin leverage.`
10127
+ );
10128
+ }
10129
+ const leverRaw = requireString(args, "lever");
10130
+ const leverNum = Number(leverRaw);
10131
+ if (!Number.isFinite(leverNum) || leverNum <= 0) {
10132
+ throw new ValidationError(
10133
+ `Parameter "lever" must be a positive number string, got "${leverRaw}".`
10134
+ );
10135
+ }
10136
+ const mgnMode = requireString(args, "mgnMode");
10137
+ assertEnum(mgnMode, "mgnMode", ["cross", "isolated"]);
10138
+ if (ccy && mgnMode !== "cross") {
10139
+ throw new ValidationError(
10140
+ `When "ccy" is supplied, "mgnMode" must be "cross" (currency-level leverage only applies to cross margin).`
10141
+ );
10142
+ }
10143
+ const response = await context.client.privatePost(
10144
+ "/api/v5/account/set-leverage",
10145
+ compactObject({
10146
+ instId,
10147
+ ccy,
10148
+ lever: leverRaw,
10149
+ mgnMode
10150
+ }),
10151
+ privateRateLimit("spot_set_leverage", 20)
10152
+ );
10153
+ return normalizeResponse(response);
10154
+ }
9527
10155
  }
9528
10156
  ];
9529
10157
  }
@@ -9655,6 +10283,7 @@ function allToolSpecs() {
9655
10283
  ...registerNewsTools(),
9656
10284
  ...registerBotTools(),
9657
10285
  ...registerAllEarnTools(),
10286
+ ...registerSmartmoneyTools(),
9658
10287
  ...registerAuditTools(),
9659
10288
  ...registerSkillsTools()
9660
10289
  ];
@@ -10118,18 +10747,20 @@ var CDN_SOURCES = [
10118
10747
  { host: "static.okx.com", protocol: "https" },
10119
10748
  { host: "static.coinall.ltd", protocol: "https" }
10120
10749
  ];
10121
- var CDN_PATH_PREFIX = "/upgradeapp/doh";
10750
+ var CDN_PATH_PREFIX = "/upgradeapp/tools/pilot";
10122
10751
  var DOWNLOAD_TIMEOUT_MS = 3e4;
10752
+ var PLATFORM_MAP = {
10753
+ "darwin-arm64": "darwin-arm64",
10754
+ "darwin-x64": "darwin-x64",
10755
+ "linux-arm64": "linux-arm64",
10756
+ "linux-x64": "linux-x64",
10757
+ "win32-arm64": "win32-arm64",
10758
+ "win32-x64": "win32-x64"
10759
+ };
10123
10760
  function getPlatformDir() {
10124
10761
  const p = platform();
10125
10762
  const a = arch();
10126
- const map = {
10127
- "darwin-arm64": "darwin-arm64",
10128
- "darwin-x64": "darwin-x64",
10129
- "linux-x64": "linux-x64",
10130
- "win32-x64": "win32-x64"
10131
- };
10132
- return map[`${p}-${a}`] ?? null;
10763
+ return PLATFORM_MAP[`${p}-${a}`] ?? null;
10133
10764
  }
10134
10765
  function getBinaryName() {
10135
10766
  return platform() === "win32" ? "okx-pilot.exe" : "okx-pilot";
@@ -10141,8 +10772,8 @@ function hashFile(filePath) {
10141
10772
  sha256: createHash("sha256").update(buf).digest("hex")
10142
10773
  };
10143
10774
  }
10144
- function getDohStatus(binaryPath, opts) {
10145
- const resolvedPath = binaryPath ?? getDohBinaryPath();
10775
+ function getPilotStatus(binaryPath, opts) {
10776
+ const resolvedPath = binaryPath ?? getPilotBinaryPath();
10146
10777
  const platformDir = getPlatformDir();
10147
10778
  if (!existsSync6(resolvedPath)) {
10148
10779
  return {
@@ -10234,7 +10865,7 @@ function atomicReplace(tmpPath, resolvedDest) {
10234
10865
  }
10235
10866
  }
10236
10867
  function installPreChecks(destPath, sources) {
10237
- if (!destPath && process.env.OKX_DOH_BINARY_PATH) {
10868
+ if (!destPath && process.env.OKX_PILOT_BINARY_PATH) {
10238
10869
  return { status: "up-to-date", source: "(env override)" };
10239
10870
  }
10240
10871
  if (!getPlatformDir()) {
@@ -10248,7 +10879,7 @@ function installPreChecks(destPath, sources) {
10248
10879
  function isLocalUpToDate(localHash, checksum) {
10249
10880
  return localHash !== null && localHash.size === checksum.size && localHash.sha256 === checksum.sha256;
10250
10881
  }
10251
- async function installDohBinary(destPath, sources = CDN_SOURCES, onProgress) {
10882
+ async function installPilotBinary(destPath, sources = CDN_SOURCES, onProgress) {
10252
10883
  const earlyResult = installPreChecks(destPath, sources);
10253
10884
  if (earlyResult) return earlyResult;
10254
10885
  const platformDir = getPlatformDir();
@@ -10291,8 +10922,8 @@ async function installDohBinary(destPath, sources = CDN_SOURCES, onProgress) {
10291
10922
  return { status: "failed", error: `All CDN sources failed:
10292
10923
  ${errors.join("\n")}` };
10293
10924
  }
10294
- function removeDohBinary(binaryPath) {
10295
- const resolvedPath = binaryPath ?? getDohBinaryPath();
10925
+ function removePilotBinary(binaryPath) {
10926
+ const resolvedPath = binaryPath ?? getPilotBinaryPath();
10296
10927
  try {
10297
10928
  unlinkSync3(resolvedPath);
10298
10929
  return { status: "removed" };
@@ -11015,7 +11646,7 @@ async function cmdDiagnoseMcp(options = {}) {
11015
11646
 
11016
11647
  // src/commands/diagnose.ts
11017
11648
  var CLI_VERSION = readCliVersion();
11018
- var GIT_HASH = true ? "e9764c9" : "dev";
11649
+ var GIT_HASH = true ? "e0ee5a96" : "dev";
11019
11650
  function maskKey2(key) {
11020
11651
  if (!key) return "(not set)";
11021
11652
  if (key.length <= 8) return "****";
@@ -11257,42 +11888,42 @@ async function cmdDiagnose(config, profile, options = {}) {
11257
11888
  }
11258
11889
  return runCliChecks(config, profile, options.output);
11259
11890
  }
11260
- async function checkDoh(report) {
11261
- section("DoH Resolver");
11262
- const local = getDohStatus();
11891
+ async function checkPilot(report) {
11892
+ section("Pilot");
11893
+ const local = getPilotStatus();
11263
11894
  if (!local.exists) {
11264
- fail("DoH binary", "not installed", [
11265
- "Run: okx doh install",
11895
+ fail("Pilot binary", "not installed", [
11896
+ "Run: okx pilot install",
11266
11897
  "Or wait for the next npm install to auto-download"
11267
11898
  ]);
11268
- report.add("doh_binary", "not installed");
11899
+ report.add("pilot_binary", "not installed");
11269
11900
  return;
11270
11901
  }
11271
- ok("DoH binary", local.binaryPath);
11272
- report.add("doh_binary", `installed (${local.platform ?? "unknown"})`);
11902
+ ok("Pilot binary", local.binaryPath);
11903
+ report.add("pilot_binary", `installed (${local.platform ?? "unknown"})`);
11273
11904
  const cdnChecksum = await fetchCdnChecksum(void 0, 5e3);
11274
11905
  if (!cdnChecksum) {
11275
- warn("DoH checksum", "CDN unreachable \u2014 cannot verify");
11276
- report.add("doh_checksum", "CDN unreachable");
11906
+ warn("Pilot checksum", "CDN unreachable \u2014 cannot verify");
11907
+ report.add("pilot_checksum", "CDN unreachable");
11277
11908
  } else if (cdnChecksum.sha256 === local.sha256) {
11278
- ok("DoH checksum", `match (${cdnChecksum.source})`);
11279
- report.add("doh_checksum", `match (${cdnChecksum.source})`);
11909
+ ok("Pilot checksum", `match (${cdnChecksum.source})`);
11910
+ report.add("pilot_checksum", `match (${cdnChecksum.source})`);
11280
11911
  } else {
11281
- warn("DoH checksum", "mismatch \u2014 update available", ["Run: okx doh install"]);
11282
- report.add("doh_checksum", "mismatch");
11912
+ warn("Pilot checksum", "mismatch \u2014 update available", ["Run: okx pilot install"]);
11913
+ report.add("pilot_checksum", "mismatch");
11283
11914
  }
11284
11915
  try {
11285
11916
  const cacheEntry = readCache("www.okx.com");
11286
11917
  if (cacheEntry) {
11287
- ok("DoH mode", cacheEntry.mode);
11288
- report.add("doh_mode", cacheEntry.mode);
11918
+ ok("Pilot mode", cacheEntry.mode);
11919
+ report.add("pilot_mode", cacheEntry.mode);
11289
11920
  } else {
11290
- ok("DoH mode", "no cache (will auto-detect on next request)");
11291
- report.add("doh_mode", "no cache");
11921
+ ok("Pilot mode", "no cache (will auto-detect on next request)");
11922
+ report.add("pilot_mode", "no cache");
11292
11923
  }
11293
11924
  } catch {
11294
- ok("DoH mode", "no cache");
11295
- report.add("doh_mode", "no cache");
11925
+ ok("Pilot mode", "no cache");
11926
+ report.add("pilot_mode", "no cache");
11296
11927
  }
11297
11928
  }
11298
11929
  function checkConfigFile(report) {
@@ -11323,7 +11954,7 @@ async function runCliChecks(config, profile, outputPath) {
11323
11954
  report.add("ts", (/* @__PURE__ */ new Date()).toISOString());
11324
11955
  const configFilePassed = checkConfigFile(report);
11325
11956
  const envPassed = checkEnvironment(report);
11326
- await checkDoh(report);
11957
+ await checkPilot(report);
11327
11958
  if (!config) {
11328
11959
  fail("Config", "Could not load config (see Config File check above)", []);
11329
11960
  report.add("result", "FAIL");
@@ -11349,6 +11980,31 @@ async function runCliChecks(config, profile, outputPath) {
11349
11980
  writeReportIfRequested(report, outputPath);
11350
11981
  }
11351
11982
 
11983
+ // src/unknown-command.ts
11984
+ function unknownSubcommand(module, action, knownActions) {
11985
+ const actionStr = action ?? "(missing)";
11986
+ errorLine(`Unknown command: okx ${module} ${actionStr}`);
11987
+ const hint = suggestSubcommand(action, knownActions);
11988
+ if (hint) {
11989
+ errorLine(` Did you mean: okx ${module} ${hint} ?`);
11990
+ }
11991
+ if (knownActions.length > 0) {
11992
+ errorLine(` Available subcommands: ${knownActions.join(", ")}`);
11993
+ }
11994
+ errorLine(` Run 'okx ${module} --help' for full usage.`);
11995
+ process.exitCode = 1;
11996
+ }
11997
+ function suggestSubcommand(action, knownActions) {
11998
+ if (!action || !action.includes("-")) return void 0;
11999
+ const parts = action.split("-");
12000
+ if (parts.length !== 2) return void 0;
12001
+ const [a, b] = parts;
12002
+ if (knownActions.includes(b)) {
12003
+ return `${b} ${a}`;
12004
+ }
12005
+ return void 0;
12006
+ }
12007
+
11352
12008
  // src/commands/upgrade.ts
11353
12009
  import { spawnSync as spawnSync2 } from "child_process";
11354
12010
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
@@ -11554,17 +12210,17 @@ var CLI_REGISTRY = {
11554
12210
  },
11555
12211
  filter: {
11556
12212
  toolName: "market_filter",
11557
- usage: "okx market filter --instType <SPOT|SWAP|FUTURES> [--sortBy <field>] [--sortOrder <asc|desc>] [--limit <n>] [--baseCcy <ccy>] [--quoteCcy <ccy>] [--settleCcy <ccy>] [--instFamily <fam>] [--ctType <linear|inverse>] [--minLast <n>] [--maxLast <n>] [--minChg24hPct <n>] [--maxChg24hPct <n>] [--minMarketCapUsd <n>] [--maxMarketCapUsd <n>] [--minVolUsd24h <n>] [--maxVolUsd24h <n>] [--minFundingRate <n>] [--maxFundingRate <n>] [--minOiUsd <n>] [--maxOiUsd <n>]",
11558
- description: "Screen / rank instruments by multi-dimensional criteria (price, volume, OI, funding rate, market cap, etc.)"
12213
+ usage: "okx market filter --instType <SPOT|SWAP|FUTURES> [--sortBy <last|chg24hPct|marketCapUsd|volUsd24h|fundingRate|oiUsd|listTime>] [--sortOrder <asc|desc>] [--limit <1-100>] [--baseCcy <ccy>] [--quoteCcy <ccy>] [--settleCcy <ccy>] [--instFamily <fam>] [--ctType <linear|inverse>] [--minLast <n>] [--maxLast <n>] [--minChg24hPct <n>] [--maxChg24hPct <n>] [--minMarketCapUsd <n>] [--maxMarketCapUsd <n>] [--minVolUsd24h <n>] [--maxVolUsd24h <n>] [--minFundingRate <n>] [--maxFundingRate <n>] [--minOiUsd <n>] [--maxOiUsd <n>]",
12214
+ description: "Screen / rank instruments by multi-dimensional criteria (price, volume, OI, funding rate, market cap, etc.). For OI *change* ranking use `market oi-change`."
11559
12215
  },
11560
12216
  "oi-history": {
11561
12217
  toolName: "market_get_oi_history",
11562
- usage: "okx market oi-history <instId> [--bar <5m|15m|1H|4H|1D>] [--limit <n>] [--ts <ms>]",
12218
+ usage: "okx market oi-history <instId> [--bar <5m|15m|1H|4H|1D>] [--limit <1-500>] [--ts <ms>]",
11563
12219
  description: "Open interest history time series with bar-over-bar delta for a single instrument"
11564
12220
  },
11565
12221
  "oi-change": {
11566
12222
  toolName: "market_filter_oi_change",
11567
- usage: "okx market oi-change --instType <SWAP|FUTURES> [--bar <5m|15m|1H|4H|1D>] [--sortBy <field>] [--sortOrder <asc|desc>] [--limit <n>] [--minOiUsd <n>] [--minVolUsd24h <n>] [--minAbsOiDeltaPct <n>]",
12223
+ usage: "okx market oi-change --instType <SWAP|FUTURES> [--bar <5m|15m|1H|4H|1D>] [--sortBy <oiUsd|oiDeltaUsd|oiDeltaPct|absOiDeltaPct|volUsd24h|fundingRate|last>] [--sortOrder <asc|desc>] [--limit <1-100>] [--minOiUsd <n>] [--minVolUsd24h <n>] [--minAbsOiDeltaPct <n>]",
11568
12224
  description: "Find instruments with largest OI changes over a bar window (accumulation/distribution scanner)"
11569
12225
  }
11570
12226
  },
@@ -11577,10 +12233,10 @@ var CLI_REGISTRY = {
11577
12233
  usage: "okx market indicator list",
11578
12234
  description: "List all supported technical indicators"
11579
12235
  },
11580
- "<instId> <indicator>": {
12236
+ "<indicator> <instId>": {
11581
12237
  toolName: "market_get_indicator",
11582
- usage: "okx market indicator <instId> <indicator> [--bar <bar>] [--limit <n>] [--backtest-time <ts>] [--params <json>]",
11583
- description: "Get indicator values for an instrument (e.g. okx market indicator BTC-USDT-SWAP rsi)"
12238
+ usage: "okx market indicator <indicator> <instId> [--bar <3m|5m|15m|1H|4H|12Hutc|1Dutc|3Dutc|1Wutc>] [--limit <1-100>] [--backtest-time <ts>] [--params <json>]",
12239
+ description: "Get indicator values for an instrument (e.g. okx market indicator rsi BTC-USDT-SWAP). NOTE: 1m is not supported for indicators."
11584
12240
  }
11585
12241
  }
11586
12242
  }
@@ -11700,6 +12356,11 @@ var CLI_REGISTRY = {
11700
12356
  alternateTools: ["spot_batch_amend", "spot_batch_cancel"],
11701
12357
  usage: "okx spot batch --action <place|amend|cancel> --orders '<json>'",
11702
12358
  description: "Batch place, amend, or cancel spot orders"
12359
+ },
12360
+ leverage: {
12361
+ toolName: "spot_set_leverage",
12362
+ usage: "okx spot leverage ( --instId <pair> | --ccy <ccy> ) --lever <positive-number> --mgnMode <cross|isolated>",
12363
+ description: "Set leverage for SPOT margin. Provide instId (pair-level) OR ccy (currency-level cross, for borrow-enabled/multi-ccy/portfolio margin). When ccy is used, mgnMode must be cross."
11703
12364
  }
11704
12365
  },
11705
12366
  subgroups: {
@@ -11782,8 +12443,8 @@ var CLI_REGISTRY = {
11782
12443
  },
11783
12444
  leverage: {
11784
12445
  toolName: "swap_set_leverage",
11785
- usage: "okx swap leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <side>]",
11786
- description: "Set leverage for a swap instrument"
12446
+ usage: "okx swap leverage --instId <id> --lever <positive-number> --mgnMode <cross|isolated> [--posSide <long|short>]",
12447
+ description: "Set leverage for a swap instrument. posSide is REQUIRED when mgnMode=isolated and account is in hedge mode \u2014 must be set for BOTH long and short separately. Not supported for portfolio margin + cross."
11787
12448
  },
11788
12449
  "get-leverage": {
11789
12450
  toolName: "swap_get_leverage",
@@ -11881,8 +12542,8 @@ var CLI_REGISTRY = {
11881
12542
  },
11882
12543
  leverage: {
11883
12544
  toolName: "futures_set_leverage",
11884
- usage: "okx futures leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <net|long|short>]",
11885
- description: "Set leverage for a futures instrument"
12545
+ usage: "okx futures leverage --instId <id> --lever <positive-number> --mgnMode <cross|isolated> [--posSide <long|short>]",
12546
+ description: "Set leverage for a futures instrument. posSide is REQUIRED when mgnMode=isolated and account is in hedge mode \u2014 must be set for BOTH long and short separately. Not supported for portfolio margin + cross."
11886
12547
  },
11887
12548
  batch: {
11888
12549
  toolName: "futures_batch_orders",
@@ -12192,9 +12853,14 @@ var CLI_REGISTRY = {
12192
12853
  usage: "okx bot grid create --instId <id> --algoOrdType <grid|contract_grid> --maxPx <px> --minPx <px> --gridNum <n>\n [--runType <1|2>] [--quoteSz <n>] [--baseSz <n>]\n [--direction <long|short|neutral>] [--lever <n>] [--sz <n>] [--basePos] [--no-basePos]\n [--tpTriggerPx <px>] [--slTriggerPx <px>] [--tpRatio <n>] [--slRatio <n>] [--algoClOrdId <id>]",
12193
12854
  description: "Create a new grid bot order (contract grid opens base position by default)"
12194
12855
  },
12856
+ amend: {
12857
+ toolName: "grid_amend_order",
12858
+ usage: "okx bot grid amend --algoId <id> --maxPx <px> --minPx <px> --gridNum <n> [--topUpAmt <n>]\n okx bot grid amend --algoId <id> --instId <id> [--tpTriggerPx <px>] [--slTriggerPx <px>] [--tpRatio <n>] [--slRatio <n>] [--topUpAmt <n>]",
12859
+ description: "Amend a running grid bot. Price-range mode: provide --maxPx/--minPx/--gridNum. TP/SL mode: provide --instId and TP/SL flags."
12860
+ },
12195
12861
  stop: {
12196
12862
  toolName: "grid_stop_order",
12197
- usage: "okx bot grid stop --algoId <id> --algoOrdType <type> --instId <id> [--stopType <1|2|3|5|6>]",
12863
+ usage: "okx bot grid stop --algoId <id> --algoOrdType <type> --instId <id> [--stopType <1|2>]",
12198
12864
  description: "Stop a running grid bot order"
12199
12865
  }
12200
12866
  }
@@ -12282,6 +12948,37 @@ var CLI_REGISTRY = {
12282
12948
  }
12283
12949
  }
12284
12950
  },
12951
+ // ── smartmoney ─────────────────────────────────────────────────────────────
12952
+ smartmoney: {
12953
+ description: "Smart money signals \u2014 trader leaderboard, consensus signals, and position analysis",
12954
+ commands: {
12955
+ overview: {
12956
+ toolName: "smartmoney_get_overview",
12957
+ usage: "okx smartmoney overview [--dataVersion <ver>] [--ts <ms>] [--instType <SWAP|SPOT>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--lmtNum <n>] [--instCcyList <ccys>] [--instCcy <ccy>] [--topInstruments <n>] [--json]",
12958
+ description: "Multi-currency smart money overview with aggregated signals"
12959
+ },
12960
+ signal: {
12961
+ toolName: "smartmoney_get_signal",
12962
+ usage: "okx smartmoney signal [--instId <id>] [--instCcy <ccy>] [--dataVersion <ver>] [--ts <ms>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--lmtNum <n>] [--authorIds <ids>] [--json]",
12963
+ description: "Single-currency aggregated consensus signal (prefer --instId; --instCcy may return empty)"
12964
+ },
12965
+ "signal-history": {
12966
+ toolName: "smartmoney_get_signal_history",
12967
+ usage: "okx smartmoney signal-history --instId <id> [--dataVersion <ver>] [--ts <ms>] [--granularity <1h|1d>] [--limit <n>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--json]",
12968
+ description: "Signal history timeline for trend analysis"
12969
+ },
12970
+ traders: {
12971
+ toolName: "smartmoney_get_traders",
12972
+ usage: 'okx smartmoney traders [--dataVersion <ts>] [--sortType <pnl|pnl_ratio>] [--period <""|3|7|30|90>] [--pnl <n>] [--winRatio <r>] [--maxRetreat <r>] [--asset <n>] [--authorIds <ids>] [--limit <n>] [--after <id>] [--before <id>] [--json]',
12973
+ description: "List/filter traders from the smart money leaderboard"
12974
+ },
12975
+ trader: {
12976
+ toolName: "smartmoney_get_trader_detail",
12977
+ usage: "okx smartmoney trader --authorId <id> [--period <3|7|30|90>] [--instCcy <ccy>] [--tradeLimit <n>] [--json]",
12978
+ description: "Trader full portrait (profile + positions + trades)"
12979
+ }
12980
+ }
12981
+ },
12285
12982
  // ── config ─────────────────────────────────────────────────────────────────
12286
12983
  config: {
12287
12984
  description: "Manage CLI configuration profiles",
@@ -12313,24 +13010,24 @@ var CLI_REGISTRY = {
12313
13010
  description: "Set up client integrations (Cursor, Windsurf, Claude, etc.)",
12314
13011
  usage: `okx setup --client <${SUPPORTED_CLIENTS.join("|")}> [--profile <name>] [--modules <list>]`
12315
13012
  },
12316
- // ── doh ────────────────────────────────────────────────────────────────────
12317
- doh: {
12318
- description: "Manage DoH (DNS-over-HTTPS) resolver binary",
13013
+ // ── pilot ──────────────────────────────────────────────────────────────────
13014
+ pilot: {
13015
+ description: "Manage Pilot proxy resolver binary",
12319
13016
  commands: {
12320
13017
  status: {
12321
13018
  toolName: null,
12322
- usage: "okx doh status [--json]",
12323
- description: "Show DoH binary info, checksum, and CDN match status"
13019
+ usage: "okx pilot status [--json]",
13020
+ description: "Show Pilot binary info, checksum, and CDN match status"
12324
13021
  },
12325
13022
  install: {
12326
13023
  toolName: null,
12327
- usage: "okx doh install [--json]",
12328
- description: "Download or update the DoH resolver binary"
13024
+ usage: "okx pilot install [--json]",
13025
+ description: "Download or update the Pilot binary"
12329
13026
  },
12330
13027
  remove: {
12331
13028
  toolName: null,
12332
- usage: "okx doh remove [--force] [--json]",
12333
- description: "Remove the DoH resolver binary (prompts for confirmation without --force)"
13029
+ usage: "okx pilot remove [--force] [--json]",
13030
+ description: "Remove the Pilot binary (prompts for confirmation without --force)"
12334
13031
  }
12335
13032
  }
12336
13033
  },
@@ -12581,7 +13278,7 @@ function formatTime(ts) {
12581
13278
  async function cmdNewsLatest(run, opts) {
12582
13279
  const result = await run("news_get_latest", {
12583
13280
  coins: opts.coins,
12584
- importance: opts.importance,
13281
+ importance: opts.importance ?? "low",
12585
13282
  platform: opts.platform,
12586
13283
  begin: opts.begin,
12587
13284
  end: opts.end,
@@ -12633,7 +13330,7 @@ async function cmdNewsImportant(run, opts) {
12633
13330
  async function cmdNewsByCoin(run, coins, opts) {
12634
13331
  const result = await run("news_get_by_coin", {
12635
13332
  coins,
12636
- importance: opts.importance,
13333
+ importance: opts.importance ?? "low",
12637
13334
  platform: opts.platform,
12638
13335
  begin: opts.begin,
12639
13336
  end: opts.end,
@@ -12659,7 +13356,7 @@ async function cmdNewsSearch(run, keyword, opts) {
12659
13356
  const result = await run("news_search", {
12660
13357
  keyword: keyword || void 0,
12661
13358
  coins: opts.coins,
12662
- importance: opts.importance,
13359
+ importance: opts.importance ?? "low",
12663
13360
  platform: opts.platform,
12664
13361
  sentiment: opts.sentiment,
12665
13362
  sortBy: opts.sortBy,
@@ -13008,6 +13705,7 @@ var CLI_OPTIONS = {
13008
13705
  slRatio: { type: "string" },
13009
13706
  algoClOrdId: { type: "string" },
13010
13707
  stopType: { type: "string" },
13708
+ topUpAmt: { type: "string" },
13011
13709
  live: { type: "boolean", default: false },
13012
13710
  // market extras
13013
13711
  instType: { type: "string" },
@@ -13016,6 +13714,7 @@ var CLI_OPTIONS = {
13016
13714
  // account extras
13017
13715
  archive: { type: "boolean", default: false },
13018
13716
  valuation: { type: "boolean", default: false },
13717
+ valuationCcy: { type: "string" },
13019
13718
  posMode: { type: "string" },
13020
13719
  ccy: { type: "string" },
13021
13720
  from: { type: "string" },
@@ -13064,6 +13763,22 @@ var CLI_OPTIONS = {
13064
13763
  // audit
13065
13764
  since: { type: "string" },
13066
13765
  tool: { type: "string" },
13766
+ // smartmoney
13767
+ authorId: { type: "string" },
13768
+ authorIds: { type: "string" },
13769
+ dataVersion: { type: "string" },
13770
+ sortType: { type: "string" },
13771
+ granularity: { type: "string" },
13772
+ lmtNum: { type: "string" },
13773
+ instCcy: { type: "string" },
13774
+ instCcyList: { type: "string" },
13775
+ topInstruments: { type: "string" },
13776
+ tradeLimit: { type: "string" },
13777
+ // smartmoney pool filters
13778
+ pnl: { type: "string" },
13779
+ winRatio: { type: "string" },
13780
+ maxRetreat: { type: "string" },
13781
+ asset: { type: "string" },
13067
13782
  // upgrade
13068
13783
  beta: { type: "boolean", default: false },
13069
13784
  check: { type: "boolean", default: false },
@@ -13603,13 +14318,14 @@ async function cmdAccountBalance(run, ccy, json) {
13603
14318
  }
13604
14319
  printTable(rows);
13605
14320
  }
13606
- async function cmdAccountAssetBalance(run, ccy, json, showValuation) {
14321
+ async function cmdAccountAssetBalance(run, ccy, json, showValuation, valuationCcy) {
13607
14322
  const result = await run("account_get_asset_balance", {
13608
14323
  ccy,
13609
- ...showValuation ? { showValuation: true } : {}
14324
+ ...showValuation ? { showValuation: true } : {},
14325
+ ...valuationCcy !== void 0 ? { valuationCcy } : {}
13610
14326
  });
13611
14327
  const data = result.data ?? [];
13612
- if (json) return printJson(showValuation ? { data, valuation: result.valuation } : data);
14328
+ if (json) return printJson(showValuation ? { data, valuation: result.valuation, valuationCcy: result.valuationCcy } : data);
13613
14329
  const assetRows = data.filter((r) => Number(r["bal"]) > 0).map((r) => ({
13614
14330
  ccy: r["ccy"],
13615
14331
  bal: r["bal"],
@@ -13624,7 +14340,7 @@ async function cmdAccountAssetBalance(run, ccy, json, showValuation) {
13624
14340
  if (showValuation && result.valuation) {
13625
14341
  const valuationData = result.valuation ?? [];
13626
14342
  outputLine("");
13627
- outputLine("Asset Valuation by Account Type:");
14343
+ outputLine(`Asset Valuation by Account Type (${String(result.valuationCcy ?? "USDT")}):`);
13628
14344
  printTable(
13629
14345
  valuationData.map((v) => {
13630
14346
  const details = v["details"] ?? {};
@@ -14065,6 +14781,19 @@ async function cmdSpotBatch(run, opts) {
14065
14781
  if (opts.json) return printJson(data);
14066
14782
  emitBatchResults(data ?? []);
14067
14783
  }
14784
+ async function cmdSpotSetLeverage(run, opts) {
14785
+ const result = await run("spot_set_leverage", {
14786
+ instId: opts.instId,
14787
+ ccy: opts.ccy,
14788
+ lever: opts.lever,
14789
+ mgnMode: opts.mgnMode
14790
+ });
14791
+ const data = getData4(result);
14792
+ if (opts.json) return printJson(data);
14793
+ const r = data?.[0];
14794
+ const target = r?.["instId"] ?? r?.["ccy"] ?? "";
14795
+ outputLine(`Leverage set: ${r?.["lever"]}x ${target} (${r?.["mgnMode"]})`);
14796
+ }
14068
14797
 
14069
14798
  // src/commands/swap.ts
14070
14799
  function getData5(result) {
@@ -15432,6 +16161,178 @@ function extractFixedOffers(result) {
15432
16161
  return [];
15433
16162
  }
15434
16163
 
16164
+ // src/commands/smartmoney.ts
16165
+ function printDataList2(data, json, emptyMsg, mapper) {
16166
+ if (json) {
16167
+ printJson(data);
16168
+ return;
16169
+ }
16170
+ if (!data.length) {
16171
+ outputLine(emptyMsg);
16172
+ return;
16173
+ }
16174
+ printTable(data.map(mapper));
16175
+ }
16176
+ function poolFilterArgs(o) {
16177
+ const result = {};
16178
+ if (o.sortType) result.sortType = o.sortType;
16179
+ if (o.period) result.period = o.period;
16180
+ if (o.pnl) result.pnl = o.pnl;
16181
+ if (o.winRatio) result.winRatio = o.winRatio;
16182
+ if (o.maxRetreat) result.maxRetreat = o.maxRetreat;
16183
+ if (o.asset) result.asset = o.asset;
16184
+ return result;
16185
+ }
16186
+ async function cmdSmartmoneyOverview(run, opts) {
16187
+ const result = await run("smartmoney_get_overview", {
16188
+ dataVersion: opts.dataVersion,
16189
+ ts: opts.ts,
16190
+ instType: opts.instType,
16191
+ ...poolFilterArgs(opts),
16192
+ lmtNum: opts.lmtNum,
16193
+ instCcyList: opts.instCcyList,
16194
+ instCcy: opts.instCcy,
16195
+ topInstruments: opts.topInstruments
16196
+ });
16197
+ const data = extractData(result);
16198
+ printDataList2(data, opts.json, "No overview data", (r) => ({
16199
+ instId: r["instId"],
16200
+ tradersWithPosition: r["tradersWithPosition"],
16201
+ longRatio: r["longRatio"],
16202
+ weightedLongRatio: r["weightedLongRatio"],
16203
+ netNotionalUsdt: r["netNotionalUsdt"],
16204
+ vs24h: r["vs24h"]
16205
+ }));
16206
+ }
16207
+ async function cmdSmartmoneySignal(run, opts) {
16208
+ const result = await run("smartmoney_get_signal", {
16209
+ instId: opts.instId,
16210
+ instCcy: opts.instCcy,
16211
+ dataVersion: opts.dataVersion,
16212
+ ts: opts.ts,
16213
+ ...poolFilterArgs(opts),
16214
+ lmtNum: opts.lmtNum,
16215
+ authorIds: opts.authorIds
16216
+ });
16217
+ const data = extractData(result);
16218
+ const signal = data[0];
16219
+ if (opts.json) {
16220
+ printJson(signal ?? {});
16221
+ return;
16222
+ }
16223
+ if (!signal) {
16224
+ outputLine("No signal data");
16225
+ return;
16226
+ }
16227
+ printKv({
16228
+ instId: signal["instId"],
16229
+ instType: signal["instType"],
16230
+ tradersWithPosition: signal["tradersWithPosition"],
16231
+ tradersTotal: signal["tradersTotal"],
16232
+ longRatio: signal["longRatio"],
16233
+ weightedLongRatio: signal["weightedLongRatio"],
16234
+ avgLongWinRatio: signal["avgLongWinRatio"],
16235
+ avgShortWinRatio: signal["avgShortWinRatio"],
16236
+ longNotionalUsdt: signal["longNotionalUsdt"],
16237
+ shortNotionalUsdt: signal["shortNotionalUsdt"],
16238
+ netNotionalUsdt: signal["netNotionalUsdt"],
16239
+ longTraders: signal["longTraders"],
16240
+ shortTraders: signal["shortTraders"],
16241
+ vs1h: signal["vs1h"],
16242
+ vs24h: signal["vs24h"],
16243
+ vs7d: signal["vs7d"],
16244
+ smartMoneyLongAvgEntry: signal["smartMoneyLongAvgEntry"],
16245
+ smartMoneyShortAvgEntry: signal["smartMoneyShortAvgEntry"],
16246
+ totalNotionalVs24h: signal["totalNotionalVs24h"],
16247
+ currentPrice: signal["currentPrice"],
16248
+ priceChange24h: signal["priceChange24h"],
16249
+ fundingRate: signal["fundingRate"],
16250
+ openInterest: signal["openInterest"],
16251
+ longShortAccountRatio: signal["longShortAccountRatio"]
16252
+ });
16253
+ }
16254
+ async function cmdSmartmoneySignalHistory(run, opts) {
16255
+ const result = await run("smartmoney_get_signal_history", {
16256
+ instId: opts.instId,
16257
+ dataVersion: opts.dataVersion,
16258
+ ts: opts.ts,
16259
+ granularity: opts.granularity,
16260
+ limit: opts.limit,
16261
+ ...poolFilterArgs(opts)
16262
+ });
16263
+ const data = extractData(result);
16264
+ printDataList2(data, opts.json, "No signal history data", (r) => ({
16265
+ ts: r["ts"],
16266
+ longRatio: r["longRatio"],
16267
+ weightedLongRatio: r["weightedLongRatio"],
16268
+ tradersWithPosition: r["tradersWithPosition"],
16269
+ netNotionalUsdt: r["netNotionalUsdt"],
16270
+ totalNotionalUsdt: r["totalNotionalUsdt"],
16271
+ tradersQualified: r["tradersQualified"]
16272
+ }));
16273
+ }
16274
+ async function cmdSmartmoneyTraders(run, opts) {
16275
+ const data = extractData(await run("smartmoney_get_traders", {
16276
+ dataVersion: opts.dataVersion,
16277
+ ...poolFilterArgs(opts),
16278
+ authorIds: opts.authorIds,
16279
+ after: opts.after,
16280
+ before: opts.before,
16281
+ limit: opts.limit
16282
+ }));
16283
+ printDataList2(data, opts.json, "No traders found", (r) => ({
16284
+ authorId: r["authorId"],
16285
+ nickName: r["nickName"],
16286
+ pnl: r["pnl"],
16287
+ pnlRatio: r["pnlRatio"],
16288
+ winRatio: r["winRatio"],
16289
+ asset: r["asset"]
16290
+ }));
16291
+ }
16292
+ async function cmdSmartmoneyTraderDetail(run, opts) {
16293
+ const result = await run("smartmoney_get_trader_detail", {
16294
+ authorId: opts.authorId,
16295
+ period: opts.period,
16296
+ instCcy: opts.instCcy,
16297
+ tradeLimit: opts.tradeLimit
16298
+ });
16299
+ const data = result;
16300
+ const inner = data["data"];
16301
+ if (opts.json) {
16302
+ printJson(inner ?? {});
16303
+ return;
16304
+ }
16305
+ if (!inner) {
16306
+ outputLine("No data");
16307
+ return;
16308
+ }
16309
+ const profileArr = inner["profile"];
16310
+ if (Array.isArray(profileArr) && profileArr.length > 0) {
16311
+ const p = profileArr[0];
16312
+ outputLine("=== Profile ===");
16313
+ printKv({
16314
+ authorId: p["authorId"],
16315
+ nickName: p["nickName"],
16316
+ pnl: p["pnl"],
16317
+ pnlRatio: p["pnlRatio"],
16318
+ winRatio: p["winRatio"],
16319
+ maxRetreat: p["maxRetreat"],
16320
+ asset: p["asset"],
16321
+ onboardDuration: p["onboardDuration"]
16322
+ });
16323
+ }
16324
+ const posArr = inner["positions"];
16325
+ if (Array.isArray(posArr) && posArr.length > 0) {
16326
+ outputLine("\n=== Current Positions ===");
16327
+ printJson(posArr);
16328
+ }
16329
+ const tradeArr = inner["trades"];
16330
+ if (Array.isArray(tradeArr) && tradeArr.length > 0) {
16331
+ outputLine("\n=== Recent Trades ===");
16332
+ printJson(tradeArr);
16333
+ }
16334
+ }
16335
+
15435
16336
  // src/commands/auto-earn.ts
15436
16337
  var USDG_EARN_CURRENCIES = /* @__PURE__ */ new Set(["USDG", "BUIDL"]);
15437
16338
  function isSupported(status) {
@@ -15685,6 +16586,28 @@ async function cmdGridCreate(run, opts) {
15685
16586
  if (opts.json) return printJson(data);
15686
16587
  emitWriteResult5(data?.[0], "Grid bot created", "algoId");
15687
16588
  }
16589
+ async function cmdGridAmend(run, opts) {
16590
+ const result = await run("grid_amend_order", {
16591
+ algoId: opts.algoId,
16592
+ instId: opts.instId,
16593
+ maxPx: opts.maxPx,
16594
+ minPx: opts.minPx,
16595
+ gridNum: opts.gridNum,
16596
+ tpTriggerPx: opts.tpTriggerPx,
16597
+ slTriggerPx: opts.slTriggerPx,
16598
+ tpRatio: opts.tpRatio,
16599
+ slRatio: opts.slRatio,
16600
+ topUpAmt: opts.topUpAmt
16601
+ });
16602
+ const data = getData8(result);
16603
+ if (opts.json) return printJson(data);
16604
+ const item = data?.[0];
16605
+ if (item?.["algoId"]) {
16606
+ outputLine(`Grid bot amended: ${item["algoId"]} (OK)`);
16607
+ } else {
16608
+ emitWriteResult5(item, "Grid bot amended", "algoId");
16609
+ }
16610
+ }
15688
16611
  async function cmdGridStop(run, opts) {
15689
16612
  const result = await run("grid_stop_order", {
15690
16613
  algoId: opts.algoId,
@@ -16313,7 +17236,7 @@ function printSkillInstallResult(meta, json) {
16313
17236
  }
16314
17237
  }
16315
17238
 
16316
- // src/commands/doh.ts
17239
+ // src/commands/pilot.ts
16317
17240
  import readline from "readline";
16318
17241
  function resolveChecksumMatch(local, cdnChecksum, cdnError) {
16319
17242
  if (!local.exists) return "not-installed";
@@ -16328,7 +17251,7 @@ function checksumMatchLabel(match) {
16328
17251
  }
16329
17252
  function formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode) {
16330
17253
  outputLine("");
16331
- outputLine(" DoH Resolver Status");
17254
+ outputLine(" Pilot Status");
16332
17255
  outputLine(" " + "\u2500".repeat(40));
16333
17256
  outputLine(` Binary path : ${local.binaryPath}`);
16334
17257
  outputLine(` Installed : ${local.exists ? "yes" : "no"}`);
@@ -16344,8 +17267,8 @@ function formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode) {
16344
17267
  outputLine(` Runtime mode: ${runtimeMode}`);
16345
17268
  outputLine("");
16346
17269
  }
16347
- async function cmdDohStatus(json, binaryPath) {
16348
- const local = getDohStatus(binaryPath);
17270
+ async function cmdPilotStatus(json, binaryPath) {
17271
+ const local = getPilotStatus(binaryPath);
16349
17272
  let runtimeMode = "no cache";
16350
17273
  try {
16351
17274
  const cacheEntry = readCache("www.okx.com");
@@ -16382,7 +17305,7 @@ async function cmdDohStatus(json, binaryPath) {
16382
17305
  }
16383
17306
  formatStatusText(local, checksumMatch, cdnChecksum, runtimeMode);
16384
17307
  }
16385
- async function cmdDohInstall(json, binaryPath) {
17308
+ async function cmdPilotInstall(json, binaryPath) {
16386
17309
  const messages2 = [];
16387
17310
  const onProgress = (msg) => {
16388
17311
  if (!json) {
@@ -16392,9 +17315,9 @@ async function cmdDohInstall(json, binaryPath) {
16392
17315
  };
16393
17316
  if (!json) {
16394
17317
  outputLine("");
16395
- outputLine(" Installing DoH resolver...");
17318
+ outputLine(" Installing Pilot...");
16396
17319
  }
16397
- const result = await installDohBinary(binaryPath, void 0, onProgress);
17320
+ const result = await installPilotBinary(binaryPath, void 0, onProgress);
16398
17321
  if (json) {
16399
17322
  outputLine(JSON.stringify({ status: result.status, source: result.source ?? null, error: result.error ?? null, messages: messages2 }));
16400
17323
  if (result.status === "failed") {
@@ -16403,9 +17326,9 @@ async function cmdDohInstall(json, binaryPath) {
16403
17326
  return;
16404
17327
  }
16405
17328
  if (result.status === "installed") {
16406
- outputLine(` \u2713 DoH resolver installed successfully (${result.source ?? ""})`);
17329
+ outputLine(` \u2713 Pilot installed successfully (${result.source ?? ""})`);
16407
17330
  } else if (result.status === "up-to-date") {
16408
- outputLine(" \u2713 DoH resolver is already up to date");
17331
+ outputLine(" \u2713 Pilot is already up to date");
16409
17332
  } else {
16410
17333
  errorLine(` \u2717 Installation failed: ${result.error ?? "unknown error"}`);
16411
17334
  errorLine(" Hint: check network connectivity or try again later");
@@ -16413,13 +17336,13 @@ async function cmdDohInstall(json, binaryPath) {
16413
17336
  }
16414
17337
  outputLine("");
16415
17338
  }
16416
- async function cmdDohRemove(force, json, binaryPath) {
16417
- const local = getDohStatus(binaryPath);
17339
+ async function cmdPilotRemove(force, json, binaryPath) {
17340
+ const local = getPilotStatus(binaryPath);
16418
17341
  if (!local.exists) {
16419
17342
  if (json) {
16420
17343
  outputLine(JSON.stringify({ status: "not-installed" }));
16421
17344
  } else {
16422
- outputLine(" DoH resolver is not installed.");
17345
+ outputLine(" Pilot is not installed.");
16423
17346
  }
16424
17347
  return;
16425
17348
  }
@@ -16430,14 +17353,14 @@ async function cmdDohRemove(force, json, binaryPath) {
16430
17353
  return;
16431
17354
  }
16432
17355
  const confirmed = await askConfirmation(
16433
- ` Remove DoH resolver at ${local.binaryPath}? [y/N] `
17356
+ ` Remove Pilot at ${local.binaryPath}? [y/N] `
16434
17357
  );
16435
17358
  if (!confirmed) {
16436
17359
  outputLine(" Cancelled.");
16437
17360
  return;
16438
17361
  }
16439
17362
  }
16440
- const result = removeDohBinary(binaryPath);
17363
+ const result = removePilotBinary(binaryPath);
16441
17364
  if (json) {
16442
17365
  outputLine(JSON.stringify({ status: result.status, path: local.binaryPath }));
16443
17366
  return;
@@ -16445,7 +17368,7 @@ async function cmdDohRemove(force, json, binaryPath) {
16445
17368
  if (result.status === "removed") {
16446
17369
  outputLine(` \u2713 Removed: ${local.binaryPath}`);
16447
17370
  } else {
16448
- outputLine(" DoH resolver is not installed.");
17371
+ outputLine(" Pilot is not installed.");
16449
17372
  }
16450
17373
  }
16451
17374
  function formatBytes(bytes) {
@@ -16912,13 +17835,13 @@ async function cmdEventCancel(run, opts) {
16912
17835
  // src/index.ts
16913
17836
  var _require3 = createRequire3(import.meta.url);
16914
17837
  var CLI_VERSION2 = _require3("../package.json").version;
16915
- var GIT_HASH2 = true ? "e9764c9" : "dev";
16916
- function handleDohCommand(action, json, force, binaryPath) {
16917
- if (action === "status") return cmdDohStatus(json, binaryPath);
16918
- if (action === "install") return cmdDohInstall(json, binaryPath);
16919
- if (action === "remove") return cmdDohRemove(force, json, binaryPath);
16920
- errorLine(`Unknown doh command: ${action}`);
16921
- errorLine("Usage: okx doh <status|install|remove>");
17838
+ var GIT_HASH2 = true ? "e0ee5a96" : "dev";
17839
+ function handlePilotCommand(action, json, force, binaryPath) {
17840
+ if (action === "status") return cmdPilotStatus(json, binaryPath);
17841
+ if (action === "install") return cmdPilotInstall(json, binaryPath);
17842
+ if (action === "remove") return cmdPilotRemove(force, json, binaryPath);
17843
+ errorLine(`Unknown pilot command: ${action}`);
17844
+ errorLine("Usage: okx pilot <status|install|remove>");
16922
17845
  process.exitCode = 1;
16923
17846
  }
16924
17847
  function handleConfigCommand(action, rest, json, lang, force) {
@@ -17045,7 +17968,28 @@ function handleMarketDataCommand(run, action, rest, v, json) {
17045
17968
  return cmdMarketIndexCandles(run, rest[0], { bar: v.bar, limit, history: v.history ?? false, json, demo: v.demo });
17046
17969
  }
17047
17970
  function handleMarketCommand(run, action, rest, v, json) {
17048
- return handleMarketPublicCommand(run, action, rest, v, json) ?? handleMarketDataCommand(run, action, rest, v, json);
17971
+ const result = handleMarketPublicCommand(run, action, rest, v, json) ?? handleMarketDataCommand(run, action, rest, v, json);
17972
+ if (result !== void 0) return result;
17973
+ unknownSubcommand("market", action, [
17974
+ "ticker",
17975
+ "tickers",
17976
+ "orderbook",
17977
+ "candles",
17978
+ "trades",
17979
+ "instruments",
17980
+ "mark-price",
17981
+ "funding-rate",
17982
+ "open-interest",
17983
+ "index-ticker",
17984
+ "price-limit",
17985
+ "stock-tokens",
17986
+ "instruments-by-category",
17987
+ "indicator",
17988
+ "filter",
17989
+ "oi-history",
17990
+ "oi-change",
17991
+ "index-candles"
17992
+ ]);
17049
17993
  }
17050
17994
  function handleAccountWriteCommand(run, action, v, json) {
17051
17995
  if (action === "set-position-mode")
@@ -17065,13 +18009,28 @@ function handleAccountWriteCommand(run, action, v, json) {
17065
18009
  subAcct: v.subAcct,
17066
18010
  json
17067
18011
  });
18012
+ unknownSubcommand("account", action, [
18013
+ "audit",
18014
+ "balance",
18015
+ "asset-balance",
18016
+ "positions",
18017
+ "positions-history",
18018
+ "bills",
18019
+ "fees",
18020
+ "config",
18021
+ "set-position-mode",
18022
+ "max-size",
18023
+ "max-avail-size",
18024
+ "max-withdrawal",
18025
+ "transfer"
18026
+ ]);
17068
18027
  }
17069
18028
  function handleAccountCommand(run, action, rest, v, json) {
17070
18029
  if (action === "audit")
17071
18030
  return cmdAccountAudit({ limit: v.limit, tool: v.tool, since: v.since, json });
17072
18031
  const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
17073
18032
  if (action === "balance") return cmdAccountBalance(run, rest[0], json);
17074
- if (action === "asset-balance") return cmdAccountAssetBalance(run, v.ccy, json, v.valuation);
18033
+ if (action === "asset-balance") return cmdAccountAssetBalance(run, v.ccy, json, v.valuation, v.valuationCcy);
17075
18034
  if (action === "positions")
17076
18035
  return cmdAccountPositions(run, { instType: v.instType, instId: v.instId, json });
17077
18036
  if (action === "positions-history")
@@ -17144,6 +18103,7 @@ function handleSpotAlgoCommand(run, subAction, v, json) {
17144
18103
  ordType: v.ordType,
17145
18104
  json
17146
18105
  });
18106
+ unknownSubcommand("spot algo", subAction, ["trail", "place", "amend", "cancel", "orders"]);
17147
18107
  }
17148
18108
  function handleSpotCommand(run, action, rest, v, json) {
17149
18109
  if (action === "orders")
@@ -17187,6 +18147,25 @@ function handleSpotCommand(run, action, rest, v, json) {
17187
18147
  return handleSpotAlgoCommand(run, rest[0], v, json);
17188
18148
  if (action === "batch")
17189
18149
  return cmdSpotBatch(run, { action: v.action, orders: v.orders, json });
18150
+ if (action === "leverage")
18151
+ return cmdSpotSetLeverage(run, {
18152
+ instId: v.instId,
18153
+ ccy: v.ccy,
18154
+ lever: v.lever,
18155
+ mgnMode: v.mgnMode,
18156
+ json
18157
+ });
18158
+ unknownSubcommand("spot", action, [
18159
+ "orders",
18160
+ "get",
18161
+ "fills",
18162
+ "place",
18163
+ "cancel",
18164
+ "amend",
18165
+ "algo",
18166
+ "batch",
18167
+ "leverage"
18168
+ ]);
17190
18169
  }
17191
18170
  function handleSwapAlgoCommand(run, subAction, v, json) {
17192
18171
  if (subAction === "trail")
@@ -17242,6 +18221,7 @@ function handleSwapAlgoCommand(run, subAction, v, json) {
17242
18221
  ordType: v.ordType,
17243
18222
  json
17244
18223
  });
18224
+ unknownSubcommand("swap algo", subAction, ["trail", "place", "amend", "cancel", "orders"]);
17245
18225
  }
17246
18226
  function handleSwapQuery(run, action, rest, v, json) {
17247
18227
  if (action === "positions")
@@ -17317,6 +18297,20 @@ function handleSwapCommand(run, action, rest, v, json) {
17317
18297
  return handleSwapAlgoCommand(run, rest[0], v, json);
17318
18298
  if (action === "batch")
17319
18299
  return cmdSwapBatch(run, { action: v.action, orders: v.orders, json });
18300
+ unknownSubcommand("swap", action, [
18301
+ "positions",
18302
+ "orders",
18303
+ "get",
18304
+ "fills",
18305
+ "get-leverage",
18306
+ "place",
18307
+ "cancel",
18308
+ "amend",
18309
+ "close",
18310
+ "leverage",
18311
+ "algo",
18312
+ "batch"
18313
+ ]);
17320
18314
  }
17321
18315
  function handleOptionAlgoCommand(run, subAction, v, json) {
17322
18316
  if (subAction === "place")
@@ -17355,6 +18349,7 @@ function handleOptionAlgoCommand(run, subAction, v, json) {
17355
18349
  ordType: v.ordType,
17356
18350
  json
17357
18351
  });
18352
+ unknownSubcommand("option algo", subAction, ["place", "amend", "cancel", "orders"]);
17358
18353
  }
17359
18354
  function handleOptionCommand(run, action, rest, v, json) {
17360
18355
  if (action === "orders") {
@@ -17405,6 +18400,19 @@ function handleOptionCommand(run, action, rest, v, json) {
17405
18400
  return cmdOptionBatchCancel(run, { orders: v.orders, json });
17406
18401
  if (action === "algo")
17407
18402
  return handleOptionAlgoCommand(run, rest[0], v, json);
18403
+ unknownSubcommand("option", action, [
18404
+ "orders",
18405
+ "get",
18406
+ "positions",
18407
+ "fills",
18408
+ "instruments",
18409
+ "greeks",
18410
+ "place",
18411
+ "cancel",
18412
+ "amend",
18413
+ "batch-cancel",
18414
+ "algo"
18415
+ ]);
17408
18416
  }
17409
18417
  function handleFuturesAlgoCommand(run, subAction, v, json) {
17410
18418
  if (subAction === "trail")
@@ -17460,6 +18468,7 @@ function handleFuturesAlgoCommand(run, subAction, v, json) {
17460
18468
  ordType: v.ordType,
17461
18469
  json
17462
18470
  });
18471
+ unknownSubcommand("futures algo", subAction, ["trail", "place", "amend", "cancel", "orders"]);
17463
18472
  }
17464
18473
  function resolveFuturesOrdersStatus(v) {
17465
18474
  if (v.archive) return "archive";
@@ -17535,6 +18544,20 @@ function handleFuturesCommand(run, action, rest, v, json) {
17535
18544
  return cmdFuturesBatch(run, { action: v.action, orders: v.orders, json });
17536
18545
  if (action === "algo")
17537
18546
  return handleFuturesAlgoCommand(run, rest[0], v, json);
18547
+ unknownSubcommand("futures", action, [
18548
+ "orders",
18549
+ "positions",
18550
+ "fills",
18551
+ "get",
18552
+ "get-leverage",
18553
+ "place",
18554
+ "cancel",
18555
+ "amend",
18556
+ "close",
18557
+ "leverage",
18558
+ "batch",
18559
+ "algo"
18560
+ ]);
17538
18561
  }
17539
18562
  function handleBotGridCommand(run, v, rest, json) {
17540
18563
  const subAction = rest[0];
@@ -17580,6 +18603,20 @@ function handleBotGridCommand(run, v, rest, json) {
17580
18603
  algoClOrdId: v.algoClOrdId,
17581
18604
  json
17582
18605
  });
18606
+ if (subAction === "amend")
18607
+ return cmdGridAmend(run, {
18608
+ algoId: v.algoId,
18609
+ instId: v.instId,
18610
+ maxPx: v.maxPx,
18611
+ minPx: v.minPx,
18612
+ gridNum: v.gridNum,
18613
+ tpTriggerPx: v.tpTriggerPx,
18614
+ slTriggerPx: v.slTriggerPx,
18615
+ tpRatio: v.tpRatio,
18616
+ slRatio: v.slRatio,
18617
+ topUpAmt: v.topUpAmt,
18618
+ json
18619
+ });
17583
18620
  if (subAction === "stop")
17584
18621
  return cmdGridStop(run, {
17585
18622
  algoId: v.algoId,
@@ -17588,6 +18625,7 @@ function handleBotGridCommand(run, v, rest, json) {
17588
18625
  stopType: v.stopType,
17589
18626
  json
17590
18627
  });
18628
+ unknownSubcommand("bot grid", subAction, ["orders", "details", "sub-orders", "create", "amend", "stop"]);
17591
18629
  }
17592
18630
  function handleBotDcaCommand(run, subAction, v, json) {
17593
18631
  const algoOrdType = v.algoOrdType ?? "contract_dca";
@@ -17626,10 +18664,12 @@ function handleBotDcaCommand(run, subAction, v, json) {
17626
18664
  });
17627
18665
  if (subAction === "stop")
17628
18666
  return cmdDcaStop(run, { algoId: v.algoId, algoOrdType, stopType: v.stopType, json });
18667
+ unknownSubcommand("bot dca", subAction, ["orders", "details", "sub-orders", "create", "stop"]);
17629
18668
  }
17630
18669
  function handleBotCommand(run, action, rest, v, json) {
17631
18670
  if (action === "grid") return handleBotGridCommand(run, v, rest, json);
17632
18671
  if (action === "dca") return handleBotDcaCommand(run, rest[0], v, json);
18672
+ unknownSubcommand("bot", action, ["grid", "dca"]);
17633
18673
  }
17634
18674
  function handleEarnCommand(run, submodule, rest, v, json) {
17635
18675
  const action = rest[0];
@@ -17672,6 +18712,82 @@ function handleEarnFlashEarnCommand(run, action, v, json) {
17672
18712
  errorLine("Valid: projects");
17673
18713
  process.exitCode = 1;
17674
18714
  }
18715
+ function handleSmartmoneyCommand(run, action, rest, v, json) {
18716
+ const poolFilters = {
18717
+ sortType: v.sortType,
18718
+ period: v.period,
18719
+ pnl: v.pnl,
18720
+ winRatio: v.winRatio,
18721
+ maxRetreat: v.maxRetreat,
18722
+ asset: v.asset
18723
+ };
18724
+ if (action === "overview")
18725
+ return cmdSmartmoneyOverview(run, {
18726
+ dataVersion: v.dataVersion,
18727
+ ts: v.ts,
18728
+ instType: v.instType,
18729
+ ...poolFilters,
18730
+ lmtNum: v.lmtNum,
18731
+ instCcyList: v.instCcyList,
18732
+ instCcy: v.instCcy,
18733
+ topInstruments: v.topInstruments,
18734
+ json
18735
+ });
18736
+ if (action === "signal")
18737
+ return cmdSmartmoneySignal(run, {
18738
+ instId: v.instId,
18739
+ dataVersion: v.dataVersion,
18740
+ ts: v.ts,
18741
+ ...poolFilters,
18742
+ instCcy: v.instCcy,
18743
+ lmtNum: v.lmtNum,
18744
+ authorIds: v.authorIds,
18745
+ json
18746
+ });
18747
+ if (action === "signal-history") {
18748
+ if (!v.instId) {
18749
+ errorLine("Missing required --instId: okx smartmoney signal-history --instId <id>");
18750
+ process.exitCode = 1;
18751
+ return;
18752
+ }
18753
+ return cmdSmartmoneySignalHistory(run, {
18754
+ instId: v.instId,
18755
+ dataVersion: v.dataVersion,
18756
+ ts: v.ts,
18757
+ granularity: v.granularity,
18758
+ limit: v.limit,
18759
+ ...poolFilters,
18760
+ json
18761
+ });
18762
+ }
18763
+ if (action === "traders")
18764
+ return cmdSmartmoneyTraders(run, {
18765
+ dataVersion: v.dataVersion,
18766
+ ...poolFilters,
18767
+ authorIds: v.authorIds,
18768
+ after: v.after,
18769
+ before: v.before,
18770
+ limit: v.limit,
18771
+ json
18772
+ });
18773
+ if (action === "trader") {
18774
+ if (!v.authorId) {
18775
+ errorLine("Missing required --authorId: okx smartmoney trader --authorId <id>");
18776
+ process.exitCode = 1;
18777
+ return;
18778
+ }
18779
+ return cmdSmartmoneyTraderDetail(run, {
18780
+ authorId: v.authorId,
18781
+ period: v.period,
18782
+ instCcy: v.instCcy,
18783
+ tradeLimit: v.tradeLimit,
18784
+ json
18785
+ });
18786
+ }
18787
+ errorLine(`Unknown smartmoney command: ${action}`);
18788
+ errorLine("Valid: overview, signal, signal-history, traders, trader");
18789
+ process.exitCode = 1;
18790
+ }
17675
18791
  function handleEarnSavingsCommand(run, action, rest, v, json) {
17676
18792
  const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
17677
18793
  if (action === "balance") return cmdEarnSavingsBalance(run, rest[0] ?? v.ccy, json);
@@ -17895,11 +19011,11 @@ async function runDiagnose(v) {
17895
19011
  }
17896
19012
  function printVersion() {
17897
19013
  outputLine(`${CLI_VERSION2} (${GIT_HASH2})`);
17898
- const dohStatus = getDohStatus(void 0, { skipHash: true });
17899
- if (dohStatus.exists) {
17900
- outputLine(`DoH resolver: installed (${dohStatus.platform ?? "unknown"})`);
19014
+ const pilotStatus = getPilotStatus(void 0, { skipHash: true });
19015
+ if (pilotStatus.exists) {
19016
+ outputLine(`Pilot: installed (${pilotStatus.platform ?? "unknown"})`);
17901
19017
  } else {
17902
- outputLine("DoH resolver: not installed");
19018
+ outputLine("Pilot: not installed");
17903
19019
  }
17904
19020
  }
17905
19021
  function routeManagementCommand(module, action, rest, json, v) {
@@ -17912,8 +19028,8 @@ function routeManagementCommand(module, action, rest, json, v) {
17912
19028
  return true;
17913
19029
  }
17914
19030
  if (module === "upgrade") return cmdUpgrade(CLI_VERSION2, { beta: v.beta, check: v.check, force: v.force }, json);
17915
- if (module === "doh") {
17916
- const r = handleDohCommand(action, json, v.force ?? false);
19031
+ if (module === "pilot") {
19032
+ const r = handlePilotCommand(action, json, v.force ?? false);
17917
19033
  return r ?? true;
17918
19034
  }
17919
19035
  if (module === "diagnose") return runDiagnose(v);
@@ -17961,6 +19077,7 @@ async function main() {
17961
19077
  news: () => handleNewsCommand(run, action, rest, v, json),
17962
19078
  bot: () => handleBotCommand(run, action, rest, v, json),
17963
19079
  earn: () => handleEarnCommand(run, action, rest, v, json),
19080
+ smartmoney: () => handleSmartmoneyCommand(run, action, rest, v, json),
17964
19081
  skill: () => handleSkillCommand(run, action, rest, v, json, config)
17965
19082
  };
17966
19083
  const handler = moduleHandlers[module];
@@ -17982,7 +19099,6 @@ export {
17982
19099
  handleBotDcaCommand,
17983
19100
  handleBotGridCommand,
17984
19101
  handleConfigCommand,
17985
- handleDohCommand,
17986
19102
  handleEarnCommand,
17987
19103
  handleEventCommand,
17988
19104
  handleFuturesAlgoCommand,
@@ -17993,8 +19109,10 @@ export {
17993
19109
  handleNewsCommand,
17994
19110
  handleOptionAlgoCommand,
17995
19111
  handleOptionCommand,
19112
+ handlePilotCommand,
17996
19113
  handleSetupCommand,
17997
19114
  handleSkillCommand,
19115
+ handleSmartmoneyCommand,
17998
19116
  handleSpotAlgoCommand,
17999
19117
  handleSpotCommand,
18000
19118
  handleSwapAlgoCommand,