@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 +1314 -196
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +9 -9
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
|
|
896
|
-
function
|
|
897
|
-
if (process.env.
|
|
898
|
-
return process.env.
|
|
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(
|
|
901
|
+
return join(PILOT_BIN_DIR, `okx-pilot${ext}`);
|
|
902
902
|
}
|
|
903
|
-
function
|
|
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 =
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1020
|
+
var PilotManager = class {
|
|
1021
1021
|
opts;
|
|
1022
|
-
//
|
|
1023
|
-
|
|
1024
|
-
|
|
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
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
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
|
|
1034
|
+
* Lazily resolve the Pilot proxy node on the first request.
|
|
1035
1035
|
* Uses cache-first strategy via the resolver.
|
|
1036
1036
|
*/
|
|
1037
|
-
|
|
1038
|
-
if (this.
|
|
1039
|
-
this.
|
|
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 =
|
|
1042
|
+
const result = resolvePilot(hostname);
|
|
1043
1043
|
if (!result.mode) {
|
|
1044
1044
|
this.directUnverified = true;
|
|
1045
1045
|
if (this.opts.verbose) {
|
|
1046
|
-
vlog("
|
|
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("
|
|
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(`
|
|
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.
|
|
1068
|
+
const baseUrl = this.pilotNode ? this.pilotBaseUrl : this.opts.baseUrl;
|
|
1069
1069
|
const result = { baseUrl };
|
|
1070
|
-
if (this.
|
|
1071
|
-
result.dispatcher = this.
|
|
1070
|
+
if (this.pilotAgent) {
|
|
1071
|
+
result.dispatcher = this.pilotAgent;
|
|
1072
1072
|
}
|
|
1073
|
-
if (this.
|
|
1074
|
-
result.userAgent = this.
|
|
1073
|
+
if (this.pilotNode) {
|
|
1074
|
+
result.userAgent = this.pilotUserAgent;
|
|
1075
1075
|
}
|
|
1076
1076
|
return result;
|
|
1077
1077
|
}
|
|
1078
|
-
/** Whether a
|
|
1078
|
+
/** Whether a Pilot proxy node is currently active. */
|
|
1079
1079
|
get isProxyActive() {
|
|
1080
|
-
return this.
|
|
1080
|
+
return this.pilotNode !== null;
|
|
1081
1081
|
}
|
|
1082
1082
|
/** Whether we have already retried after network failure. */
|
|
1083
1083
|
get hasRetried() {
|
|
1084
|
-
return this.
|
|
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.
|
|
1092
|
-
this.
|
|
1093
|
-
const failedIp = this.
|
|
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.
|
|
1096
|
-
this.
|
|
1097
|
-
this.
|
|
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 ? `
|
|
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
|
|
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.
|
|
1106
|
+
this.pilotRetried = false;
|
|
1107
1107
|
return true;
|
|
1108
1108
|
}
|
|
1109
1109
|
} catch {
|
|
1110
1110
|
}
|
|
1111
1111
|
if (this.opts.verbose) {
|
|
1112
|
-
vlog("
|
|
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.
|
|
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("
|
|
1131
|
+
vlog("Pilot: direct connection succeeded, cached mode=direct");
|
|
1132
1132
|
}
|
|
1133
1133
|
}
|
|
1134
|
-
/** User-Agent for
|
|
1135
|
-
get
|
|
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
|
|
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.
|
|
1147
|
-
this.
|
|
1146
|
+
this.pilotNode = node;
|
|
1147
|
+
this.pilotBaseUrl = `${protocol}//${node.host}`;
|
|
1148
1148
|
const nodeIpIsRealIp = !!isIP(node.ip);
|
|
1149
|
-
this.
|
|
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(`
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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,
|
|
1636
|
+
* Inherits proxy, timeout, Pilot, and verbose capabilities from the client.
|
|
1634
1637
|
*/
|
|
1635
1638
|
async publicGetBinary(path42, query, opts) {
|
|
1636
|
-
this.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
1747
|
+
vlog2(`Network failure, refreshing Pilot: ${cause}`);
|
|
1743
1748
|
}
|
|
1744
|
-
const shouldRetry = await this.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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]
|
|
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-
|
|
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"
|
|
4267
|
-
description: "1
|
|
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: {
|
|
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"
|
|
6781
|
-
description: "
|
|
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
|
|
6792
|
-
lever:
|
|
6793
|
-
mgnMode
|
|
6794
|
-
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
|
|
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.
|
|
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/
|
|
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
|
-
|
|
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
|
|
10145
|
-
const resolvedPath = binaryPath ??
|
|
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.
|
|
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
|
|
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
|
|
10295
|
-
const resolvedPath = binaryPath ??
|
|
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 ? "
|
|
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
|
|
11261
|
-
section("
|
|
11262
|
-
const local =
|
|
11891
|
+
async function checkPilot(report) {
|
|
11892
|
+
section("Pilot");
|
|
11893
|
+
const local = getPilotStatus();
|
|
11263
11894
|
if (!local.exists) {
|
|
11264
|
-
fail("
|
|
11265
|
-
"Run: okx
|
|
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("
|
|
11899
|
+
report.add("pilot_binary", "not installed");
|
|
11269
11900
|
return;
|
|
11270
11901
|
}
|
|
11271
|
-
ok("
|
|
11272
|
-
report.add("
|
|
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("
|
|
11276
|
-
report.add("
|
|
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("
|
|
11279
|
-
report.add("
|
|
11909
|
+
ok("Pilot checksum", `match (${cdnChecksum.source})`);
|
|
11910
|
+
report.add("pilot_checksum", `match (${cdnChecksum.source})`);
|
|
11280
11911
|
} else {
|
|
11281
|
-
warn("
|
|
11282
|
-
report.add("
|
|
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("
|
|
11288
|
-
report.add("
|
|
11918
|
+
ok("Pilot mode", cacheEntry.mode);
|
|
11919
|
+
report.add("pilot_mode", cacheEntry.mode);
|
|
11289
11920
|
} else {
|
|
11290
|
-
ok("
|
|
11291
|
-
report.add("
|
|
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("
|
|
11295
|
-
report.add("
|
|
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
|
|
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 <
|
|
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 <
|
|
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 <
|
|
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
|
-
"<
|
|
12236
|
+
"<indicator> <instId>": {
|
|
11581
12237
|
toolName: "market_get_indicator",
|
|
11582
|
-
usage: "okx market indicator <
|
|
11583
|
-
description: "Get indicator values for an instrument (e.g. okx market indicator BTC-USDT-SWAP
|
|
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 <
|
|
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 <
|
|
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
|
|
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
|
-
// ──
|
|
12317
|
-
|
|
12318
|
-
description: "Manage
|
|
13013
|
+
// ── pilot ──────────────────────────────────────────────────────────────────
|
|
13014
|
+
pilot: {
|
|
13015
|
+
description: "Manage Pilot proxy resolver binary",
|
|
12319
13016
|
commands: {
|
|
12320
13017
|
status: {
|
|
12321
13018
|
toolName: null,
|
|
12322
|
-
usage: "okx
|
|
12323
|
-
description: "Show
|
|
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
|
|
12328
|
-
description: "Download or update the
|
|
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
|
|
12333
|
-
description: "Remove the
|
|
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(
|
|
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/
|
|
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("
|
|
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
|
|
16348
|
-
const local =
|
|
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
|
|
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
|
|
17318
|
+
outputLine(" Installing Pilot...");
|
|
16396
17319
|
}
|
|
16397
|
-
const result = await
|
|
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
|
|
17329
|
+
outputLine(` \u2713 Pilot installed successfully (${result.source ?? ""})`);
|
|
16407
17330
|
} else if (result.status === "up-to-date") {
|
|
16408
|
-
outputLine(" \u2713
|
|
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
|
|
16417
|
-
const local =
|
|
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("
|
|
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
|
|
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 =
|
|
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("
|
|
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 ? "
|
|
16916
|
-
function
|
|
16917
|
-
if (action === "status") return
|
|
16918
|
-
if (action === "install") return
|
|
16919
|
-
if (action === "remove") return
|
|
16920
|
-
errorLine(`Unknown
|
|
16921
|
-
errorLine("Usage: okx
|
|
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
|
-
|
|
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
|
|
17899
|
-
if (
|
|
17900
|
-
outputLine(`
|
|
19014
|
+
const pilotStatus = getPilotStatus(void 0, { skipHash: true });
|
|
19015
|
+
if (pilotStatus.exists) {
|
|
19016
|
+
outputLine(`Pilot: installed (${pilotStatus.platform ?? "unknown"})`);
|
|
17901
19017
|
} else {
|
|
17902
|
-
outputLine("
|
|
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 === "
|
|
17916
|
-
const r =
|
|
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,
|