@okx_ai/okx-trade-cli 1.3.3-beta.1 → 1.3.3-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 +258 -233
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -880,32 +880,29 @@ import * as path3 from "path";
|
|
|
880
880
|
import * as os3 from "os";
|
|
881
881
|
import { execFileSync } from "child_process";
|
|
882
882
|
import {
|
|
883
|
-
createWriteStream as createWriteStream3,
|
|
884
883
|
mkdirSync as mkdirSync9,
|
|
885
884
|
chmodSync as chmodSync2,
|
|
886
885
|
existsSync as existsSync7,
|
|
887
|
-
unlinkSync as
|
|
886
|
+
unlinkSync as unlinkSync5,
|
|
888
887
|
renameSync as renameSync4
|
|
889
888
|
} from "fs";
|
|
890
889
|
import { homedir as homedir9, platform as platform2 } from "os";
|
|
891
890
|
import { join as join11, dirname as dirname7 } from "path";
|
|
892
|
-
import {
|
|
893
|
-
import { get as
|
|
891
|
+
import { createWriteStream as createWriteStream2, unlinkSync as unlinkSync3 } from "fs";
|
|
892
|
+
import { get as httpsGet } from "https";
|
|
893
|
+
import { get as httpGet } from "http";
|
|
894
894
|
import {
|
|
895
895
|
readFileSync as readFileSync7,
|
|
896
|
-
createWriteStream as createWriteStream2,
|
|
897
896
|
mkdirSync as mkdirSync8,
|
|
898
897
|
chmodSync,
|
|
899
898
|
existsSync as existsSync6,
|
|
900
|
-
unlinkSync as
|
|
899
|
+
unlinkSync as unlinkSync4,
|
|
901
900
|
renameSync as renameSync3
|
|
902
901
|
} from "fs";
|
|
903
902
|
import { createHash } from "crypto";
|
|
904
903
|
import { homedir as homedir8, platform, arch } from "os";
|
|
905
904
|
import { join as join10, dirname as dirname6 } from "path";
|
|
906
|
-
import {
|
|
907
|
-
import { get as httpGet } from "http";
|
|
908
|
-
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, unlinkSync as unlinkSync5, existsSync as existsSync8 } from "fs";
|
|
905
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, unlinkSync as unlinkSync6, existsSync as existsSync8 } from "fs";
|
|
909
906
|
import { join as join12 } from "path";
|
|
910
907
|
import { homedir as homedir10 } from "os";
|
|
911
908
|
var EXEC_TIMEOUT_MS = 3e4;
|
|
@@ -1634,7 +1631,7 @@ var OkxRestClient = class _OkxRestClient {
|
|
|
1634
1631
|
headers.set("OK-ACCESS-TIMESTAMP", timestamp);
|
|
1635
1632
|
}
|
|
1636
1633
|
throwOkxError(code, msg, reqConfig, traceId) {
|
|
1637
|
-
const message = msg
|
|
1634
|
+
const message = msg && msg.trim() !== "" ? msg : `OKX API rejected request (code ${code}).`;
|
|
1638
1635
|
const endpoint = `${reqConfig.method} ${reqConfig.path}`;
|
|
1639
1636
|
if (code === "50111" || code === "50112" || code === "50113") {
|
|
1640
1637
|
throw new AuthenticationError(
|
|
@@ -6999,31 +6996,31 @@ var SIGNAL_POOL_FILTER_PROPS = {
|
|
|
6999
6996
|
type: "string",
|
|
7000
6997
|
enum: PERIOD_DAYS,
|
|
7001
6998
|
default: "7",
|
|
7002
|
-
description: 'Lookback window in days.
|
|
6999
|
+
description: 'Lookback window in days. One of `"3"` / `"7"` / `"30"` / `"90"`. Drives capability metrics (avgLongWinRate / avgShortWinRate) and the `winRateTier` filter. Does NOT affect signal fields (which always use the latest snapshot).'
|
|
7003
7000
|
},
|
|
7004
7001
|
pnlTier: {
|
|
7005
7002
|
type: "string",
|
|
7006
7003
|
enum: ["PNL_ANY", "PNL_TOP50", "PNL_TOP20", "PNL_TOP5"],
|
|
7007
7004
|
default: "PNL_ANY",
|
|
7008
|
-
description: "PnL percentile gate applied on top of `sortBy`.
|
|
7005
|
+
description: "PnL percentile gate applied on top of `sortBy`. Naming: `TOP{N}` = top N% percentile (NOT an absolute PnL value). PNL_ANY = no filter; PNL_TOP50 = PnL \u2265 P50 (median); PNL_TOP20 = \u2265 P80; PNL_TOP5 = \u2265 P95. PnL distribution is long-tailed \u2014 use percentile, not absolute thresholds."
|
|
7009
7006
|
},
|
|
7010
7007
|
winRateTier: {
|
|
7011
7008
|
type: "string",
|
|
7012
7009
|
enum: ["WR_ANY", "WR_GE_50", "WR_GE_80"],
|
|
7013
7010
|
default: "WR_ANY",
|
|
7014
|
-
description: "Minimum win-rate gate (
|
|
7011
|
+
description: "Minimum win-rate gate (absolute thresholds, NOT percentile). Naming: `GE_{N}` = career win-rate \u2265 N% \u2014 distinct from `pnlTier`/`aumTier` `TOP{N}` which are percentiles. WR_ANY = no filter; WR_GE_50 = \u2265 50%; WR_GE_80 = \u2265 80%."
|
|
7015
7012
|
},
|
|
7016
7013
|
maxDrawdownTier: {
|
|
7017
7014
|
type: "string",
|
|
7018
7015
|
enum: ["MR_ANY", "MR_LE_20", "MR_LE_50"],
|
|
7019
7016
|
default: "MR_ANY",
|
|
7020
|
-
description: "Maximum-drawdown gate (
|
|
7017
|
+
description: "Maximum-drawdown gate (absolute thresholds, NOT percentile; smaller drawdown = lower risk). Naming: `LE_{N}` = drawdown \u2264 N% \u2014 distinct from `pnlTier`/`aumTier` `TOP{N}` which are percentiles. MR_ANY = no filter; MR_LE_20 = drawdown \u2264 20%; MR_LE_50 = \u2264 50%."
|
|
7021
7018
|
},
|
|
7022
7019
|
aumTier: {
|
|
7023
7020
|
type: "string",
|
|
7024
7021
|
enum: ["AUM_ANY", "AUM_TOP50", "AUM_TOP20", "AUM_TOP5"],
|
|
7025
7022
|
default: "AUM_ANY",
|
|
7026
|
-
description: "AUM (Assets Under Management) percentile gate.
|
|
7023
|
+
description: "AUM (Assets Under Management) percentile gate. Naming: `TOP{N}` = top N% percentile (NOT an absolute USD amount). AUM_ANY = no filter; AUM_TOP50 = AUM \u2265 P50; AUM_TOP20 = \u2265 P80; AUM_TOP5 = \u2265 P95. AUM is long-tailed \u2014 use percentile, not absolute USD."
|
|
7027
7024
|
}
|
|
7028
7025
|
};
|
|
7029
7026
|
var LEADERBOARD_POOL_FILTER_PROPS = {
|
|
@@ -7031,29 +7028,29 @@ var LEADERBOARD_POOL_FILTER_PROPS = {
|
|
|
7031
7028
|
type: "string",
|
|
7032
7029
|
enum: ["pnl", "pnlRatio"],
|
|
7033
7030
|
default: "pnl",
|
|
7034
|
-
description:
|
|
7031
|
+
description: 'Required. Leaderboard sort key. `pnl` = absolute USD profit; `pnlRatio` = percentage return. Default `"pnl"`.'
|
|
7035
7032
|
},
|
|
7036
7033
|
period: {
|
|
7037
7034
|
type: "string",
|
|
7038
7035
|
enum: PERIOD_DAYS,
|
|
7039
7036
|
default: "90",
|
|
7040
|
-
description: 'Performance lookback window in days.
|
|
7037
|
+
description: 'Required. Performance lookback window in days. One of `"3"` / `"7"` / `"30"` / `"90"`. Default `"90"` (matches leaderboard UI). Filters AND ranks traders by their PnL over that window.'
|
|
7041
7038
|
},
|
|
7042
7039
|
minPnl: {
|
|
7043
7040
|
type: "string",
|
|
7044
|
-
description: 'Minimum absolute PnL in USD
|
|
7041
|
+
description: 'Minimum absolute PnL in USD as a string, e.g. `"10000"` \u2192 traders with PnL \u2265 $10,000. Numeric threshold \u2014 distinct from the signal-side `pnlTier` percentile enum.'
|
|
7045
7042
|
},
|
|
7046
7043
|
minWinRate: {
|
|
7047
7044
|
type: "string",
|
|
7048
|
-
description: 'Minimum win-rate as decimal in 0~1 range
|
|
7045
|
+
description: 'Minimum win-rate as a decimal in 0~1 range, passed as a string, e.g. `"0.8"` \u2192 traders with win-rate \u2265 80%. Numeric threshold \u2014 distinct from the signal-side `winRateTier` enum.'
|
|
7049
7046
|
},
|
|
7050
7047
|
maxDrawdown: {
|
|
7051
7048
|
type: "string",
|
|
7052
|
-
description: 'Maximum drawdown as decimal
|
|
7049
|
+
description: 'Maximum drawdown as a decimal, passed as a string, e.g. `"0.1"` \u2192 traders with drawdown \u2264 10%. Lower = lower risk. Numeric threshold \u2014 distinct from the signal-side `maxDrawdownTier` enum.'
|
|
7053
7050
|
},
|
|
7054
7051
|
minAum: {
|
|
7055
7052
|
type: "string",
|
|
7056
|
-
description: 'Minimum AUM (Assets Under Management) in USD
|
|
7053
|
+
description: 'Minimum AUM (Assets Under Management) in USD as a string, e.g. `"1000"` \u2192 traders with AUM \u2265 $1,000. Numeric threshold \u2014 distinct from the signal-side `aumTier` percentile enum.'
|
|
7057
7054
|
}
|
|
7058
7055
|
};
|
|
7059
7056
|
var LEADERBOARD_FILTER_UPSTREAM_NAMES = {
|
|
@@ -7065,19 +7062,25 @@ var LEADERBOARD_FILTER_UPSTREAM_NAMES = {
|
|
|
7065
7062
|
minAum: "asset"
|
|
7066
7063
|
};
|
|
7067
7064
|
function readPoolFilters(args) {
|
|
7065
|
+
assertPoolFilterEnums(args, LEADERBOARD_POOL_FILTER_PROPS);
|
|
7068
7066
|
const result = {};
|
|
7069
7067
|
for (const [publicKey, upstreamKey] of Object.entries(LEADERBOARD_FILTER_UPSTREAM_NAMES)) {
|
|
7070
7068
|
const val = readString(args, publicKey);
|
|
7071
7069
|
if (val !== void 0 && val !== "") result[upstreamKey] = val;
|
|
7072
7070
|
}
|
|
7071
|
+
if (result.sortBy === void 0) result.sortBy = "pnl";
|
|
7072
|
+
if (result.period === void 0) result.period = "90";
|
|
7073
7073
|
return result;
|
|
7074
7074
|
}
|
|
7075
7075
|
function readSignalPoolFilters(args) {
|
|
7076
|
+
assertPoolFilterEnums(args, SIGNAL_POOL_FILTER_PROPS);
|
|
7076
7077
|
const result = {};
|
|
7077
7078
|
for (const key of Object.keys(SIGNAL_POOL_FILTER_PROPS)) {
|
|
7078
7079
|
const val = readString(args, key);
|
|
7079
7080
|
if (val) result[key] = val;
|
|
7080
7081
|
}
|
|
7082
|
+
if (result.sortBy === void 0) result.sortBy = "pnl";
|
|
7083
|
+
if (result.period === void 0) result.period = "7";
|
|
7081
7084
|
return result;
|
|
7082
7085
|
}
|
|
7083
7086
|
function extractLeaderboardEnvelope(data) {
|
|
@@ -7093,7 +7096,7 @@ function extractLeaderboardEnvelope(data) {
|
|
|
7093
7096
|
function deriveDirection(posSide, pos) {
|
|
7094
7097
|
if (posSide === "long") return "long";
|
|
7095
7098
|
if (posSide === "short") return "short";
|
|
7096
|
-
if (posSide === "both" && typeof pos === "string" && pos !== "") {
|
|
7099
|
+
if ((posSide === "net" || posSide === "both") && typeof pos === "string" && pos !== "") {
|
|
7097
7100
|
const n = Number(pos);
|
|
7098
7101
|
if (Number.isFinite(n) && n !== 0) return n > 0 ? "long" : "short";
|
|
7099
7102
|
}
|
|
@@ -7130,6 +7133,22 @@ function extractBaseCcy(instId) {
|
|
|
7130
7133
|
function actionableError(message, hint) {
|
|
7131
7134
|
return new ValidationError(`${message} ${hint}`);
|
|
7132
7135
|
}
|
|
7136
|
+
function assertEnum2(args, key, allowed) {
|
|
7137
|
+
const val = readString(args, key);
|
|
7138
|
+
if (val === void 0 || val === "") return;
|
|
7139
|
+
if (!allowed.includes(val)) {
|
|
7140
|
+
throw actionableError(
|
|
7141
|
+
`Invalid value for "${key}": ${JSON.stringify(val)}.`,
|
|
7142
|
+
`Allowed values: ${allowed.map((v) => JSON.stringify(v)).join(", ")}.`
|
|
7143
|
+
);
|
|
7144
|
+
}
|
|
7145
|
+
}
|
|
7146
|
+
function assertPoolFilterEnums(args, props) {
|
|
7147
|
+
for (const [key, spec] of Object.entries(props)) {
|
|
7148
|
+
const enumList = spec.enum;
|
|
7149
|
+
if (Array.isArray(enumList)) assertEnum2(args, key, enumList);
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7133
7152
|
function readArrayAsCsv(args, key) {
|
|
7134
7153
|
const arr = readStringArray(args, key);
|
|
7135
7154
|
if (!arr || arr.length === 0) return void 0;
|
|
@@ -7206,21 +7225,33 @@ var SIGNAL_ITEM_PROPS = {
|
|
|
7206
7225
|
type: "object",
|
|
7207
7226
|
description: "Notional / capital-flow group.",
|
|
7208
7227
|
properties: {
|
|
7209
|
-
longNotionalUsdt: {
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7228
|
+
longNotionalUsdt: {
|
|
7229
|
+
type: "string",
|
|
7230
|
+
description: "Sum of long-side notional in USDT, weighted by each trader's ENTRY PRICE (price_avg), not mark price. Moves only when positions are opened / closed / scaled \u2014 stays constant when positions are unchanged."
|
|
7231
|
+
},
|
|
7232
|
+
shortNotionalUsdt: {
|
|
7233
|
+
type: "string",
|
|
7234
|
+
description: "Sum of short-side notional in USDT, weighted by each trader's ENTRY PRICE (price_avg), not mark price. Moves only when positions are opened / closed / scaled \u2014 stays constant when positions are unchanged."
|
|
7235
|
+
},
|
|
7236
|
+
netNotionalUsdt: {
|
|
7237
|
+
type: "string",
|
|
7238
|
+
description: "Net directional notional in USDT = long \u2212 short. Weighted by each trader's ENTRY PRICE (price_avg), not mark price \u2014 reflects position scaling, not underlying price movement."
|
|
7239
|
+
},
|
|
7240
|
+
totalNotionalUsdt: {
|
|
7241
|
+
type: "string",
|
|
7242
|
+
description: "Gross notional in USDT = long + short. Weighted by each trader's ENTRY PRICE (price_avg), not mark price \u2014 reflects position scaling (open / close / add), not underlying price movement. Stays constant across buckets when traders hold positions unchanged."
|
|
7243
|
+
},
|
|
7213
7244
|
totalNotionalVs24h: {
|
|
7214
7245
|
type: "string",
|
|
7215
7246
|
description: "Capital-flow change ratio vs 24h: (curr \u2212 hist_24h) / hist_24h. Positive = smart money adding exposure; negative = retreating. NULL when hist=0."
|
|
7216
7247
|
},
|
|
7217
7248
|
smartMoneyLongAvgEntry: {
|
|
7218
7249
|
type: "string",
|
|
7219
|
-
description:
|
|
7250
|
+
description: 'Long-side notional-weighted average entry price (USDT). Empty string `""` when no long. Compare to current price to judge whether following the longs is cheap/expensive now.'
|
|
7220
7251
|
},
|
|
7221
7252
|
smartMoneyShortAvgEntry: {
|
|
7222
7253
|
type: "string",
|
|
7223
|
-
description:
|
|
7254
|
+
description: 'Short-side notional-weighted average entry price (USDT). Empty string `""` when no short.'
|
|
7224
7255
|
}
|
|
7225
7256
|
}
|
|
7226
7257
|
},
|
|
@@ -7232,14 +7263,17 @@ var SIGNAL_ITEM_PROPS = {
|
|
|
7232
7263
|
longRatioVs24h: { type: "string", description: "longRatio \u2212 hist_24h.longRatio. NULL when no hist." },
|
|
7233
7264
|
longRatioVs7d: { type: "string", description: "longRatio \u2212 hist_7d.longRatio. NULL when no hist." },
|
|
7234
7265
|
longRatio: { type: "string", description: "Headcount long ratio = longTraders / tradersWithPosition. NULL when no traders." },
|
|
7235
|
-
shortRatio: {
|
|
7266
|
+
shortRatio: {
|
|
7267
|
+
type: "string",
|
|
7268
|
+
description: "Headcount short ratio = shortTraders / tradersWithPosition. NULL when no traders."
|
|
7269
|
+
},
|
|
7236
7270
|
weightedLongRatio: {
|
|
7237
7271
|
type: "string",
|
|
7238
|
-
description: "Notional-weighted long ratio = \u03A3(long_notional) / \u03A3(notional). NULL when no notional."
|
|
7272
|
+
description: "Notional-weighted long ratio = \u03A3(long_notional) / \u03A3(notional). Notional uses each trader's ENTRY PRICE (price_avg), not mark price \u2014 ratio shifts only when positions are scaled. NULL when no notional."
|
|
7239
7273
|
},
|
|
7240
7274
|
weightedShortRatio: {
|
|
7241
7275
|
type: "string",
|
|
7242
|
-
description: "Notional-weighted short ratio = \u03A3(short_notional) / \u03A3(notional). NULL when no notional."
|
|
7276
|
+
description: "Notional-weighted short ratio = \u03A3(short_notional) / \u03A3(notional). Notional uses each trader's ENTRY PRICE (price_avg), not mark price. NULL when no notional."
|
|
7243
7277
|
}
|
|
7244
7278
|
}
|
|
7245
7279
|
},
|
|
@@ -7266,15 +7300,15 @@ var SIGNAL_HISTORY_ITEM_PROPS = {
|
|
|
7266
7300
|
},
|
|
7267
7301
|
shortRatio: {
|
|
7268
7302
|
type: "string",
|
|
7269
|
-
description: "Headcount short ratio at this bucket =
|
|
7303
|
+
description: "Headcount short ratio at this bucket = shortTraders / tradersWithPosition. Decimal 0~1."
|
|
7270
7304
|
},
|
|
7271
7305
|
weightedLongRatio: {
|
|
7272
7306
|
type: "string",
|
|
7273
|
-
description: "Notional-weighted long ratio at this bucket. Decimal 0~1."
|
|
7307
|
+
description: "Notional-weighted long ratio at this bucket = \u03A3(long_notional) / \u03A3(notional). Decimal 0~1. Notional uses each trader's ENTRY PRICE (price_avg), not mark price \u2014 ratio shifts only when positions are scaled."
|
|
7274
7308
|
},
|
|
7275
7309
|
weightedShortRatio: {
|
|
7276
7310
|
type: "string",
|
|
7277
|
-
description: "Notional-weighted short ratio at this bucket. Decimal 0~1."
|
|
7311
|
+
description: "Notional-weighted short ratio at this bucket = \u03A3(short_notional) / \u03A3(notional). Decimal 0~1. Notional uses each trader's ENTRY PRICE (price_avg), not mark price."
|
|
7278
7312
|
},
|
|
7279
7313
|
longTraders: {
|
|
7280
7314
|
type: "integer",
|
|
@@ -7290,11 +7324,11 @@ var SIGNAL_HISTORY_ITEM_PROPS = {
|
|
|
7290
7324
|
},
|
|
7291
7325
|
netNotionalUsdt: {
|
|
7292
7326
|
type: "string",
|
|
7293
|
-
description: "Net directional notional in USDT at this bucket = long notional \u2212 short notional."
|
|
7327
|
+
description: "Net directional notional in USDT at this bucket = long notional \u2212 short notional. Weighted by each trader's ENTRY PRICE (price_avg), not mark price \u2014 reflects position scaling, not underlying price movement."
|
|
7294
7328
|
},
|
|
7295
7329
|
totalNotionalUsdt: {
|
|
7296
7330
|
type: "string",
|
|
7297
|
-
description: "Gross notional in USDT at this bucket = long notional + short notional.
|
|
7331
|
+
description: "Gross notional in USDT at this bucket = long notional + short notional. Weighted by each trader's ENTRY PRICE (price_avg), not mark price \u2014 tracks capital deployed (rising = adding, falling = retreating). Stays constant across buckets when traders hold positions unchanged."
|
|
7298
7332
|
},
|
|
7299
7333
|
tradersQualified: { type: "integer", description: "Pool size after applying tier filters (includes traders without a position)." },
|
|
7300
7334
|
dataVersion: { type: "string", description: "Snapshot version key in `yyyyMMddHH` UTC (10-digit, e.g. `2026042820`)." }
|
|
@@ -7325,16 +7359,16 @@ function registerSmartmoneyTools() {
|
|
|
7325
7359
|
properties: {
|
|
7326
7360
|
updateTime: {
|
|
7327
7361
|
type: "string",
|
|
7328
|
-
description: 'Snapshot version key
|
|
7362
|
+
description: 'Snapshot version key \u2014 12-digit `yyyyMMddHHmm` (UTC+8) as a string, e.g. `"202604301815"`. Omit to query the latest snapshot (refreshed every ~5 min).'
|
|
7329
7363
|
},
|
|
7330
7364
|
...LEADERBOARD_POOL_FILTER_PROPS,
|
|
7331
7365
|
after: {
|
|
7332
7366
|
type: "string",
|
|
7333
|
-
description:
|
|
7367
|
+
description: 'Pagination cursor (older page) \u2014 pass the `authorId` of the last item from the previous page as a string, e.g. `"872913470357110787"`. Cursor anchors on `authorId` while preserving the current `sortBy` order.'
|
|
7334
7368
|
},
|
|
7335
7369
|
before: {
|
|
7336
7370
|
type: "string",
|
|
7337
|
-
description:
|
|
7371
|
+
description: 'Pagination cursor (newer page) \u2014 pass the `authorId` of the first item from the previous page as a string, e.g. `"872913470357110787"`. Cursor anchors on `authorId` while preserving the current `sortBy` order.'
|
|
7338
7372
|
},
|
|
7339
7373
|
limit: {
|
|
7340
7374
|
type: "integer",
|
|
@@ -7343,7 +7377,8 @@ function registerSmartmoneyTools() {
|
|
|
7343
7377
|
default: 10,
|
|
7344
7378
|
description: "Max results per page (default 10, max 100)."
|
|
7345
7379
|
}
|
|
7346
|
-
}
|
|
7380
|
+
},
|
|
7381
|
+
required: ["sortBy", "period"]
|
|
7347
7382
|
},
|
|
7348
7383
|
handler: async (rawArgs, context) => {
|
|
7349
7384
|
const args = asRecord(rawArgs);
|
|
@@ -7393,17 +7428,25 @@ function registerSmartmoneyTools() {
|
|
|
7393
7428
|
minItems: 1,
|
|
7394
7429
|
description: 'Trader IDs to look up, e.g. `["1001", "1002"]`. Required.'
|
|
7395
7430
|
},
|
|
7431
|
+
sortBy: {
|
|
7432
|
+
type: "string",
|
|
7433
|
+
enum: ["pnl", "pnlRatio"],
|
|
7434
|
+
default: "pnl",
|
|
7435
|
+
description: 'Required. Result sort key. `pnl` = absolute USD profit; `pnlRatio` = percentage return. Default `"pnl"`.'
|
|
7436
|
+
},
|
|
7396
7437
|
period: {
|
|
7397
7438
|
type: "string",
|
|
7398
7439
|
enum: PERIOD_DAYS,
|
|
7399
7440
|
default: "90",
|
|
7400
|
-
description: 'Performance lookback window in days.
|
|
7441
|
+
description: 'Required. Performance lookback window in days. One of `"3"` / `"7"` / `"30"` / `"90"`. Default `"90"`.'
|
|
7401
7442
|
}
|
|
7402
7443
|
},
|
|
7403
|
-
required: ["authorIds"]
|
|
7444
|
+
required: ["authorIds", "sortBy", "period"]
|
|
7404
7445
|
},
|
|
7405
7446
|
handler: async (rawArgs, context) => {
|
|
7406
7447
|
const args = asRecord(rawArgs);
|
|
7448
|
+
assertEnum2(args, "sortBy", ["pnl", "pnlRatio"]);
|
|
7449
|
+
assertEnum2(args, "period", PERIOD_DAYS);
|
|
7407
7450
|
const authorIds = readArrayAsCsv(args, "authorIds");
|
|
7408
7451
|
if (!authorIds) {
|
|
7409
7452
|
throw actionableError(
|
|
@@ -7415,7 +7458,10 @@ function registerSmartmoneyTools() {
|
|
|
7415
7458
|
PATH_LEADERBOARD,
|
|
7416
7459
|
compactObject({
|
|
7417
7460
|
authorIds,
|
|
7418
|
-
|
|
7461
|
+
// Apply schema defaults explicitly so behavior does not depend on backend defaults
|
|
7462
|
+
// (CLI bypasses MCP `required` validation, so handler is the only deterministic layer).
|
|
7463
|
+
sortBy: readString(args, "sortBy") ?? "pnl",
|
|
7464
|
+
period: readString(args, "period") ?? "90"
|
|
7419
7465
|
}),
|
|
7420
7466
|
publicRateLimit("smartmoney_get_performance_by_trader", SMARTMONEY_RPS)
|
|
7421
7467
|
);
|
|
@@ -7447,12 +7493,12 @@ function registerSmartmoneyTools() {
|
|
|
7447
7493
|
},
|
|
7448
7494
|
posSide: {
|
|
7449
7495
|
type: "string",
|
|
7450
|
-
description: "Raw upstream position direction. `long` = long-side position (buy-to-open); `short` = short-side position (sell-to-open); `both` = net/one-way position mode where the sign of `pos` encodes direction. Prefer the derived `direction` field below for agent logic."
|
|
7496
|
+
description: "Raw upstream position direction. `long` = long-side position (buy-to-open); `short` = short-side position (sell-to-open); `net` (or legacy `both`) = net/one-way position mode where the sign of `pos` encodes direction. Prefer the derived `direction` field below for agent logic."
|
|
7451
7497
|
},
|
|
7452
7498
|
direction: {
|
|
7453
7499
|
type: "string",
|
|
7454
7500
|
enum: ["long", "short"],
|
|
7455
|
-
description: 'Derived clean direction (`long` | `short`) \u2014 handler computes this from `posSide` + sign of `pos` so agents do not have to branch on the `posSide="
|
|
7501
|
+
description: 'Derived clean direction (`long` | `short`) \u2014 handler computes this from `posSide` + sign of `pos` so agents do not have to branch on the `posSide="net"` net-mode case.'
|
|
7456
7502
|
},
|
|
7457
7503
|
posCcy: { type: "string", description: 'Position currency \u2014 the asset being held, e.g. "BTC".' },
|
|
7458
7504
|
quoteCcy: { type: "string", description: 'Quote currency the position is priced/settled in, e.g. "USDT".' },
|
|
@@ -7600,11 +7646,11 @@ function registerSmartmoneyTools() {
|
|
|
7600
7646
|
},
|
|
7601
7647
|
after: {
|
|
7602
7648
|
type: "string",
|
|
7603
|
-
description:
|
|
7649
|
+
description: 'Pagination cursor (older) \u2014 returns positions with `posId` smaller than this value. Pass the `posId` as a string, e.g. `"872913470357110787"`.'
|
|
7604
7650
|
},
|
|
7605
7651
|
before: {
|
|
7606
7652
|
type: "string",
|
|
7607
|
-
description:
|
|
7653
|
+
description: 'Pagination cursor (newer) \u2014 returns positions with `posId` greater than this value. Pass the `posId` as a string, e.g. `"872913470357110787"`.'
|
|
7608
7654
|
},
|
|
7609
7655
|
limit: {
|
|
7610
7656
|
type: "integer",
|
|
@@ -7718,11 +7764,11 @@ function registerSmartmoneyTools() {
|
|
|
7718
7764
|
},
|
|
7719
7765
|
after: {
|
|
7720
7766
|
type: "string",
|
|
7721
|
-
description:
|
|
7767
|
+
description: 'Pagination cursor (older) \u2014 returns trades with `ordId` smaller than this value. Pass the `ordId` as a string, e.g. `"872913470357110787"`.'
|
|
7722
7768
|
},
|
|
7723
7769
|
before: {
|
|
7724
7770
|
type: "string",
|
|
7725
|
-
description:
|
|
7771
|
+
description: 'Pagination cursor (newer) \u2014 returns trades with `ordId` greater than this value. Pass the `ordId` as a string, e.g. `"872913470357110787"`.'
|
|
7726
7772
|
},
|
|
7727
7773
|
limit: {
|
|
7728
7774
|
type: "integer",
|
|
@@ -7818,7 +7864,7 @@ function registerSmartmoneyTools() {
|
|
|
7818
7864
|
{
|
|
7819
7865
|
name: "smartmoney_get_signal_overview_by_filter",
|
|
7820
7866
|
module: "smartmoney",
|
|
7821
|
-
description: "Multi-asset smart-money consensus signals (long/short ratio, weighted entry, capital flow, deltas vs 1h/24h/7d), aggregated over a tier-filtered trader pool (PnL / win-rate / drawdown / AUM). Pick instruments via `topInstruments` OR `instCcyList` \u2014 exactly one. Snapshot time auto-resolved to current hour. Use when: latest cross-asset consensus from a criteria-defined pool. See also: `smartmoney_get_signal_overview_by_trader` (restrict pool to specific traders), `smartmoney_get_signal_trend_by_filter` (time-series instead of latest snapshot).",
|
|
7867
|
+
description: "Multi-asset smart-money consensus signals (long/short ratio, weighted entry, capital flow, deltas vs 1h/24h/7d), aggregated over a tier-filtered trader pool (PnL / win-rate / drawdown / AUM). Pick instruments via `topInstruments` OR `instCcyList` \u2014 exactly one. Snapshot time auto-resolved to current hour. **Linear (USDT/USDS-margined) contracts only \u2014 coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions are excluded by upstream and silently omitted from the aggregation.** Use when: latest cross-asset consensus from a criteria-defined pool. See also: `smartmoney_get_signal_overview_by_trader` (restrict pool to specific traders), `smartmoney_get_signal_trend_by_filter` (time-series instead of latest snapshot).",
|
|
7822
7868
|
isWrite: false,
|
|
7823
7869
|
outputSchema: envelope({
|
|
7824
7870
|
type: "array",
|
|
@@ -7839,7 +7885,7 @@ function registerSmartmoneyTools() {
|
|
|
7839
7885
|
type: "array",
|
|
7840
7886
|
items: { type: "string" },
|
|
7841
7887
|
minItems: 1,
|
|
7842
|
-
description: 'Base currencies to aggregate, e.g. `["BTC", "ETH", "SOL"]`. Mutually exclusive with `topInstruments`.'
|
|
7888
|
+
description: 'Base currencies to aggregate, e.g. `["BTC", "ETH", "SOL"]`. Mutually exclusive with `topInstruments`. Scope: only USDT-margined and USDS-margined (linear) instruments \u2014 e.g. `BTC` covers `BTC-USDT-SWAP` + `BTC-USDS-SWAP`. Coin-margined contracts (`BTC-USD-SWAP`, `BTC-USD-DELIVERY`) are NOT included; positions a trader holds in those instruments are silently dropped from the aggregation.'
|
|
7843
7889
|
},
|
|
7844
7890
|
...SIGNAL_POOL_FILTER_PROPS,
|
|
7845
7891
|
lmtNum: {
|
|
@@ -7849,7 +7895,8 @@ function registerSmartmoneyTools() {
|
|
|
7849
7895
|
default: 100,
|
|
7850
7896
|
description: "Top-N traders to pull into the aggregation pool, ranked by `sortBy` (DESC). Larger pool = stronger signal but slower. Default 100 is fine for most cases."
|
|
7851
7897
|
}
|
|
7852
|
-
}
|
|
7898
|
+
},
|
|
7899
|
+
required: ["sortBy", "period"]
|
|
7853
7900
|
},
|
|
7854
7901
|
handler: async (rawArgs, context) => {
|
|
7855
7902
|
const args = asRecord(rawArgs);
|
|
@@ -7877,7 +7924,7 @@ function registerSmartmoneyTools() {
|
|
|
7877
7924
|
{
|
|
7878
7925
|
name: "smartmoney_get_signal_overview_by_trader",
|
|
7879
7926
|
module: "smartmoney",
|
|
7880
|
-
description: "Multi-asset smart-money signals aggregated over a hand-picked set of traders (`authorIds`). Pick instruments via `topInstruments` OR `instCcyList`.
|
|
7927
|
+
description: "Multi-asset smart-money signals aggregated over a hand-picked set of traders (`authorIds`). Pick instruments via `topInstruments` OR `instCcyList`. Capability tier filters (pnlTier / winRateTier / etc.) not exposed \u2014 backend uses defaults for direct-lookup scenarios. **Linear (USDT/USDS-margined) contracts only \u2014 a trader's coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions are silently excluded from the aggregation, even when those positions are large.** Use `smartmoney_get_trader_positions` if the full position book is needed. Use when: caller already knows which traders to follow and wants their cross-asset consensus at the latest hour. See also: `smartmoney_get_signal_overview_by_filter` (criteria-defined pool), `smartmoney_get_signal_trend_by_trader` (time-series), `smartmoney_get_traders_by_filter` / `smartmoney_search_trader` (discover authorIds).",
|
|
7881
7928
|
isWrite: false,
|
|
7882
7929
|
outputSchema: envelope({
|
|
7883
7930
|
type: "array",
|
|
@@ -7904,13 +7951,27 @@ function registerSmartmoneyTools() {
|
|
|
7904
7951
|
type: "array",
|
|
7905
7952
|
items: { type: "string" },
|
|
7906
7953
|
minItems: 1,
|
|
7907
|
-
description: 'Base currencies to aggregate, e.g. `["BTC", "ETH", "SOL"]`. Mutually exclusive with `topInstruments`.'
|
|
7954
|
+
description: 'Base currencies to aggregate, e.g. `["BTC", "ETH", "SOL"]`. Mutually exclusive with `topInstruments`. Scope: only USDT-margined and USDS-margined (linear) instruments \u2014 e.g. `BTC` covers `BTC-USDT-SWAP` + `BTC-USDS-SWAP`. Coin-margined contracts (`BTC-USD-SWAP`, `BTC-USD-DELIVERY`) are NOT included; the trader\'s positions in those instruments are silently dropped.'
|
|
7955
|
+
},
|
|
7956
|
+
sortBy: {
|
|
7957
|
+
type: "string",
|
|
7958
|
+
enum: ["pnl", "pnlRatio"],
|
|
7959
|
+
default: "pnl",
|
|
7960
|
+
description: 'Required. Ranking key for the trader set. `pnl` = absolute USD profit; `pnlRatio` = percentage return. Default `"pnl"`.'
|
|
7961
|
+
},
|
|
7962
|
+
period: {
|
|
7963
|
+
type: "string",
|
|
7964
|
+
enum: PERIOD_DAYS,
|
|
7965
|
+
default: "7",
|
|
7966
|
+
description: 'Required. Lookback window in days for capability metrics (`winRate.avgLongWinRate` / `avgShortWinRate`). One of `"3"` / `"7"` / `"30"` / `"90"`. Default `"7"`. Does NOT affect signal fields.'
|
|
7908
7967
|
}
|
|
7909
7968
|
},
|
|
7910
|
-
required: ["authorIds"]
|
|
7969
|
+
required: ["authorIds", "sortBy", "period"]
|
|
7911
7970
|
},
|
|
7912
7971
|
handler: async (rawArgs, context) => {
|
|
7913
7972
|
const args = asRecord(rawArgs);
|
|
7973
|
+
assertEnum2(args, "sortBy", ["pnl", "pnlRatio"]);
|
|
7974
|
+
assertEnum2(args, "period", PERIOD_DAYS);
|
|
7914
7975
|
const authorIds = readArrayAsCsv(args, "authorIds");
|
|
7915
7976
|
if (!authorIds) {
|
|
7916
7977
|
throw actionableError(
|
|
@@ -7930,7 +7991,11 @@ function registerSmartmoneyTools() {
|
|
|
7930
7991
|
PATH_OVERVIEW,
|
|
7931
7992
|
compactObject({
|
|
7932
7993
|
authorIds,
|
|
7933
|
-
...instCcyList ? { instCcyList } : { topInstruments: topInstrumentsRaw ?? 20 }
|
|
7994
|
+
...instCcyList ? { instCcyList } : { topInstruments: topInstrumentsRaw ?? 20 },
|
|
7995
|
+
// Apply schema defaults explicitly so behavior does not depend on backend defaults
|
|
7996
|
+
// (CLI bypasses MCP `required` validation, so handler is the only deterministic layer).
|
|
7997
|
+
sortBy: readString(args, "sortBy") ?? "pnl",
|
|
7998
|
+
period: readString(args, "period") ?? "7"
|
|
7934
7999
|
}),
|
|
7935
8000
|
publicRateLimit("smartmoney_get_signal_overview_by_trader", SMARTMONEY_RPS)
|
|
7936
8001
|
);
|
|
@@ -7941,7 +8006,7 @@ function registerSmartmoneyTools() {
|
|
|
7941
8006
|
{
|
|
7942
8007
|
name: "smartmoney_get_signal_trend_by_filter",
|
|
7943
8008
|
module: "smartmoney",
|
|
7944
|
-
description: "Time-series of single-asset smart-money signal across hourly/daily buckets, aggregated over a tier-filtered trader pool. Returns the latest `limit` buckets ending at `asOfTime` (defaults to current UTC hour). Use when: tracking how long/short conviction and capital evolve over time (smart money adding exposure or retreating). See also: `smartmoney_get_signal_overview_by_filter` (latest snapshot only), `smartmoney_get_signal_trend_by_trader` (restrict to specific traders). Note: `asOfTime` is 10-digit `yyyyMMddHH` UTC, different from leaderboard tools' 12-digit UTC+8 `updateTime` \u2014 do not cross-pass.",
|
|
8009
|
+
description: "Time-series of single-asset smart-money signal across hourly/daily buckets, aggregated over a tier-filtered trader pool. Returns the latest `limit` buckets ending at `asOfTime` (defaults to current UTC hour). **Linear (USDT/USDS-margined) contracts only \u2014 coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions are excluded by upstream and silently omitted.** Use when: tracking how long/short conviction and capital evolve over time (smart money adding exposure or retreating). See also: `smartmoney_get_signal_overview_by_filter` (latest snapshot only), `smartmoney_get_signal_trend_by_trader` (restrict to specific traders). Note: `asOfTime` is 10-digit `yyyyMMddHH` UTC, different from leaderboard tools' 12-digit UTC+8 `updateTime` \u2014 do not cross-pass.",
|
|
7945
8010
|
isWrite: false,
|
|
7946
8011
|
outputSchema: envelope({
|
|
7947
8012
|
type: "array",
|
|
@@ -7953,11 +8018,11 @@ function registerSmartmoneyTools() {
|
|
|
7953
8018
|
properties: {
|
|
7954
8019
|
instCcy: {
|
|
7955
8020
|
type: "string",
|
|
7956
|
-
description: 'Base currency to scope the time-series, e.g. "BTC". Required.'
|
|
8021
|
+
description: 'Base currency to scope the time-series, e.g. "BTC". Required. Scope: USDT-margined and USDS-margined (linear) instruments only \u2014 coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions are NOT included.'
|
|
7957
8022
|
},
|
|
7958
8023
|
asOfTime: {
|
|
7959
8024
|
type: "string",
|
|
7960
|
-
description: 'Anchor snapshot time
|
|
8025
|
+
description: 'Anchor snapshot time \u2014 10-digit `yyyyMMddHH` UTC as a string, e.g. `"2026050100"`. Returns the latest `limit` buckets ending at this anchor. Omit to use the current UTC hour.'
|
|
7961
8026
|
},
|
|
7962
8027
|
granularity: {
|
|
7963
8028
|
type: "string",
|
|
@@ -7981,10 +8046,11 @@ function registerSmartmoneyTools() {
|
|
|
7981
8046
|
description: "Top-N traders to pull into the aggregation pool, ranked by `sortBy` (DESC). Default 100, max 2000."
|
|
7982
8047
|
}
|
|
7983
8048
|
},
|
|
7984
|
-
required: ["instCcy"]
|
|
8049
|
+
required: ["instCcy", "granularity", "sortBy", "period"]
|
|
7985
8050
|
},
|
|
7986
8051
|
handler: async (rawArgs, context) => {
|
|
7987
8052
|
const args = asRecord(rawArgs);
|
|
8053
|
+
assertEnum2(args, "granularity", ["1h", "1d"]);
|
|
7988
8054
|
const instCcy = readString(args, "instCcy");
|
|
7989
8055
|
if (!instCcy) {
|
|
7990
8056
|
throw actionableError(
|
|
@@ -7997,7 +8063,8 @@ function registerSmartmoneyTools() {
|
|
|
7997
8063
|
compactObject({
|
|
7998
8064
|
instCcy,
|
|
7999
8065
|
asOfTime: readString(args, "asOfTime"),
|
|
8000
|
-
|
|
8066
|
+
// Apply schema default explicitly (CLI bypasses MCP `required` validation).
|
|
8067
|
+
granularity: readString(args, "granularity") ?? "1h",
|
|
8001
8068
|
limit: readNumber(args, "limit"),
|
|
8002
8069
|
...readSignalPoolFilters(args),
|
|
8003
8070
|
lmtNum: readNumber(args, "lmtNum")
|
|
@@ -8011,7 +8078,7 @@ function registerSmartmoneyTools() {
|
|
|
8011
8078
|
{
|
|
8012
8079
|
name: "smartmoney_get_signal_trend_by_trader",
|
|
8013
8080
|
module: "smartmoney",
|
|
8014
|
-
description: "Time-series of single-asset smart-money signal aggregated over a hand-picked set of traders (`authorIds`). Returns the latest `limit` buckets ending at `asOfTime` (defaults to current UTC hour).
|
|
8081
|
+
description: "Time-series of single-asset smart-money signal aggregated over a hand-picked set of traders (`authorIds`). Returns the latest `limit` buckets ending at `asOfTime` (defaults to current UTC hour). Capability tier filters (pnlTier / winRateTier / etc.) not exposed \u2014 backend uses defaults for direct-lookup scenarios. **Linear (USDT/USDS-margined) contracts only \u2014 a trader's coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions on the requested base ccy are silently excluded from each bucket.** Use `smartmoney_get_trader_positions` to inspect the full position book. Use when: tracking how a specific group of traders has evolved their long/short consensus over time on one coin. See also: `smartmoney_get_signal_trend_by_filter` (criteria-defined pool), `smartmoney_get_signal_overview_by_trader` (latest snapshot only), `smartmoney_get_traders_by_filter` / `smartmoney_search_trader` (discover authorIds). Note: `asOfTime` is 10-digit `yyyyMMddHH` UTC, different from leaderboard tools' 12-digit UTC+8 `updateTime` \u2014 do not cross-pass.",
|
|
8015
8082
|
isWrite: false,
|
|
8016
8083
|
outputSchema: envelope({
|
|
8017
8084
|
type: "array",
|
|
@@ -8029,11 +8096,11 @@ function registerSmartmoneyTools() {
|
|
|
8029
8096
|
},
|
|
8030
8097
|
instCcy: {
|
|
8031
8098
|
type: "string",
|
|
8032
|
-
description: 'Base currency to scope the time-series, e.g. "BTC". Required.'
|
|
8099
|
+
description: 'Base currency to scope the time-series, e.g. "BTC". Required. Scope: USDT-margined and USDS-margined (linear) instruments only \u2014 coin-margined (`-USD-SWAP` / `-USD-DELIVERY`) positions held by the trader set are NOT included.'
|
|
8033
8100
|
},
|
|
8034
8101
|
asOfTime: {
|
|
8035
8102
|
type: "string",
|
|
8036
|
-
description: 'Anchor snapshot time
|
|
8103
|
+
description: 'Anchor snapshot time \u2014 10-digit `yyyyMMddHH` UTC as a string, e.g. `"2026050100"`. Returns the latest `limit` buckets ending at this anchor. Omit to use the current UTC hour.'
|
|
8037
8104
|
},
|
|
8038
8105
|
granularity: {
|
|
8039
8106
|
type: "string",
|
|
@@ -8047,12 +8114,27 @@ function registerSmartmoneyTools() {
|
|
|
8047
8114
|
maximum: 500,
|
|
8048
8115
|
default: 24,
|
|
8049
8116
|
description: "Number of buckets to return (newest first), ending at `asOfTime`. Default 24, max 500."
|
|
8117
|
+
},
|
|
8118
|
+
sortBy: {
|
|
8119
|
+
type: "string",
|
|
8120
|
+
enum: ["pnl", "pnlRatio"],
|
|
8121
|
+
default: "pnl",
|
|
8122
|
+
description: 'Required. Ranking key for the trader set. `pnl` = absolute USD profit; `pnlRatio` = percentage return. Default `"pnl"`.'
|
|
8123
|
+
},
|
|
8124
|
+
period: {
|
|
8125
|
+
type: "string",
|
|
8126
|
+
enum: PERIOD_DAYS,
|
|
8127
|
+
default: "7",
|
|
8128
|
+
description: 'Required. Lookback window in days. One of `"3"` / `"7"` / `"30"` / `"90"`. Default `"7"`. Does NOT affect signal fields (which always use the latest snapshot).'
|
|
8050
8129
|
}
|
|
8051
8130
|
},
|
|
8052
|
-
required: ["authorIds", "instCcy"]
|
|
8131
|
+
required: ["authorIds", "instCcy", "granularity", "sortBy", "period"]
|
|
8053
8132
|
},
|
|
8054
8133
|
handler: async (rawArgs, context) => {
|
|
8055
8134
|
const args = asRecord(rawArgs);
|
|
8135
|
+
assertEnum2(args, "granularity", ["1h", "1d"]);
|
|
8136
|
+
assertEnum2(args, "sortBy", ["pnl", "pnlRatio"]);
|
|
8137
|
+
assertEnum2(args, "period", PERIOD_DAYS);
|
|
8056
8138
|
const authorIds = readArrayAsCsv(args, "authorIds");
|
|
8057
8139
|
const instCcy = readString(args, "instCcy");
|
|
8058
8140
|
if (!authorIds) {
|
|
@@ -8073,8 +8155,12 @@ function registerSmartmoneyTools() {
|
|
|
8073
8155
|
authorIds,
|
|
8074
8156
|
instCcy,
|
|
8075
8157
|
asOfTime: readString(args, "asOfTime"),
|
|
8076
|
-
|
|
8077
|
-
|
|
8158
|
+
// Apply schema defaults explicitly so behavior does not depend on backend defaults
|
|
8159
|
+
// (CLI bypasses MCP `required` validation, so handler is the only deterministic layer).
|
|
8160
|
+
granularity: readString(args, "granularity") ?? "1h",
|
|
8161
|
+
limit: readNumber(args, "limit"),
|
|
8162
|
+
sortBy: readString(args, "sortBy") ?? "pnl",
|
|
8163
|
+
period: readString(args, "period") ?? "7"
|
|
8078
8164
|
}),
|
|
8079
8165
|
publicRateLimit("smartmoney_get_signal_trend_by_trader", SMARTMONEY_RPS)
|
|
8080
8166
|
);
|
|
@@ -11925,6 +12011,78 @@ function runSetup(options) {
|
|
|
11925
12011
|
`);
|
|
11926
12012
|
}
|
|
11927
12013
|
}
|
|
12014
|
+
function isRedirect(statusCode) {
|
|
12015
|
+
return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
|
|
12016
|
+
}
|
|
12017
|
+
function validateRedirect(res, requestUrl, redirectCount, maxRedirects) {
|
|
12018
|
+
if (redirectCount > maxRedirects) {
|
|
12019
|
+
throw new Error(`Too many redirects (${maxRedirects})`);
|
|
12020
|
+
}
|
|
12021
|
+
const location = res.headers.location;
|
|
12022
|
+
if (requestUrl.startsWith("https") && !location.startsWith("https")) {
|
|
12023
|
+
throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
|
|
12024
|
+
}
|
|
12025
|
+
return location;
|
|
12026
|
+
}
|
|
12027
|
+
function fetchResponse(url, timeoutMs) {
|
|
12028
|
+
return new Promise((resolve3, reject) => {
|
|
12029
|
+
let redirects = 0;
|
|
12030
|
+
const maxRedirects = 5;
|
|
12031
|
+
function doRequest(requestUrl) {
|
|
12032
|
+
const reqFn = requestUrl.startsWith("https") ? httpsGet : httpGet;
|
|
12033
|
+
const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
|
|
12034
|
+
if (isRedirect(res.statusCode) && res.headers.location) {
|
|
12035
|
+
redirects++;
|
|
12036
|
+
try {
|
|
12037
|
+
const location = validateRedirect(res, requestUrl, redirects, maxRedirects);
|
|
12038
|
+
res.resume();
|
|
12039
|
+
doRequest(location);
|
|
12040
|
+
} catch (err) {
|
|
12041
|
+
reject(err);
|
|
12042
|
+
}
|
|
12043
|
+
return;
|
|
12044
|
+
}
|
|
12045
|
+
if (res.statusCode !== 200) {
|
|
12046
|
+
reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
|
|
12047
|
+
return;
|
|
12048
|
+
}
|
|
12049
|
+
resolve3(res);
|
|
12050
|
+
});
|
|
12051
|
+
req.on("error", reject);
|
|
12052
|
+
req.on("timeout", () => {
|
|
12053
|
+
req.destroy();
|
|
12054
|
+
reject(new Error("Download timed out"));
|
|
12055
|
+
});
|
|
12056
|
+
}
|
|
12057
|
+
doRequest(url);
|
|
12058
|
+
});
|
|
12059
|
+
}
|
|
12060
|
+
function download(url, destPath, timeoutMs) {
|
|
12061
|
+
return fetchResponse(url, timeoutMs).then(
|
|
12062
|
+
(res) => new Promise((resolve3, reject) => {
|
|
12063
|
+
const file = createWriteStream2(destPath);
|
|
12064
|
+
res.pipe(file);
|
|
12065
|
+
file.on("finish", () => file.close(() => resolve3()));
|
|
12066
|
+
file.on("error", (err) => {
|
|
12067
|
+
try {
|
|
12068
|
+
unlinkSync3(destPath);
|
|
12069
|
+
} catch {
|
|
12070
|
+
}
|
|
12071
|
+
reject(err);
|
|
12072
|
+
});
|
|
12073
|
+
})
|
|
12074
|
+
);
|
|
12075
|
+
}
|
|
12076
|
+
function downloadText(url, timeoutMs) {
|
|
12077
|
+
return fetchResponse(url, timeoutMs).then(
|
|
12078
|
+
(res) => new Promise((resolve3, reject) => {
|
|
12079
|
+
const chunks = [];
|
|
12080
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
12081
|
+
res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
|
|
12082
|
+
res.on("error", reject);
|
|
12083
|
+
})
|
|
12084
|
+
);
|
|
12085
|
+
}
|
|
11928
12086
|
var CDN_SOURCES = [
|
|
11929
12087
|
{ host: "static.jingyunyilian.com", protocol: "https" },
|
|
11930
12088
|
{ host: "static.okx.com", protocol: "https" },
|
|
@@ -12038,7 +12196,7 @@ async function downloadAndVerify(host, protocol, binaryPath, tmpPath, checksum,
|
|
|
12038
12196
|
function atomicReplace(tmpPath, resolvedDest) {
|
|
12039
12197
|
if (platform() === "win32") {
|
|
12040
12198
|
try {
|
|
12041
|
-
|
|
12199
|
+
unlinkSync4(resolvedDest);
|
|
12042
12200
|
} catch {
|
|
12043
12201
|
}
|
|
12044
12202
|
}
|
|
@@ -12094,7 +12252,7 @@ async function installPilotBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
|
12094
12252
|
return { status: "installed", source: host };
|
|
12095
12253
|
} catch (err) {
|
|
12096
12254
|
try {
|
|
12097
|
-
|
|
12255
|
+
unlinkSync4(tmpPath);
|
|
12098
12256
|
} catch {
|
|
12099
12257
|
}
|
|
12100
12258
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -12108,7 +12266,7 @@ ${errors.join("\n")}` };
|
|
|
12108
12266
|
function removePilotBinary(binaryPath) {
|
|
12109
12267
|
const resolvedPath = binaryPath ?? getPilotBinaryPath();
|
|
12110
12268
|
try {
|
|
12111
|
-
|
|
12269
|
+
unlinkSync4(resolvedPath);
|
|
12112
12270
|
return { status: "removed" };
|
|
12113
12271
|
} catch (err) {
|
|
12114
12272
|
if (err.code === "ENOENT") {
|
|
@@ -12118,78 +12276,6 @@ function removePilotBinary(binaryPath) {
|
|
|
12118
12276
|
throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
|
|
12119
12277
|
}
|
|
12120
12278
|
}
|
|
12121
|
-
function isRedirect(statusCode) {
|
|
12122
|
-
return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
|
|
12123
|
-
}
|
|
12124
|
-
function validateRedirect(res, requestUrl, redirectCount, maxRedirects) {
|
|
12125
|
-
if (redirectCount > maxRedirects) {
|
|
12126
|
-
throw new Error(`Too many redirects (${maxRedirects})`);
|
|
12127
|
-
}
|
|
12128
|
-
const location = res.headers.location;
|
|
12129
|
-
if (requestUrl.startsWith("https") && !location.startsWith("https")) {
|
|
12130
|
-
throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
|
|
12131
|
-
}
|
|
12132
|
-
return location;
|
|
12133
|
-
}
|
|
12134
|
-
function fetchResponse(url, timeoutMs) {
|
|
12135
|
-
return new Promise((resolve3, reject) => {
|
|
12136
|
-
let redirects = 0;
|
|
12137
|
-
const maxRedirects = 5;
|
|
12138
|
-
function doRequest(requestUrl) {
|
|
12139
|
-
const reqFn = requestUrl.startsWith("https") ? httpsGet : httpGet;
|
|
12140
|
-
const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
|
|
12141
|
-
if (isRedirect(res.statusCode) && res.headers.location) {
|
|
12142
|
-
redirects++;
|
|
12143
|
-
try {
|
|
12144
|
-
const location = validateRedirect(res, requestUrl, redirects, maxRedirects);
|
|
12145
|
-
res.resume();
|
|
12146
|
-
doRequest(location);
|
|
12147
|
-
} catch (err) {
|
|
12148
|
-
reject(err);
|
|
12149
|
-
}
|
|
12150
|
-
return;
|
|
12151
|
-
}
|
|
12152
|
-
if (res.statusCode !== 200) {
|
|
12153
|
-
reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
|
|
12154
|
-
return;
|
|
12155
|
-
}
|
|
12156
|
-
resolve3(res);
|
|
12157
|
-
});
|
|
12158
|
-
req.on("error", reject);
|
|
12159
|
-
req.on("timeout", () => {
|
|
12160
|
-
req.destroy();
|
|
12161
|
-
reject(new Error("Download timed out"));
|
|
12162
|
-
});
|
|
12163
|
-
}
|
|
12164
|
-
doRequest(url);
|
|
12165
|
-
});
|
|
12166
|
-
}
|
|
12167
|
-
function download(url, destPath, timeoutMs) {
|
|
12168
|
-
return fetchResponse(url, timeoutMs).then(
|
|
12169
|
-
(res) => new Promise((resolve3, reject) => {
|
|
12170
|
-
const file = createWriteStream2(destPath);
|
|
12171
|
-
res.pipe(file);
|
|
12172
|
-
file.on("finish", () => file.close(() => resolve3()));
|
|
12173
|
-
file.on("error", (err) => {
|
|
12174
|
-
try {
|
|
12175
|
-
unlinkSync3(destPath);
|
|
12176
|
-
} catch {
|
|
12177
|
-
}
|
|
12178
|
-
reject(err);
|
|
12179
|
-
});
|
|
12180
|
-
})
|
|
12181
|
-
);
|
|
12182
|
-
}
|
|
12183
|
-
function downloadText(url, timeoutMs) {
|
|
12184
|
-
return fetchResponse(url, timeoutMs).then(
|
|
12185
|
-
(res) => new Promise((resolve3, reject) => {
|
|
12186
|
-
const chunks = [];
|
|
12187
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
12188
|
-
res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
|
|
12189
|
-
res.on("error", reject);
|
|
12190
|
-
})
|
|
12191
|
-
);
|
|
12192
|
-
}
|
|
12193
12279
|
var AUTH_CDN_PATH_PREFIX = "/upgradeapp/tools/oauth";
|
|
12194
12280
|
function getAuthBinaryName() {
|
|
12195
12281
|
return platform2() === "win32" ? "okx-auth.exe" : "okx-auth";
|
|
@@ -12213,7 +12299,7 @@ async function fetchAuthCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_
|
|
|
12213
12299
|
for (const { host, protocol } of sources) {
|
|
12214
12300
|
try {
|
|
12215
12301
|
const url = `${protocol}://${host}${checksumPath}`;
|
|
12216
|
-
const raw = await
|
|
12302
|
+
const raw = await downloadText(url, timeoutMs);
|
|
12217
12303
|
const data = JSON.parse(raw);
|
|
12218
12304
|
if (typeof data.sha256 !== "string" || typeof data.size !== "number" || typeof data.target !== "string") {
|
|
12219
12305
|
continue;
|
|
@@ -12227,7 +12313,7 @@ async function fetchAuthCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_
|
|
|
12227
12313
|
async function fetchAndValidateChecksum2(host, protocol, checksumPath, platformDir, timeoutMs, onProgress) {
|
|
12228
12314
|
const checksumUrl = `${protocol}://${host}${checksumPath}`;
|
|
12229
12315
|
onProgress?.(`Fetching checksum from ${host}...`);
|
|
12230
|
-
const raw = await
|
|
12316
|
+
const raw = await downloadText(checksumUrl, timeoutMs);
|
|
12231
12317
|
const checksum = JSON.parse(raw);
|
|
12232
12318
|
if (typeof checksum.sha256 !== "string" || typeof checksum.size !== "number" || typeof checksum.target !== "string") {
|
|
12233
12319
|
throw new Error("Invalid checksum.json: missing sha256, size, or target");
|
|
@@ -12240,7 +12326,7 @@ async function fetchAndValidateChecksum2(host, protocol, checksumPath, platformD
|
|
|
12240
12326
|
async function downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, timeoutMs, onProgress) {
|
|
12241
12327
|
const binaryUrl = `${protocol}://${host}${binaryPath}`;
|
|
12242
12328
|
onProgress?.(`Downloading binary from ${host}...`);
|
|
12243
|
-
await
|
|
12329
|
+
await download(binaryUrl, tmpPath, timeoutMs);
|
|
12244
12330
|
const actual = hashFile(tmpPath);
|
|
12245
12331
|
if (actual.size !== checksum.size) {
|
|
12246
12332
|
throw new Error(`Size mismatch: expected ${checksum.size}, got ${actual.size}`);
|
|
@@ -12252,7 +12338,7 @@ async function downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum,
|
|
|
12252
12338
|
function atomicReplace2(tmpPath, resolvedDest) {
|
|
12253
12339
|
if (platform2() === "win32") {
|
|
12254
12340
|
try {
|
|
12255
|
-
|
|
12341
|
+
unlinkSync5(resolvedDest);
|
|
12256
12342
|
} catch {
|
|
12257
12343
|
}
|
|
12258
12344
|
}
|
|
@@ -12308,7 +12394,7 @@ async function installAuthBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
|
12308
12394
|
return { status: "installed", source: host };
|
|
12309
12395
|
} catch (err) {
|
|
12310
12396
|
try {
|
|
12311
|
-
|
|
12397
|
+
unlinkSync5(tmpPath);
|
|
12312
12398
|
} catch {
|
|
12313
12399
|
}
|
|
12314
12400
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -12322,7 +12408,7 @@ ${errors.join("\n")}` };
|
|
|
12322
12408
|
function removeAuthBinary(binaryPath) {
|
|
12323
12409
|
const resolvedPath = binaryPath ?? getAuthBinaryPath();
|
|
12324
12410
|
try {
|
|
12325
|
-
|
|
12411
|
+
unlinkSync5(resolvedPath);
|
|
12326
12412
|
return { status: "removed" };
|
|
12327
12413
|
} catch (err) {
|
|
12328
12414
|
if (err.code === "ENOENT") {
|
|
@@ -12332,78 +12418,6 @@ function removeAuthBinary(binaryPath) {
|
|
|
12332
12418
|
throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
|
|
12333
12419
|
}
|
|
12334
12420
|
}
|
|
12335
|
-
function isRedirect2(statusCode) {
|
|
12336
|
-
return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
|
|
12337
|
-
}
|
|
12338
|
-
function validateRedirect2(res, requestUrl, redirectCount, maxRedirects) {
|
|
12339
|
-
if (redirectCount > maxRedirects) {
|
|
12340
|
-
throw new Error(`Too many redirects (${maxRedirects})`);
|
|
12341
|
-
}
|
|
12342
|
-
const location = res.headers.location;
|
|
12343
|
-
if (requestUrl.startsWith("https") && !location.startsWith("https")) {
|
|
12344
|
-
throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
|
|
12345
|
-
}
|
|
12346
|
-
return location;
|
|
12347
|
-
}
|
|
12348
|
-
function fetchResponse2(url, timeoutMs) {
|
|
12349
|
-
return new Promise((resolve3, reject) => {
|
|
12350
|
-
let redirects = 0;
|
|
12351
|
-
const maxRedirects = 5;
|
|
12352
|
-
function doRequest(requestUrl) {
|
|
12353
|
-
const reqFn = requestUrl.startsWith("https") ? httpsGet2 : httpGet2;
|
|
12354
|
-
const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
|
|
12355
|
-
if (isRedirect2(res.statusCode) && res.headers.location) {
|
|
12356
|
-
redirects++;
|
|
12357
|
-
try {
|
|
12358
|
-
const location = validateRedirect2(res, requestUrl, redirects, maxRedirects);
|
|
12359
|
-
res.resume();
|
|
12360
|
-
doRequest(location);
|
|
12361
|
-
} catch (err) {
|
|
12362
|
-
reject(err);
|
|
12363
|
-
}
|
|
12364
|
-
return;
|
|
12365
|
-
}
|
|
12366
|
-
if (res.statusCode !== 200) {
|
|
12367
|
-
reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
|
|
12368
|
-
return;
|
|
12369
|
-
}
|
|
12370
|
-
resolve3(res);
|
|
12371
|
-
});
|
|
12372
|
-
req.on("error", reject);
|
|
12373
|
-
req.on("timeout", () => {
|
|
12374
|
-
req.destroy();
|
|
12375
|
-
reject(new Error("Download timed out"));
|
|
12376
|
-
});
|
|
12377
|
-
}
|
|
12378
|
-
doRequest(url);
|
|
12379
|
-
});
|
|
12380
|
-
}
|
|
12381
|
-
function download2(url, destPath, timeoutMs) {
|
|
12382
|
-
return fetchResponse2(url, timeoutMs).then(
|
|
12383
|
-
(res) => new Promise((resolve3, reject) => {
|
|
12384
|
-
const file = createWriteStream3(destPath);
|
|
12385
|
-
res.pipe(file);
|
|
12386
|
-
file.on("finish", () => file.close(() => resolve3()));
|
|
12387
|
-
file.on("error", (err) => {
|
|
12388
|
-
try {
|
|
12389
|
-
unlinkSync4(destPath);
|
|
12390
|
-
} catch {
|
|
12391
|
-
}
|
|
12392
|
-
reject(err);
|
|
12393
|
-
});
|
|
12394
|
-
})
|
|
12395
|
-
);
|
|
12396
|
-
}
|
|
12397
|
-
function downloadText2(url, timeoutMs) {
|
|
12398
|
-
return fetchResponse2(url, timeoutMs).then(
|
|
12399
|
-
(res) => new Promise((resolve3, reject) => {
|
|
12400
|
-
const chunks = [];
|
|
12401
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
12402
|
-
res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
|
|
12403
|
-
res.on("error", reject);
|
|
12404
|
-
})
|
|
12405
|
-
);
|
|
12406
|
-
}
|
|
12407
12421
|
var CACHE_PATH = join12(homedir10(), ".okx", "auth-binary-check.json");
|
|
12408
12422
|
var CHECK_INTERVAL_MS2 = 2 * 60 * 60 * 1e3;
|
|
12409
12423
|
function readCache3() {
|
|
@@ -12452,7 +12466,7 @@ function updateAuthBinaryCache(sha256) {
|
|
|
12452
12466
|
}
|
|
12453
12467
|
function clearAuthBinaryCache() {
|
|
12454
12468
|
try {
|
|
12455
|
-
|
|
12469
|
+
unlinkSync6(CACHE_PATH);
|
|
12456
12470
|
} catch {
|
|
12457
12471
|
}
|
|
12458
12472
|
}
|
|
@@ -13368,7 +13382,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
13368
13382
|
|
|
13369
13383
|
// src/commands/diagnose.ts
|
|
13370
13384
|
var CLI_VERSION = readCliVersion();
|
|
13371
|
-
var GIT_HASH = true ? "
|
|
13385
|
+
var GIT_HASH = true ? "e8a0930a" : "dev";
|
|
13372
13386
|
function maskKey2(key) {
|
|
13373
13387
|
if (!key) return "(not set)";
|
|
13374
13388
|
if (key.length <= 8) return "****";
|
|
@@ -14676,12 +14690,12 @@ var CLI_REGISTRY = {
|
|
|
14676
14690
|
commands: {
|
|
14677
14691
|
"traders-by-filter": {
|
|
14678
14692
|
toolName: "smartmoney_get_traders_by_filter",
|
|
14679
|
-
usage: "okx smartmoney traders-by-filter [--updateTime <
|
|
14693
|
+
usage: "okx smartmoney traders-by-filter [--updateTime <yyyyMMddHHmmss UTC+8>] [--sortBy <pnl|pnlRatio, default pnl>] [--period <3|7|30|90, default 90>] [--minPnl <n>] [--minWinRate <r>] [--maxDrawdown <r>] [--minAum <n>] [--after <authorId>] [--before <authorId>] [--limit <n, default 10>] [--json]",
|
|
14680
14694
|
description: "Leaderboard of top smart-money traders, ranked and filtered by pool conditions"
|
|
14681
14695
|
},
|
|
14682
14696
|
"performance-by-trader": {
|
|
14683
14697
|
toolName: "smartmoney_get_performance_by_trader",
|
|
14684
|
-
usage: "okx smartmoney performance-by-trader --authorIds <id1,id2> [--period <3|7|30|90>] [--json]",
|
|
14698
|
+
usage: "okx smartmoney performance-by-trader --authorIds <id1,id2> [--sortBy <pnl|pnlRatio, default pnl>] [--period <3|7|30|90, default 90>] [--json]",
|
|
14685
14699
|
description: "PnL / win-rate / drawdown profile for one or more traders by authorIds"
|
|
14686
14700
|
},
|
|
14687
14701
|
"trader-positions": {
|
|
@@ -14691,12 +14705,12 @@ var CLI_REGISTRY = {
|
|
|
14691
14705
|
},
|
|
14692
14706
|
"trader-positions-history": {
|
|
14693
14707
|
toolName: "smartmoney_get_trader_positions_history",
|
|
14694
|
-
usage: "okx smartmoney trader-positions-history --authorId <id> [--instId <id>] [--after <posId>] [--before <posId>] [--limit <n>] [--json]",
|
|
14708
|
+
usage: "okx smartmoney trader-positions-history --authorId <id> [--instId <id>] [--after <posId>] [--before <posId>] [--limit <n, default 10>] [--json]",
|
|
14695
14709
|
description: "Closed-position history of a single trader (paginated)"
|
|
14696
14710
|
},
|
|
14697
14711
|
"trader-orders-history": {
|
|
14698
14712
|
toolName: "smartmoney_get_trader_orders_history",
|
|
14699
|
-
usage: "okx smartmoney trader-orders-history --authorId <id> [--instId <id>] [--after <ordId>] [--before <ordId>] [--limit <n>] [--json]",
|
|
14713
|
+
usage: "okx smartmoney trader-orders-history --authorId <id> [--instId <id>] [--after <ordId>] [--before <ordId>] [--limit <n, default 10>] [--json]",
|
|
14700
14714
|
description: "Recent orders/fills placed by a single trader (paginated)"
|
|
14701
14715
|
},
|
|
14702
14716
|
"search-trader": {
|
|
@@ -14706,22 +14720,22 @@ var CLI_REGISTRY = {
|
|
|
14706
14720
|
},
|
|
14707
14721
|
"signal-overview-by-filter": {
|
|
14708
14722
|
toolName: "smartmoney_get_signal_overview_by_filter",
|
|
14709
|
-
usage: "okx smartmoney signal-overview-by-filter [--topInstruments <n> | --instCcyList <BTC,ETH,...>] [--sortBy <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnlTier <tier>] [--winRateTier <tier>] [--maxDrawdownTier <tier>] [--aumTier <tier>] [--lmtNum <n>] [--json]",
|
|
14723
|
+
usage: "okx smartmoney signal-overview-by-filter [--topInstruments <n, default 20> | --instCcyList <BTC,ETH,...>] [--sortBy <pnl|pnlRatio, default pnl>] [--period <3|7|30|90, default 7>] [--pnlTier <tier>] [--winRateTier <tier>] [--maxDrawdownTier <tier>] [--aumTier <tier>] [--lmtNum <n, default 100>] [--json]",
|
|
14710
14724
|
description: "Multi-asset smart-money consensus signal aggregated over a tier-filtered pool"
|
|
14711
14725
|
},
|
|
14712
14726
|
"signal-overview-by-trader": {
|
|
14713
14727
|
toolName: "smartmoney_get_signal_overview_by_trader",
|
|
14714
|
-
usage: "okx smartmoney signal-overview-by-trader --authorIds <id1,id2> [--topInstruments <n> | --instCcyList <BTC,ETH,...>] [--json]",
|
|
14728
|
+
usage: "okx smartmoney signal-overview-by-trader --authorIds <id1,id2> [--topInstruments <n, default 20> | --instCcyList <BTC,ETH,...>] [--sortBy <pnl|pnlRatio, default pnl>] [--period <3|7|30|90, default 7>] [--json]",
|
|
14715
14729
|
description: "Multi-asset smart-money signal aggregated over a hand-picked set of traders (authorIds-direct-lookup; pool filters not exposed)"
|
|
14716
14730
|
},
|
|
14717
14731
|
"signal-trend-by-filter": {
|
|
14718
14732
|
toolName: "smartmoney_get_signal_trend_by_filter",
|
|
14719
|
-
usage: "okx smartmoney signal-trend-by-filter --instCcy <ccy> [--asOfTime <yyyyMMddHH>] [--granularity <1h|1d>] [--limit <n>] [--sortBy <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnlTier <tier>] [--winRateTier <tier>] [--maxDrawdownTier <tier>] [--aumTier <tier>] [--lmtNum <n>] [--json]",
|
|
14733
|
+
usage: "okx smartmoney signal-trend-by-filter --instCcy <ccy> [--asOfTime <yyyyMMddHH UTC>] [--granularity <1h|1d, default 1h>] [--limit <n, default 24>] [--sortBy <pnl|pnlRatio, default pnl>] [--period <3|7|30|90, default 7>] [--pnlTier <tier>] [--winRateTier <tier>] [--maxDrawdownTier <tier>] [--aumTier <tier>] [--lmtNum <n, default 100>] [--json]",
|
|
14720
14734
|
description: "Single-coin smart-money signal time-series aggregated over a tier-filtered pool, anchored at asOfTime"
|
|
14721
14735
|
},
|
|
14722
14736
|
"signal-trend-by-trader": {
|
|
14723
14737
|
toolName: "smartmoney_get_signal_trend_by_trader",
|
|
14724
|
-
usage: "okx smartmoney signal-trend-by-trader --authorIds <id1,id2> --instCcy <ccy> [--asOfTime <yyyyMMddHH>] [--granularity <1h|1d>] [--limit <n>] [--json]",
|
|
14738
|
+
usage: "okx smartmoney signal-trend-by-trader --authorIds <id1,id2> --instCcy <ccy> [--asOfTime <yyyyMMddHH UTC>] [--granularity <1h|1d, default 1h>] [--limit <n, default 24>] [--sortBy <pnl|pnlRatio, default pnl>] [--period <3|7|30|90, default 7>] [--json]",
|
|
14725
14739
|
description: "Single-coin smart-money signal time-series aggregated over a hand-picked set of traders (authorIds-direct-lookup; pool filters not exposed)"
|
|
14726
14740
|
}
|
|
14727
14741
|
}
|
|
@@ -18140,6 +18154,7 @@ async function cmdSmartmoneyTradersByFilter(run, opts) {
|
|
|
18140
18154
|
async function cmdSmartmoneyPerformanceByTrader(run, opts) {
|
|
18141
18155
|
const result = await run("smartmoney_get_performance_by_trader", {
|
|
18142
18156
|
authorIds: csvToArray(opts.authorIds),
|
|
18157
|
+
sortBy: opts.sortBy,
|
|
18143
18158
|
period: opts.period
|
|
18144
18159
|
});
|
|
18145
18160
|
if (opts.json) {
|
|
@@ -18280,7 +18295,9 @@ async function cmdSmartmoneySignalOverviewByTrader(run, opts) {
|
|
|
18280
18295
|
const result = await run("smartmoney_get_signal_overview_by_trader", {
|
|
18281
18296
|
authorIds: csvToArray(opts.authorIds),
|
|
18282
18297
|
topInstruments: opts.topInstruments,
|
|
18283
|
-
instCcyList: csvToArray(opts.instCcyList)
|
|
18298
|
+
instCcyList: csvToArray(opts.instCcyList),
|
|
18299
|
+
sortBy: opts.sortBy,
|
|
18300
|
+
period: opts.period
|
|
18284
18301
|
});
|
|
18285
18302
|
if (opts.json) {
|
|
18286
18303
|
printJson(result);
|
|
@@ -18325,7 +18342,9 @@ async function cmdSmartmoneySignalTrendByTrader(run, opts) {
|
|
|
18325
18342
|
instCcy: opts.instCcy,
|
|
18326
18343
|
asOfTime: opts.asOfTime,
|
|
18327
18344
|
granularity: opts.granularity,
|
|
18328
|
-
limit: opts.limit
|
|
18345
|
+
limit: opts.limit,
|
|
18346
|
+
sortBy: opts.sortBy,
|
|
18347
|
+
period: opts.period
|
|
18329
18348
|
});
|
|
18330
18349
|
if (opts.json) {
|
|
18331
18350
|
printJson(result);
|
|
@@ -19849,7 +19868,7 @@ async function cmdEventCancel(run, opts) {
|
|
|
19849
19868
|
// src/index.ts
|
|
19850
19869
|
var _require3 = createRequire3(import.meta.url);
|
|
19851
19870
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
19852
|
-
var GIT_HASH2 = true ? "
|
|
19871
|
+
var GIT_HASH2 = true ? "e8a0930a" : "dev";
|
|
19853
19872
|
function handlePilotCommand(action, json, force, binaryPath) {
|
|
19854
19873
|
if (action === "status") return cmdPilotStatus(json, binaryPath);
|
|
19855
19874
|
if (action === "install") return cmdPilotInstall(json, binaryPath);
|
|
@@ -20887,6 +20906,7 @@ function handleSmartmoneyCommand(run, action, rest, v, json) {
|
|
|
20887
20906
|
}
|
|
20888
20907
|
return cmdSmartmoneyPerformanceByTrader(run, {
|
|
20889
20908
|
authorIds: v.authorIds,
|
|
20909
|
+
sortBy: v.sortBy,
|
|
20890
20910
|
period: v.period,
|
|
20891
20911
|
json
|
|
20892
20912
|
});
|
|
@@ -20977,6 +20997,8 @@ function handleSmartmoneyCommand(run, action, rest, v, json) {
|
|
|
20977
20997
|
authorIds: v.authorIds,
|
|
20978
20998
|
topInstruments: v.topInstruments,
|
|
20979
20999
|
instCcyList: v.instCcyList,
|
|
21000
|
+
sortBy: v.sortBy,
|
|
21001
|
+
period: v.period,
|
|
20980
21002
|
json
|
|
20981
21003
|
});
|
|
20982
21004
|
}
|
|
@@ -21013,6 +21035,8 @@ function handleSmartmoneyCommand(run, action, rest, v, json) {
|
|
|
21013
21035
|
asOfTime: v.asOfTime,
|
|
21014
21036
|
granularity: v.granularity,
|
|
21015
21037
|
limit: v.limit,
|
|
21038
|
+
sortBy: v.sortBy,
|
|
21039
|
+
period: v.period,
|
|
21016
21040
|
json
|
|
21017
21041
|
});
|
|
21018
21042
|
}
|
|
@@ -21342,6 +21366,7 @@ async function main() {
|
|
|
21342
21366
|
main().catch((error) => {
|
|
21343
21367
|
const payload = toToolErrorPayload(error);
|
|
21344
21368
|
errorLine(`Error: ${payload.message}`);
|
|
21369
|
+
if (payload.code) errorLine(`Code: ${payload.code}`);
|
|
21345
21370
|
if (payload.traceId) errorLine(`TraceId: ${payload.traceId}`);
|
|
21346
21371
|
if (payload.suggestion) errorLine(`Hint: ${payload.suggestion}`);
|
|
21347
21372
|
errorLine(`Version: @okx_ai/okx-trade-cli@${CLI_VERSION2}`);
|