@okx_ai/okx-trade-cli 1.3.2 → 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 +2203 -689
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +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(
|
|
@@ -1988,6 +1985,16 @@ function readBoolean(args, key) {
|
|
|
1988
1985
|
}
|
|
1989
1986
|
return value;
|
|
1990
1987
|
}
|
|
1988
|
+
function readStringArray(args, key) {
|
|
1989
|
+
const value = args[key];
|
|
1990
|
+
if (value === void 0 || value === null) {
|
|
1991
|
+
return void 0;
|
|
1992
|
+
}
|
|
1993
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
1994
|
+
throw new ValidationError(`Parameter "${key}" must be an array of strings.`);
|
|
1995
|
+
}
|
|
1996
|
+
return value;
|
|
1997
|
+
}
|
|
1991
1998
|
function requireString(args, key) {
|
|
1992
1999
|
const value = readString(args, key);
|
|
1993
2000
|
if (!value || value.length === 0) {
|
|
@@ -2028,12 +2035,170 @@ function validateSwapInstId(instId) {
|
|
|
2028
2035
|
);
|
|
2029
2036
|
}
|
|
2030
2037
|
}
|
|
2038
|
+
var TP_ORD_KIND_SCHEMA = {
|
|
2039
|
+
type: "string",
|
|
2040
|
+
enum: ["condition", "limit"],
|
|
2041
|
+
description: "condition(default)=trigger-based TP; limit=immediate limit order (no trigger phase)"
|
|
2042
|
+
};
|
|
2043
|
+
var TP_TRIGGER_PX_TYPE_SCHEMA = {
|
|
2044
|
+
type: "string",
|
|
2045
|
+
enum: ["last", "index", "mark"],
|
|
2046
|
+
description: "TP trigger price source: last(default)|index|mark"
|
|
2047
|
+
};
|
|
2048
|
+
var SL_TRIGGER_PX_TYPE_SCHEMA = {
|
|
2049
|
+
type: "string",
|
|
2050
|
+
enum: ["last", "index", "mark"],
|
|
2051
|
+
description: "SL trigger price source: last(default)|index|mark"
|
|
2052
|
+
};
|
|
2053
|
+
var STP_MODE_SCHEMA = {
|
|
2054
|
+
type: "string",
|
|
2055
|
+
enum: ["cancel_maker", "cancel_taker", "cancel_both"],
|
|
2056
|
+
description: "Self-trade prevention: cancel_maker|cancel_taker|cancel_both"
|
|
2057
|
+
};
|
|
2058
|
+
var CXL_ON_CLOSE_POS_SCHEMA = {
|
|
2059
|
+
type: "boolean",
|
|
2060
|
+
description: "Auto-cancel TP/SL when associated position closes (algo only)"
|
|
2061
|
+
};
|
|
2062
|
+
var PHASE1_PLACE_FLAGS_SCHEMA = {
|
|
2063
|
+
tpOrdKind: TP_ORD_KIND_SCHEMA,
|
|
2064
|
+
tpTriggerPxType: TP_TRIGGER_PX_TYPE_SCHEMA,
|
|
2065
|
+
slTriggerPxType: SL_TRIGGER_PX_TYPE_SCHEMA,
|
|
2066
|
+
stpMode: STP_MODE_SCHEMA
|
|
2067
|
+
};
|
|
2068
|
+
var PHASE1_ALGO_FLAGS_SCHEMA = {
|
|
2069
|
+
...PHASE1_PLACE_FLAGS_SCHEMA,
|
|
2070
|
+
cxlOnClosePos: CXL_ON_CLOSE_POS_SCHEMA
|
|
2071
|
+
};
|
|
2072
|
+
var TRIGGER_FLAGS_SCHEMA = {
|
|
2073
|
+
triggerPx: {
|
|
2074
|
+
type: "string",
|
|
2075
|
+
description: "Activation price; order submits when market hits this level (trigger only)"
|
|
2076
|
+
},
|
|
2077
|
+
orderPx: {
|
|
2078
|
+
type: "string",
|
|
2079
|
+
description: "Order price submitted when trigger fires; -1=market (trigger only)"
|
|
2080
|
+
},
|
|
2081
|
+
advanceOrdType: {
|
|
2082
|
+
type: "string",
|
|
2083
|
+
enum: ["fok", "ioc"],
|
|
2084
|
+
description: "Execution qualifier for triggered order: fok=fill-or-kill, ioc=immediate-or-cancel (trigger only)"
|
|
2085
|
+
},
|
|
2086
|
+
triggerPxType: {
|
|
2087
|
+
type: "string",
|
|
2088
|
+
enum: ["last", "index", "mark"],
|
|
2089
|
+
description: "Price type used to evaluate trigger: last(default)|index|mark (trigger only)"
|
|
2090
|
+
}
|
|
2091
|
+
};
|
|
2092
|
+
var CHASE_FLAGS_SCHEMA = {
|
|
2093
|
+
chaseType: {
|
|
2094
|
+
type: "string",
|
|
2095
|
+
enum: ["distance", "ratio"],
|
|
2096
|
+
description: "Chase unit: distance=price ticks, ratio=proportion of price (chase only, default distance)"
|
|
2097
|
+
},
|
|
2098
|
+
chaseVal: {
|
|
2099
|
+
type: "string",
|
|
2100
|
+
description: "Chase amount matching chaseType (e.g. 0.5 ticks for distance, 0.001 for ratio) (chase only)"
|
|
2101
|
+
},
|
|
2102
|
+
maxChaseType: {
|
|
2103
|
+
type: "string",
|
|
2104
|
+
enum: ["distance", "ratio"],
|
|
2105
|
+
description: "Upper-bound unit for chase (chase only)"
|
|
2106
|
+
},
|
|
2107
|
+
maxChaseVal: {
|
|
2108
|
+
type: "string",
|
|
2109
|
+
description: "Upper-bound value for chase (chase only)"
|
|
2110
|
+
}
|
|
2111
|
+
};
|
|
2112
|
+
var ICEBERG_TWAP_FLAGS_SCHEMA = {
|
|
2113
|
+
pxVar: {
|
|
2114
|
+
type: "string",
|
|
2115
|
+
description: "Price variance % [0.0001, 0.01]; provide pxVar OR pxSpread (iceberg/twap only)"
|
|
2116
|
+
},
|
|
2117
|
+
pxSpread: {
|
|
2118
|
+
type: "string",
|
|
2119
|
+
description: "Price variance constant >= 0; provide pxVar OR pxSpread (iceberg/twap only)"
|
|
2120
|
+
},
|
|
2121
|
+
szLimit: {
|
|
2122
|
+
type: "string",
|
|
2123
|
+
description: "Average per-child-order size (iceberg/twap only)"
|
|
2124
|
+
},
|
|
2125
|
+
pxLimit: {
|
|
2126
|
+
type: "string",
|
|
2127
|
+
description: "Order price ceiling >= 0 (iceberg/twap only)"
|
|
2128
|
+
},
|
|
2129
|
+
timeInterval: {
|
|
2130
|
+
type: "string",
|
|
2131
|
+
description: "Seconds between child orders (iceberg/twap only)"
|
|
2132
|
+
}
|
|
2133
|
+
};
|
|
2134
|
+
function buildTriggerOrdTypeBody(args) {
|
|
2135
|
+
return compactObject({
|
|
2136
|
+
triggerPx: readString(args, "triggerPx"),
|
|
2137
|
+
orderPx: readString(args, "orderPx"),
|
|
2138
|
+
advanceOrdType: readString(args, "advanceOrdType"),
|
|
2139
|
+
triggerPxType: readString(args, "triggerPxType"),
|
|
2140
|
+
attachAlgoOrds: buildAttachAlgoOrds(args)
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
function buildChaseOrdTypeBody(args) {
|
|
2144
|
+
return compactObject({
|
|
2145
|
+
chaseType: readString(args, "chaseType"),
|
|
2146
|
+
chaseVal: readString(args, "chaseVal"),
|
|
2147
|
+
maxChaseType: readString(args, "maxChaseType"),
|
|
2148
|
+
maxChaseVal: readString(args, "maxChaseVal")
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
function buildIcebergTwapOrdTypeBody(args) {
|
|
2152
|
+
return compactObject({
|
|
2153
|
+
pxVar: readString(args, "pxVar"),
|
|
2154
|
+
pxSpread: readString(args, "pxSpread"),
|
|
2155
|
+
szLimit: readString(args, "szLimit"),
|
|
2156
|
+
pxLimit: readString(args, "pxLimit"),
|
|
2157
|
+
timeInterval: readString(args, "timeInterval")
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
function buildAlgoConditionalCommonFields(args) {
|
|
2161
|
+
return {
|
|
2162
|
+
tpTriggerPx: readString(args, "tpTriggerPx"),
|
|
2163
|
+
tpOrdPx: readString(args, "tpOrdPx"),
|
|
2164
|
+
tpOrdKind: readString(args, "tpOrdKind"),
|
|
2165
|
+
tpTriggerPxType: readString(args, "tpTriggerPxType"),
|
|
2166
|
+
tpTriggerRatio: readString(args, "tpTriggerRatio"),
|
|
2167
|
+
slTriggerPx: readString(args, "slTriggerPx"),
|
|
2168
|
+
slOrdPx: readString(args, "slOrdPx"),
|
|
2169
|
+
slTriggerPxType: readString(args, "slTriggerPxType"),
|
|
2170
|
+
slTriggerRatio: readString(args, "slTriggerRatio"),
|
|
2171
|
+
closeFraction: readString(args, "closeFraction"),
|
|
2172
|
+
activePx: readString(args, "activePx")
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2031
2175
|
function buildAttachAlgoOrds(source) {
|
|
2176
|
+
const tpLevels = source["tpLevels"];
|
|
2177
|
+
if (Array.isArray(tpLevels) && tpLevels.length > 0) {
|
|
2178
|
+
return tpLevels.map(
|
|
2179
|
+
(level) => compactObject(level)
|
|
2180
|
+
);
|
|
2181
|
+
}
|
|
2032
2182
|
const tpTriggerPx = readString(source, "tpTriggerPx");
|
|
2033
2183
|
const tpOrdPx = readString(source, "tpOrdPx");
|
|
2034
2184
|
const slTriggerPx = readString(source, "slTriggerPx");
|
|
2035
2185
|
const slOrdPx = readString(source, "slOrdPx");
|
|
2036
|
-
const
|
|
2186
|
+
const tpOrdKind = readString(source, "tpOrdKind");
|
|
2187
|
+
const tpTriggerPxType = readString(source, "tpTriggerPxType");
|
|
2188
|
+
const slTriggerPxType = readString(source, "slTriggerPxType");
|
|
2189
|
+
const tpTriggerRatio = readString(source, "tpTriggerRatio");
|
|
2190
|
+
const slTriggerRatio = readString(source, "slTriggerRatio");
|
|
2191
|
+
const entry = compactObject({
|
|
2192
|
+
tpTriggerPx,
|
|
2193
|
+
tpOrdPx,
|
|
2194
|
+
slTriggerPx,
|
|
2195
|
+
slOrdPx,
|
|
2196
|
+
tpOrdKind,
|
|
2197
|
+
tpTriggerPxType,
|
|
2198
|
+
slTriggerPxType,
|
|
2199
|
+
tpTriggerRatio,
|
|
2200
|
+
slTriggerRatio
|
|
2201
|
+
});
|
|
2037
2202
|
return Object.keys(entry).length > 0 ? [entry] : void 0;
|
|
2038
2203
|
}
|
|
2039
2204
|
var OKX_CANDLE_BARS = [
|
|
@@ -3108,7 +3273,7 @@ function registerAlgoTradeTools() {
|
|
|
3108
3273
|
{
|
|
3109
3274
|
name: "swap_place_algo_order",
|
|
3110
3275
|
module: "swap",
|
|
3111
|
-
description: "Place a SWAP/FUTURES algo order
|
|
3276
|
+
description: "Place a SWAP/FUTURES algo order. [CAUTION] Executes real trades. conditional: single TP, single SL, or both on one order. oco: TP+SL simultaneously \u2014 first trigger cancels the other. move_order_stop: trailing stop (callbackRatio or callbackSpread). trigger: pending order activated when triggerPx is hit (provide triggerPx + orderPx). chase: smart-follow best bid/ask. iceberg: split large order into child orders at intervals. twap: time-weighted average price order splitting.",
|
|
3112
3277
|
isWrite: true,
|
|
3113
3278
|
inputSchema: {
|
|
3114
3279
|
type: "object",
|
|
@@ -3134,8 +3299,8 @@ function registerAlgoTradeTools() {
|
|
|
3134
3299
|
},
|
|
3135
3300
|
ordType: {
|
|
3136
3301
|
type: "string",
|
|
3137
|
-
enum: ["conditional", "oco", "move_order_stop"],
|
|
3138
|
-
description: "conditional=single TP/SL or both; oco=TP+SL pair
|
|
3302
|
+
enum: ["conditional", "oco", "move_order_stop", "trigger", "chase", "iceberg", "twap"],
|
|
3303
|
+
description: "conditional=single TP/SL or both; oco=TP+SL pair; move_order_stop=trailing stop; trigger=pending order; chase=follow best bid/ask; iceberg=split order; twap=time-weighted split"
|
|
3139
3304
|
},
|
|
3140
3305
|
sz: {
|
|
3141
3306
|
type: "string",
|
|
@@ -3149,11 +3314,8 @@ function registerAlgoTradeTools() {
|
|
|
3149
3314
|
type: "string",
|
|
3150
3315
|
description: "TP order price; -1=market (conditional/oco only)"
|
|
3151
3316
|
},
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
enum: ["last", "index", "mark"],
|
|
3155
|
-
description: "last(default)|index|mark (conditional/oco only)"
|
|
3156
|
-
},
|
|
3317
|
+
tpOrdKind: TP_ORD_KIND_SCHEMA,
|
|
3318
|
+
tpTriggerPxType: TP_TRIGGER_PX_TYPE_SCHEMA,
|
|
3157
3319
|
slTriggerPx: {
|
|
3158
3320
|
type: "string",
|
|
3159
3321
|
description: "SL trigger price (conditional/oco only)"
|
|
@@ -3162,11 +3324,9 @@ function registerAlgoTradeTools() {
|
|
|
3162
3324
|
type: "string",
|
|
3163
3325
|
description: "SL order price; -1=market (recommended) (conditional/oco only)"
|
|
3164
3326
|
},
|
|
3165
|
-
slTriggerPxType:
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
description: "last(default)|index|mark (conditional/oco only)"
|
|
3169
|
-
},
|
|
3327
|
+
slTriggerPxType: SL_TRIGGER_PX_TYPE_SCHEMA,
|
|
3328
|
+
stpMode: STP_MODE_SCHEMA,
|
|
3329
|
+
cxlOnClosePos: CXL_ON_CLOSE_POS_SCHEMA,
|
|
3170
3330
|
callbackRatio: {
|
|
3171
3331
|
type: "string",
|
|
3172
3332
|
description: "Callback ratio (e.g. '0.01'=1%); provide either ratio or spread (move_order_stop only)"
|
|
@@ -3179,6 +3339,9 @@ function registerAlgoTradeTools() {
|
|
|
3179
3339
|
type: "string",
|
|
3180
3340
|
description: "Activation price; tracking starts after market reaches this level (move_order_stop only)"
|
|
3181
3341
|
},
|
|
3342
|
+
...TRIGGER_FLAGS_SCHEMA,
|
|
3343
|
+
...CHASE_FLAGS_SCHEMA,
|
|
3344
|
+
...ICEBERG_TWAP_FLAGS_SCHEMA,
|
|
3182
3345
|
tgtCcy: {
|
|
3183
3346
|
type: "string",
|
|
3184
3347
|
enum: ["base_ccy", "quote_ccy", "margin"],
|
|
@@ -3198,6 +3361,8 @@ function registerAlgoTradeTools() {
|
|
|
3198
3361
|
handler: async (rawArgs, context) => {
|
|
3199
3362
|
const args = asRecord(rawArgs);
|
|
3200
3363
|
const reduceOnly = args.reduceOnly;
|
|
3364
|
+
const cxlOnClosePos = args.cxlOnClosePos;
|
|
3365
|
+
const ordType = requireString(args, "ordType");
|
|
3201
3366
|
const resolved = await resolveQuoteCcySz(
|
|
3202
3367
|
requireString(args, "instId"),
|
|
3203
3368
|
requireString(args, "sz"),
|
|
@@ -3206,29 +3371,44 @@ function registerAlgoTradeTools() {
|
|
|
3206
3371
|
context.client,
|
|
3207
3372
|
readString(args, "tdMode")
|
|
3208
3373
|
);
|
|
3374
|
+
const base = compactObject({
|
|
3375
|
+
instId: requireString(args, "instId"),
|
|
3376
|
+
tdMode: requireString(args, "tdMode"),
|
|
3377
|
+
side: requireString(args, "side"),
|
|
3378
|
+
posSide: readString(args, "posSide"),
|
|
3379
|
+
ordType,
|
|
3380
|
+
sz: resolved.sz,
|
|
3381
|
+
tgtCcy: resolved.tgtCcy,
|
|
3382
|
+
stpMode: readString(args, "stpMode"),
|
|
3383
|
+
cxlOnClosePos: typeof cxlOnClosePos === "boolean" ? String(cxlOnClosePos) : void 0,
|
|
3384
|
+
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
3385
|
+
clOrdId: readString(args, "clOrdId"),
|
|
3386
|
+
// Phase 3a+c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
3387
|
+
pxAmendType: readString(args, "pxAmendType"),
|
|
3388
|
+
tag: context.config.sourceTag
|
|
3389
|
+
});
|
|
3390
|
+
switch (ordType) {
|
|
3391
|
+
case "trigger":
|
|
3392
|
+
Object.assign(base, buildTriggerOrdTypeBody(args));
|
|
3393
|
+
break;
|
|
3394
|
+
case "chase":
|
|
3395
|
+
Object.assign(base, buildChaseOrdTypeBody(args));
|
|
3396
|
+
break;
|
|
3397
|
+
case "iceberg":
|
|
3398
|
+
case "twap":
|
|
3399
|
+
Object.assign(base, buildIcebergTwapOrdTypeBody(args));
|
|
3400
|
+
break;
|
|
3401
|
+
default:
|
|
3402
|
+
Object.assign(base, compactObject({
|
|
3403
|
+
...buildAlgoConditionalCommonFields(args),
|
|
3404
|
+
callBackRatio: readString(args, "callbackRatio"),
|
|
3405
|
+
callBackSpread: readString(args, "callbackSpread")
|
|
3406
|
+
}));
|
|
3407
|
+
break;
|
|
3408
|
+
}
|
|
3209
3409
|
const response = await context.client.privatePost(
|
|
3210
3410
|
"/api/v5/trade/order-algo",
|
|
3211
|
-
|
|
3212
|
-
instId: requireString(args, "instId"),
|
|
3213
|
-
tdMode: requireString(args, "tdMode"),
|
|
3214
|
-
side: requireString(args, "side"),
|
|
3215
|
-
posSide: readString(args, "posSide"),
|
|
3216
|
-
ordType: requireString(args, "ordType"),
|
|
3217
|
-
sz: resolved.sz,
|
|
3218
|
-
tgtCcy: resolved.tgtCcy,
|
|
3219
|
-
tpTriggerPx: readString(args, "tpTriggerPx"),
|
|
3220
|
-
tpOrdPx: readString(args, "tpOrdPx"),
|
|
3221
|
-
tpTriggerPxType: readString(args, "tpTriggerPxType"),
|
|
3222
|
-
slTriggerPx: readString(args, "slTriggerPx"),
|
|
3223
|
-
slOrdPx: readString(args, "slOrdPx"),
|
|
3224
|
-
slTriggerPxType: readString(args, "slTriggerPxType"),
|
|
3225
|
-
callBackRatio: readString(args, "callbackRatio"),
|
|
3226
|
-
callBackSpread: readString(args, "callbackSpread"),
|
|
3227
|
-
activePx: readString(args, "activePx"),
|
|
3228
|
-
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
3229
|
-
clOrdId: readString(args, "clOrdId"),
|
|
3230
|
-
tag: context.config.sourceTag
|
|
3231
|
-
}),
|
|
3411
|
+
base,
|
|
3232
3412
|
privateRateLimit("swap_place_algo_order", 20)
|
|
3233
3413
|
);
|
|
3234
3414
|
const result = normalizeResponse(response);
|
|
@@ -3453,7 +3633,7 @@ function registerFuturesAlgoTools() {
|
|
|
3453
3633
|
{
|
|
3454
3634
|
name: "futures_place_algo_order",
|
|
3455
3635
|
module: "futures",
|
|
3456
|
-
description: "Place a FUTURES delivery algo order
|
|
3636
|
+
description: "Place a FUTURES delivery algo order. [CAUTION] Executes real trades. conditional: single TP, single SL, or both on one order. oco: TP+SL simultaneously \u2014 first trigger cancels the other. move_order_stop: trailing stop (callbackRatio or callbackSpread). trigger: pending order activated when triggerPx is hit (provide triggerPx + orderPx). chase: smart-follow best bid/ask. iceberg: split large order into child orders at intervals. twap: time-weighted average price order splitting.",
|
|
3457
3637
|
isWrite: true,
|
|
3458
3638
|
inputSchema: {
|
|
3459
3639
|
type: "object",
|
|
@@ -3479,8 +3659,8 @@ function registerFuturesAlgoTools() {
|
|
|
3479
3659
|
},
|
|
3480
3660
|
ordType: {
|
|
3481
3661
|
type: "string",
|
|
3482
|
-
enum: ["conditional", "oco", "move_order_stop"],
|
|
3483
|
-
description: "conditional=single TP/SL or both; oco=TP+SL pair; move_order_stop=trailing stop"
|
|
3662
|
+
enum: ["conditional", "oco", "move_order_stop", "trigger", "chase", "iceberg", "twap"],
|
|
3663
|
+
description: "conditional=single TP/SL or both; oco=TP+SL pair; move_order_stop=trailing stop; trigger=pending order; chase=follow best bid/ask; iceberg=split order; twap=time-weighted split"
|
|
3484
3664
|
},
|
|
3485
3665
|
sz: {
|
|
3486
3666
|
type: "string",
|
|
@@ -3494,11 +3674,8 @@ function registerFuturesAlgoTools() {
|
|
|
3494
3674
|
type: "string",
|
|
3495
3675
|
description: "TP order price; -1=market (conditional/oco only)"
|
|
3496
3676
|
},
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
enum: ["last", "index", "mark"],
|
|
3500
|
-
description: "last(default)|index|mark (conditional/oco only)"
|
|
3501
|
-
},
|
|
3677
|
+
tpOrdKind: TP_ORD_KIND_SCHEMA,
|
|
3678
|
+
tpTriggerPxType: TP_TRIGGER_PX_TYPE_SCHEMA,
|
|
3502
3679
|
slTriggerPx: {
|
|
3503
3680
|
type: "string",
|
|
3504
3681
|
description: "SL trigger price (conditional/oco only)"
|
|
@@ -3507,11 +3684,9 @@ function registerFuturesAlgoTools() {
|
|
|
3507
3684
|
type: "string",
|
|
3508
3685
|
description: "SL order price; -1=market (conditional/oco only)"
|
|
3509
3686
|
},
|
|
3510
|
-
slTriggerPxType:
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
description: "last(default)|index|mark (conditional/oco only)"
|
|
3514
|
-
},
|
|
3687
|
+
slTriggerPxType: SL_TRIGGER_PX_TYPE_SCHEMA,
|
|
3688
|
+
stpMode: STP_MODE_SCHEMA,
|
|
3689
|
+
cxlOnClosePos: CXL_ON_CLOSE_POS_SCHEMA,
|
|
3515
3690
|
callbackRatio: {
|
|
3516
3691
|
type: "string",
|
|
3517
3692
|
description: "Callback ratio (e.g. '0.01'=1%); provide either ratio or spread (move_order_stop only)"
|
|
@@ -3524,6 +3699,9 @@ function registerFuturesAlgoTools() {
|
|
|
3524
3699
|
type: "string",
|
|
3525
3700
|
description: "Activation price; tracking starts after market reaches this level (move_order_stop only)"
|
|
3526
3701
|
},
|
|
3702
|
+
...TRIGGER_FLAGS_SCHEMA,
|
|
3703
|
+
...CHASE_FLAGS_SCHEMA,
|
|
3704
|
+
...ICEBERG_TWAP_FLAGS_SCHEMA,
|
|
3527
3705
|
tgtCcy: {
|
|
3528
3706
|
type: "string",
|
|
3529
3707
|
enum: ["base_ccy", "quote_ccy", "margin"],
|
|
@@ -3543,6 +3721,8 @@ function registerFuturesAlgoTools() {
|
|
|
3543
3721
|
handler: async (rawArgs, context) => {
|
|
3544
3722
|
const args = asRecord(rawArgs);
|
|
3545
3723
|
const reduceOnly = args.reduceOnly;
|
|
3724
|
+
const cxlOnClosePos = args.cxlOnClosePos;
|
|
3725
|
+
const ordType = requireString(args, "ordType");
|
|
3546
3726
|
const resolved = await resolveQuoteCcySz(
|
|
3547
3727
|
requireString(args, "instId"),
|
|
3548
3728
|
requireString(args, "sz"),
|
|
@@ -3551,29 +3731,44 @@ function registerFuturesAlgoTools() {
|
|
|
3551
3731
|
context.client,
|
|
3552
3732
|
readString(args, "tdMode")
|
|
3553
3733
|
);
|
|
3734
|
+
const base = compactObject({
|
|
3735
|
+
instId: requireString(args, "instId"),
|
|
3736
|
+
tdMode: requireString(args, "tdMode"),
|
|
3737
|
+
side: requireString(args, "side"),
|
|
3738
|
+
posSide: readString(args, "posSide"),
|
|
3739
|
+
ordType,
|
|
3740
|
+
sz: resolved.sz,
|
|
3741
|
+
tgtCcy: resolved.tgtCcy,
|
|
3742
|
+
stpMode: readString(args, "stpMode"),
|
|
3743
|
+
cxlOnClosePos: typeof cxlOnClosePos === "boolean" ? String(cxlOnClosePos) : void 0,
|
|
3744
|
+
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
3745
|
+
clOrdId: readString(args, "clOrdId"),
|
|
3746
|
+
// Phase 3a+c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
3747
|
+
pxAmendType: readString(args, "pxAmendType"),
|
|
3748
|
+
tag: context.config.sourceTag
|
|
3749
|
+
});
|
|
3750
|
+
switch (ordType) {
|
|
3751
|
+
case "trigger":
|
|
3752
|
+
Object.assign(base, buildTriggerOrdTypeBody(args));
|
|
3753
|
+
break;
|
|
3754
|
+
case "chase":
|
|
3755
|
+
Object.assign(base, buildChaseOrdTypeBody(args));
|
|
3756
|
+
break;
|
|
3757
|
+
case "iceberg":
|
|
3758
|
+
case "twap":
|
|
3759
|
+
Object.assign(base, buildIcebergTwapOrdTypeBody(args));
|
|
3760
|
+
break;
|
|
3761
|
+
default:
|
|
3762
|
+
Object.assign(base, compactObject({
|
|
3763
|
+
...buildAlgoConditionalCommonFields(args),
|
|
3764
|
+
callBackRatio: readString(args, "callbackRatio"),
|
|
3765
|
+
callBackSpread: readString(args, "callbackSpread")
|
|
3766
|
+
}));
|
|
3767
|
+
break;
|
|
3768
|
+
}
|
|
3554
3769
|
const response = await context.client.privatePost(
|
|
3555
3770
|
"/api/v5/trade/order-algo",
|
|
3556
|
-
|
|
3557
|
-
instId: requireString(args, "instId"),
|
|
3558
|
-
tdMode: requireString(args, "tdMode"),
|
|
3559
|
-
side: requireString(args, "side"),
|
|
3560
|
-
posSide: readString(args, "posSide"),
|
|
3561
|
-
ordType: requireString(args, "ordType"),
|
|
3562
|
-
sz: resolved.sz,
|
|
3563
|
-
tgtCcy: resolved.tgtCcy,
|
|
3564
|
-
tpTriggerPx: readString(args, "tpTriggerPx"),
|
|
3565
|
-
tpOrdPx: readString(args, "tpOrdPx"),
|
|
3566
|
-
tpTriggerPxType: readString(args, "tpTriggerPxType"),
|
|
3567
|
-
slTriggerPx: readString(args, "slTriggerPx"),
|
|
3568
|
-
slOrdPx: readString(args, "slOrdPx"),
|
|
3569
|
-
slTriggerPxType: readString(args, "slTriggerPxType"),
|
|
3570
|
-
callBackRatio: readString(args, "callbackRatio"),
|
|
3571
|
-
callBackSpread: readString(args, "callbackSpread"),
|
|
3572
|
-
activePx: readString(args, "activePx"),
|
|
3573
|
-
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
3574
|
-
clOrdId: readString(args, "clOrdId"),
|
|
3575
|
-
tag: context.config.sourceTag
|
|
3576
|
-
}),
|
|
3771
|
+
base,
|
|
3577
3772
|
privateRateLimit("futures_place_algo_order", 20)
|
|
3578
3773
|
);
|
|
3579
3774
|
const result = normalizeResponse(response);
|
|
@@ -6156,6 +6351,23 @@ function resolveOutcome(value) {
|
|
|
6156
6351
|
}
|
|
6157
6352
|
return resolved;
|
|
6158
6353
|
}
|
|
6354
|
+
async function withConcurrency(items, maxConcurrency, fn) {
|
|
6355
|
+
const results = new Array(items.length);
|
|
6356
|
+
let nextIndex = 0;
|
|
6357
|
+
async function runNext() {
|
|
6358
|
+
while (nextIndex < items.length) {
|
|
6359
|
+
const idx = nextIndex++;
|
|
6360
|
+
try {
|
|
6361
|
+
results[idx] = { status: "fulfilled", value: await fn(items[idx]) };
|
|
6362
|
+
} catch (err) {
|
|
6363
|
+
results[idx] = { status: "rejected", reason: err };
|
|
6364
|
+
}
|
|
6365
|
+
}
|
|
6366
|
+
}
|
|
6367
|
+
const workers = Array.from({ length: Math.min(maxConcurrency, items.length) }, runNext);
|
|
6368
|
+
await Promise.all(workers);
|
|
6369
|
+
return results;
|
|
6370
|
+
}
|
|
6159
6371
|
function filterBrowseCandidates(allSeries, underlyingFilter) {
|
|
6160
6372
|
const isHumanReadable = (id) => /^(BTC|ETH|TRX|EOS|SOL|IOTA|KISHU|SUSHI|BTG|XTZ|SOLVU)-/.test(id);
|
|
6161
6373
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -6296,6 +6508,7 @@ function handlePlaceOrderError(base, rawArgs, endpoint) {
|
|
|
6296
6508
|
}
|
|
6297
6509
|
throw new OkxApiError(`[${sCode}] ${sMsg}`, { code: sCode, endpoint });
|
|
6298
6510
|
}
|
|
6511
|
+
var MAX_CONCURRENT_MARKET_FETCHES = 8;
|
|
6299
6512
|
var OUTCOME_SCHEMA = {
|
|
6300
6513
|
type: "string",
|
|
6301
6514
|
enum: ["UP", "YES", "DOWN", "NO"],
|
|
@@ -6335,10 +6548,15 @@ function registerEventContractTools() {
|
|
|
6335
6548
|
const normalizedSeries = normalizeResponse(seriesResp);
|
|
6336
6549
|
const allSeries = Array.isArray(normalizedSeries["data"]) ? normalizedSeries["data"] : [];
|
|
6337
6550
|
const candidates = filterBrowseCandidates(allSeries, underlyingFilter);
|
|
6338
|
-
const
|
|
6339
|
-
candidates
|
|
6551
|
+
const settled = await withConcurrency(
|
|
6552
|
+
candidates,
|
|
6553
|
+
MAX_CONCURRENT_MARKET_FETCHES,
|
|
6554
|
+
(s) => fetchActiveContractsForSeries(context.client, s)
|
|
6340
6555
|
);
|
|
6341
|
-
const
|
|
6556
|
+
const fulfilled = settled.filter(
|
|
6557
|
+
(r) => r.status === "fulfilled" && r.value !== null
|
|
6558
|
+
);
|
|
6559
|
+
const results = fulfilled.map((r) => r.value);
|
|
6342
6560
|
return {
|
|
6343
6561
|
data: results,
|
|
6344
6562
|
total: results.reduce((n, r) => n + (r?.contracts?.length ?? 0), 0)
|
|
@@ -6758,379 +6976,1195 @@ function registerEventContractTools() {
|
|
|
6758
6976
|
}
|
|
6759
6977
|
];
|
|
6760
6978
|
}
|
|
6979
|
+
var SMARTMONEY_RPS = 5;
|
|
6761
6980
|
var PATH_LEADERBOARD = "/api/v5/orbit/public/leaderboard";
|
|
6762
6981
|
var PATH_POSITION_CURRENT = "/api/v5/orbit/public/position-current";
|
|
6982
|
+
var PATH_POSITION_HISTORY = "/api/v5/orbit/public/position-history";
|
|
6763
6983
|
var PATH_TRADE_RECORDS = "/api/v5/orbit/public/trade-records";
|
|
6984
|
+
var PATH_TOP_TRADER_SEARCH = "/api/v5/orbit/top-trader-search";
|
|
6764
6985
|
var PATH_OVERVIEW = "/api/v5/journal/smartmoney/overview";
|
|
6765
|
-
var PATH_SIGNAL = "/api/v5/journal/smartmoney/signal";
|
|
6766
6986
|
var PATH_SIGNAL_HISTORY = "/api/v5/journal/smartmoney/signal-history";
|
|
6987
|
+
var PERIOD_DAYS = ["3", "7", "30", "90"];
|
|
6767
6988
|
var SIGNAL_POOL_FILTER_PROPS = {
|
|
6768
|
-
|
|
6989
|
+
sortBy: {
|
|
6769
6990
|
type: "string",
|
|
6770
|
-
|
|
6991
|
+
enum: ["pnl", "pnlRatio"],
|
|
6992
|
+
default: "pnl",
|
|
6993
|
+
description: "Ranking key used to pick traders into the aggregation pool. `pnl` = absolute USD profit (favors high-AUM whales); `pnlRatio` = percentage return (favors small-but-efficient traders)."
|
|
6771
6994
|
},
|
|
6772
6995
|
period: {
|
|
6773
6996
|
type: "string",
|
|
6774
|
-
|
|
6997
|
+
enum: PERIOD_DAYS,
|
|
6998
|
+
default: "7",
|
|
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).'
|
|
6775
7000
|
},
|
|
6776
|
-
|
|
7001
|
+
pnlTier: {
|
|
6777
7002
|
type: "string",
|
|
6778
|
-
|
|
7003
|
+
enum: ["PNL_ANY", "PNL_TOP50", "PNL_TOP20", "PNL_TOP5"],
|
|
7004
|
+
default: "PNL_ANY",
|
|
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."
|
|
6779
7006
|
},
|
|
6780
|
-
|
|
7007
|
+
winRateTier: {
|
|
6781
7008
|
type: "string",
|
|
6782
|
-
|
|
7009
|
+
enum: ["WR_ANY", "WR_GE_50", "WR_GE_80"],
|
|
7010
|
+
default: "WR_ANY",
|
|
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%."
|
|
6783
7012
|
},
|
|
6784
|
-
|
|
7013
|
+
maxDrawdownTier: {
|
|
6785
7014
|
type: "string",
|
|
6786
|
-
|
|
7015
|
+
enum: ["MR_ANY", "MR_LE_20", "MR_LE_50"],
|
|
7016
|
+
default: "MR_ANY",
|
|
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%."
|
|
6787
7018
|
},
|
|
6788
|
-
|
|
7019
|
+
aumTier: {
|
|
6789
7020
|
type: "string",
|
|
6790
|
-
|
|
7021
|
+
enum: ["AUM_ANY", "AUM_TOP50", "AUM_TOP20", "AUM_TOP5"],
|
|
7022
|
+
default: "AUM_ANY",
|
|
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."
|
|
6791
7024
|
}
|
|
6792
7025
|
};
|
|
6793
7026
|
var LEADERBOARD_POOL_FILTER_PROPS = {
|
|
6794
|
-
|
|
7027
|
+
sortBy: {
|
|
6795
7028
|
type: "string",
|
|
6796
|
-
|
|
7029
|
+
enum: ["pnl", "pnlRatio"],
|
|
7030
|
+
default: "pnl",
|
|
7031
|
+
description: 'Required. Leaderboard sort key. `pnl` = absolute USD profit; `pnlRatio` = percentage return. Default `"pnl"`.'
|
|
6797
7032
|
},
|
|
6798
7033
|
period: {
|
|
6799
7034
|
type: "string",
|
|
6800
|
-
|
|
7035
|
+
enum: PERIOD_DAYS,
|
|
7036
|
+
default: "90",
|
|
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.'
|
|
6801
7038
|
},
|
|
6802
|
-
|
|
7039
|
+
minPnl: {
|
|
6803
7040
|
type: "string",
|
|
6804
|
-
description:
|
|
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.'
|
|
6805
7042
|
},
|
|
6806
|
-
|
|
7043
|
+
minWinRate: {
|
|
6807
7044
|
type: "string",
|
|
6808
|
-
description:
|
|
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.'
|
|
6809
7046
|
},
|
|
6810
|
-
|
|
7047
|
+
maxDrawdown: {
|
|
6811
7048
|
type: "string",
|
|
6812
|
-
description:
|
|
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.'
|
|
6813
7050
|
},
|
|
6814
|
-
|
|
7051
|
+
minAum: {
|
|
6815
7052
|
type: "string",
|
|
6816
|
-
description:
|
|
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.'
|
|
6817
7054
|
}
|
|
6818
7055
|
};
|
|
6819
|
-
var
|
|
7056
|
+
var LEADERBOARD_FILTER_UPSTREAM_NAMES = {
|
|
7057
|
+
sortBy: "sortBy",
|
|
7058
|
+
period: "period",
|
|
7059
|
+
minPnl: "pnl",
|
|
7060
|
+
minWinRate: "winRate",
|
|
7061
|
+
maxDrawdown: "maxDrawdown",
|
|
7062
|
+
minAum: "asset"
|
|
7063
|
+
};
|
|
6820
7064
|
function readPoolFilters(args) {
|
|
7065
|
+
assertPoolFilterEnums(args, LEADERBOARD_POOL_FILTER_PROPS);
|
|
6821
7066
|
const result = {};
|
|
6822
|
-
for (const
|
|
7067
|
+
for (const [publicKey, upstreamKey] of Object.entries(LEADERBOARD_FILTER_UPSTREAM_NAMES)) {
|
|
7068
|
+
const val = readString(args, publicKey);
|
|
7069
|
+
if (val !== void 0 && val !== "") result[upstreamKey] = val;
|
|
7070
|
+
}
|
|
7071
|
+
if (result.sortBy === void 0) result.sortBy = "pnl";
|
|
7072
|
+
if (result.period === void 0) result.period = "90";
|
|
7073
|
+
return result;
|
|
7074
|
+
}
|
|
7075
|
+
function readSignalPoolFilters(args) {
|
|
7076
|
+
assertPoolFilterEnums(args, SIGNAL_POOL_FILTER_PROPS);
|
|
7077
|
+
const result = {};
|
|
7078
|
+
for (const key of Object.keys(SIGNAL_POOL_FILTER_PROPS)) {
|
|
6823
7079
|
const val = readString(args, key);
|
|
6824
7080
|
if (val) result[key] = val;
|
|
6825
7081
|
}
|
|
7082
|
+
if (result.sortBy === void 0) result.sortBy = "pnl";
|
|
7083
|
+
if (result.period === void 0) result.period = "7";
|
|
6826
7084
|
return result;
|
|
6827
7085
|
}
|
|
6828
|
-
function
|
|
6829
|
-
if (Array.isArray(data)) return data;
|
|
7086
|
+
function extractLeaderboardEnvelope(data) {
|
|
7087
|
+
if (Array.isArray(data)) return { items: data };
|
|
6830
7088
|
if (data && typeof data === "object") {
|
|
6831
|
-
const
|
|
6832
|
-
|
|
7089
|
+
const obj = data;
|
|
7090
|
+
const inner = obj.data;
|
|
7091
|
+
const updateTime = typeof obj.updateTime === "string" ? obj.updateTime : void 0;
|
|
7092
|
+
if (Array.isArray(inner)) return { items: inner, updateTime };
|
|
7093
|
+
}
|
|
7094
|
+
return { items: [] };
|
|
7095
|
+
}
|
|
7096
|
+
function deriveDirection(posSide, pos) {
|
|
7097
|
+
if (posSide === "long") return "long";
|
|
7098
|
+
if (posSide === "short") return "short";
|
|
7099
|
+
if ((posSide === "net" || posSide === "both") && typeof pos === "string" && pos !== "") {
|
|
7100
|
+
const n = Number(pos);
|
|
7101
|
+
if (Number.isFinite(n) && n !== 0) return n > 0 ? "long" : "short";
|
|
7102
|
+
}
|
|
7103
|
+
return void 0;
|
|
7104
|
+
}
|
|
7105
|
+
function extractPositionData(data) {
|
|
7106
|
+
if (!Array.isArray(data) || data.length === 0) return [];
|
|
7107
|
+
const first = data[0];
|
|
7108
|
+
if (first && typeof first === "object") {
|
|
7109
|
+
const posData = first.posData;
|
|
7110
|
+
if (Array.isArray(posData)) {
|
|
7111
|
+
return posData.map((row) => {
|
|
7112
|
+
if (!row || typeof row !== "object") return row;
|
|
7113
|
+
const r = row;
|
|
7114
|
+
const direction = deriveDirection(r.posSide, r.pos);
|
|
7115
|
+
return direction ? { ...r, direction } : r;
|
|
7116
|
+
});
|
|
7117
|
+
}
|
|
6833
7118
|
}
|
|
6834
7119
|
return [];
|
|
6835
7120
|
}
|
|
7121
|
+
function buildPagination(data, effectiveLimit, cursorField) {
|
|
7122
|
+
const hasMore = data.length >= effectiveLimit;
|
|
7123
|
+
const last = data.length > 0 ? data[data.length - 1] : void 0;
|
|
7124
|
+
const nextAfter = hasMore && last && typeof last === "object" && last !== null ? last[cursorField] : void 0;
|
|
7125
|
+
return nextAfter !== void 0 ? { hasMore, nextAfter } : { hasMore };
|
|
7126
|
+
}
|
|
7127
|
+
function extractBaseCcy(instId) {
|
|
7128
|
+
if (!instId) return void 0;
|
|
7129
|
+
const idx = instId.indexOf("-");
|
|
7130
|
+
const base = idx === -1 ? instId : instId.slice(0, idx);
|
|
7131
|
+
return base || void 0;
|
|
7132
|
+
}
|
|
7133
|
+
function actionableError(message, hint) {
|
|
7134
|
+
return new ValidationError(`${message} ${hint}`);
|
|
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
|
+
}
|
|
7152
|
+
function readArrayAsCsv(args, key) {
|
|
7153
|
+
const arr = readStringArray(args, key);
|
|
7154
|
+
if (!arr || arr.length === 0) return void 0;
|
|
7155
|
+
return arr.join(",");
|
|
7156
|
+
}
|
|
7157
|
+
function envelope(dataSchema, extras = {}) {
|
|
7158
|
+
return {
|
|
7159
|
+
type: "object",
|
|
7160
|
+
properties: {
|
|
7161
|
+
endpoint: {
|
|
7162
|
+
type: "string",
|
|
7163
|
+
description: "Upstream API path that produced this payload (debug/audit aid)."
|
|
7164
|
+
},
|
|
7165
|
+
requestTime: { type: "string", description: "ISO-8601 timestamp when the request was issued." },
|
|
7166
|
+
data: dataSchema,
|
|
7167
|
+
...extras
|
|
7168
|
+
},
|
|
7169
|
+
required: ["endpoint", "data"]
|
|
7170
|
+
};
|
|
7171
|
+
}
|
|
7172
|
+
var PAGINATION_PROP = {
|
|
7173
|
+
type: "object",
|
|
7174
|
+
description: "Cursor pagination metadata. Only emitted on list tools that support paging.",
|
|
7175
|
+
properties: {
|
|
7176
|
+
hasMore: {
|
|
7177
|
+
type: "boolean",
|
|
7178
|
+
description: "True when `data.length` reached the requested `limit` (more pages likely). False guarantees there are no more results after this page."
|
|
7179
|
+
},
|
|
7180
|
+
nextAfter: {
|
|
7181
|
+
type: "string",
|
|
7182
|
+
description: "Cursor to pass back as `after` on the next call to fetch the following page. Absent/empty when `hasMore` is false."
|
|
7183
|
+
}
|
|
7184
|
+
}
|
|
7185
|
+
};
|
|
7186
|
+
var TRADER_ITEM_PROPS = {
|
|
7187
|
+
authorId: { type: "string", description: "Trader's unique ID \u2014 pass to other smartmoney_get_trader_* tools." },
|
|
7188
|
+
nickName: { type: "string", description: "Display nickname." },
|
|
7189
|
+
pnl: { type: "string", description: "Absolute PnL in USD over the requested `period` (numeric string)." },
|
|
7190
|
+
pnlRatio: { type: "string", description: 'PnL as a decimal ratio over the requested `period` (e.g. "0.35" = +35%).' },
|
|
7191
|
+
asset: { type: "string", description: "AUM (Assets Under Management) in USD \u2014 same field that the input `minAum` filter applies to." },
|
|
7192
|
+
winRate: { type: "string", description: "Lifetime win-rate as a decimal (0~1)." },
|
|
7193
|
+
maxDrawdown: { type: "string", description: 'Max drawdown as a decimal (e.g. "0.2" = 20%). Lower = lower risk.' },
|
|
7194
|
+
onboardDuration: { type: "string", description: "Days the trader has been onboarded on the leaderboard (numeric string)." },
|
|
7195
|
+
portrait: { type: "string", description: "Avatar image URL." },
|
|
7196
|
+
rates: {
|
|
7197
|
+
type: "array",
|
|
7198
|
+
description: "Equity-curve / PnL-rate time series (one entry per day).",
|
|
7199
|
+
items: {
|
|
7200
|
+
type: "object",
|
|
7201
|
+
properties: {
|
|
7202
|
+
statTime: { type: "string", description: 'Date stamp in `YYMMDD` (e.g. "240726" = 2024-07-26).' },
|
|
7203
|
+
value: { type: "string", description: "Cumulative PnL ratio at that day (decimal)." }
|
|
7204
|
+
}
|
|
7205
|
+
}
|
|
7206
|
+
}
|
|
7207
|
+
};
|
|
7208
|
+
var SIGNAL_ITEM_PROPS = {
|
|
7209
|
+
ccy: { type: "string", description: "Instrument ID e.g. BTC-USDT-SWAP (outer identifier; the field name is `ccy`, not `instId`)." },
|
|
7210
|
+
dataVersion: {
|
|
7211
|
+
type: "string",
|
|
7212
|
+
description: "Snapshot version key in `yyyyMMddHH` UTC (10 digits, e.g. `2026043014` = 2026-04-30 14:00 UTC; floored to the hour)."
|
|
7213
|
+
},
|
|
7214
|
+
tradersWithPosition: {
|
|
7215
|
+
type: "integer",
|
|
7216
|
+
description: "Pool traders holding this asset at latest_snap (double-sided counted once). Higher = stronger consensus."
|
|
7217
|
+
},
|
|
7218
|
+
tradersQualified: {
|
|
7219
|
+
type: "integer",
|
|
7220
|
+
description: "Pool size after applying tier filters (incl. those without positions on this instrument)."
|
|
7221
|
+
},
|
|
7222
|
+
longTraders: { type: "integer", description: "Number of pool traders currently long this asset (incl. double-sided)." },
|
|
7223
|
+
shortTraders: { type: "integer", description: "Number of pool traders currently short this asset (incl. double-sided)." },
|
|
7224
|
+
notional: {
|
|
7225
|
+
type: "object",
|
|
7226
|
+
description: "Notional / capital-flow group.",
|
|
7227
|
+
properties: {
|
|
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
|
+
},
|
|
7244
|
+
totalNotionalVs24h: {
|
|
7245
|
+
type: "string",
|
|
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."
|
|
7247
|
+
},
|
|
7248
|
+
smartMoneyLongAvgEntry: {
|
|
7249
|
+
type: "string",
|
|
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.'
|
|
7251
|
+
},
|
|
7252
|
+
smartMoneyShortAvgEntry: {
|
|
7253
|
+
type: "string",
|
|
7254
|
+
description: 'Short-side notional-weighted average entry price (USDT). Empty string `""` when no short.'
|
|
7255
|
+
}
|
|
7256
|
+
}
|
|
7257
|
+
},
|
|
7258
|
+
longShortRatio: {
|
|
7259
|
+
type: "object",
|
|
7260
|
+
description: "Long/short ratio + historical-delta group.",
|
|
7261
|
+
properties: {
|
|
7262
|
+
longRatioVs1h: { type: "string", description: "longRatio \u2212 hist_1h.longRatio. NULL when no hist." },
|
|
7263
|
+
longRatioVs24h: { type: "string", description: "longRatio \u2212 hist_24h.longRatio. NULL when no hist." },
|
|
7264
|
+
longRatioVs7d: { type: "string", description: "longRatio \u2212 hist_7d.longRatio. NULL when no hist." },
|
|
7265
|
+
longRatio: { type: "string", description: "Headcount long ratio = longTraders / tradersWithPosition. NULL when no traders." },
|
|
7266
|
+
shortRatio: {
|
|
7267
|
+
type: "string",
|
|
7268
|
+
description: "Headcount short ratio = shortTraders / tradersWithPosition. NULL when no traders."
|
|
7269
|
+
},
|
|
7270
|
+
weightedLongRatio: {
|
|
7271
|
+
type: "string",
|
|
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."
|
|
7273
|
+
},
|
|
7274
|
+
weightedShortRatio: {
|
|
7275
|
+
type: "string",
|
|
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."
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
7279
|
+
},
|
|
7280
|
+
winRate: {
|
|
7281
|
+
type: "object",
|
|
7282
|
+
description: "Capability (historical performance) group; driven by the `period` window.",
|
|
7283
|
+
properties: {
|
|
7284
|
+
avgLongWinRate: {
|
|
7285
|
+
type: "string",
|
|
7286
|
+
description: "Mean closed-position win-rate (full-market) over `period` days for users currently long. NULL when closed-position sample size is below the configured minimum."
|
|
7287
|
+
},
|
|
7288
|
+
avgShortWinRate: {
|
|
7289
|
+
type: "string",
|
|
7290
|
+
description: "Mean closed-position win-rate (full-market) over `period` days for users currently short. NULL when sample is below threshold."
|
|
7291
|
+
}
|
|
7292
|
+
}
|
|
7293
|
+
}
|
|
7294
|
+
};
|
|
7295
|
+
var SIGNAL_HISTORY_ITEM_PROPS = {
|
|
7296
|
+
ccy: { type: "string", description: "Base currency / instrument key for this bucket." },
|
|
7297
|
+
longRatio: {
|
|
7298
|
+
type: "string",
|
|
7299
|
+
description: "Headcount long ratio at this bucket. Decimal 0~1."
|
|
7300
|
+
},
|
|
7301
|
+
shortRatio: {
|
|
7302
|
+
type: "string",
|
|
7303
|
+
description: "Headcount short ratio at this bucket = shortTraders / tradersWithPosition. Decimal 0~1."
|
|
7304
|
+
},
|
|
7305
|
+
weightedLongRatio: {
|
|
7306
|
+
type: "string",
|
|
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."
|
|
7308
|
+
},
|
|
7309
|
+
weightedShortRatio: {
|
|
7310
|
+
type: "string",
|
|
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."
|
|
7312
|
+
},
|
|
7313
|
+
longTraders: {
|
|
7314
|
+
type: "integer",
|
|
7315
|
+
description: "Number of traders with long exposure at this bucket (includes dual-side traders)."
|
|
7316
|
+
},
|
|
7317
|
+
shortTraders: {
|
|
7318
|
+
type: "integer",
|
|
7319
|
+
description: "Number of traders with short exposure at this bucket (includes dual-side traders)."
|
|
7320
|
+
},
|
|
7321
|
+
tradersWithPosition: {
|
|
7322
|
+
type: "integer",
|
|
7323
|
+
description: "Pool traders holding this asset at this bucket. Few traders = unreliable signal."
|
|
7324
|
+
},
|
|
7325
|
+
netNotionalUsdt: {
|
|
7326
|
+
type: "string",
|
|
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."
|
|
7328
|
+
},
|
|
7329
|
+
totalNotionalUsdt: {
|
|
7330
|
+
type: "string",
|
|
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."
|
|
7332
|
+
},
|
|
7333
|
+
tradersQualified: { type: "integer", description: "Pool size after applying tier filters (includes traders without a position)." },
|
|
7334
|
+
dataVersion: { type: "string", description: "Snapshot version key in `yyyyMMddHH` UTC (10-digit, e.g. `2026042820`)." }
|
|
7335
|
+
};
|
|
6836
7336
|
function registerSmartmoneyTools() {
|
|
6837
7337
|
const tools = [
|
|
6838
|
-
/*
|
|
7338
|
+
/* ===================================================== */
|
|
7339
|
+
/* Trader family (6) */
|
|
7340
|
+
/* ===================================================== */
|
|
7341
|
+
/* ---------- T1. Top traders (leaderboard rank) ---------- */
|
|
6839
7342
|
{
|
|
6840
|
-
name: "
|
|
7343
|
+
name: "smartmoney_get_traders_by_filter",
|
|
6841
7344
|
module: "smartmoney",
|
|
6842
|
-
description: "
|
|
7345
|
+
description: "Leaderboard ranking of OKX smart-money traders, filtered by pool conditions and ranked by `sortBy`. Use when: discovering top performers by criteria (PnL / win-rate / drawdown / AUM). See also: `smartmoney_get_performance_by_trader` (lookup by ID), `smartmoney_search_trader` (lookup by nickname). Note: `updateTime` is 12-digit `yyyyMMddHHmm` UTC+8, different from signal tools' 10-digit UTC `asOfTime`/`dataVersion` \u2014 do not cross-pass.",
|
|
6843
7346
|
isWrite: false,
|
|
7347
|
+
outputSchema: envelope(
|
|
7348
|
+
{ type: "array", items: { type: "object", properties: TRADER_ITEM_PROPS } },
|
|
7349
|
+
{
|
|
7350
|
+
updateTime: {
|
|
7351
|
+
type: "string",
|
|
7352
|
+
description: "Snapshot version of the leaderboard, in `yyyyMMddHHmm` (UTC+8, e.g. `202604301815`). Lives at the response top level (shared by every item in `data`), NOT inside each trader row. Refreshed approximately every 5 minutes."
|
|
7353
|
+
},
|
|
7354
|
+
pagination: PAGINATION_PROP
|
|
7355
|
+
}
|
|
7356
|
+
),
|
|
6844
7357
|
inputSchema: {
|
|
6845
7358
|
type: "object",
|
|
6846
7359
|
properties: {
|
|
6847
|
-
|
|
6848
|
-
type: "string",
|
|
6849
|
-
description: "Recommended. Timestamp ms \u2014 use Date.now() for latest."
|
|
6850
|
-
},
|
|
6851
|
-
dataVersion: {
|
|
6852
|
-
type: "string",
|
|
6853
|
-
description: "Alternative. yyyyMMddHHmm UTC for prior snapshot. If both sent, ts wins."
|
|
6854
|
-
},
|
|
6855
|
-
instType: {
|
|
6856
|
-
type: "string",
|
|
6857
|
-
description: "SPOT|MARGIN|FUTURES|SWAP|OPTION (default SWAP)"
|
|
6858
|
-
},
|
|
6859
|
-
...SIGNAL_POOL_FILTER_PROPS,
|
|
6860
|
-
lmtNum: {
|
|
7360
|
+
updateTime: {
|
|
6861
7361
|
type: "string",
|
|
6862
|
-
description:
|
|
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).'
|
|
6863
7363
|
},
|
|
6864
|
-
|
|
7364
|
+
...LEADERBOARD_POOL_FILTER_PROPS,
|
|
7365
|
+
after: {
|
|
6865
7366
|
type: "string",
|
|
6866
|
-
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.'
|
|
6867
7368
|
},
|
|
6868
|
-
|
|
7369
|
+
before: {
|
|
6869
7370
|
type: "string",
|
|
6870
|
-
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.'
|
|
6871
7372
|
},
|
|
6872
|
-
|
|
6873
|
-
type: "
|
|
6874
|
-
|
|
7373
|
+
limit: {
|
|
7374
|
+
type: "integer",
|
|
7375
|
+
minimum: 1,
|
|
7376
|
+
maximum: 100,
|
|
7377
|
+
default: 10,
|
|
7378
|
+
description: "Max results per page (default 10, max 100)."
|
|
6875
7379
|
}
|
|
6876
|
-
}
|
|
7380
|
+
},
|
|
7381
|
+
required: ["sortBy", "period"]
|
|
6877
7382
|
},
|
|
6878
7383
|
handler: async (rawArgs, context) => {
|
|
6879
7384
|
const args = asRecord(rawArgs);
|
|
6880
|
-
const
|
|
6881
|
-
const ts = readString(args, "ts");
|
|
6882
|
-
if (!dv && !ts) {
|
|
6883
|
-
throw new ValidationError('Either "dataVersion" or "ts" is required for smartmoney_get_overview.');
|
|
6884
|
-
}
|
|
7385
|
+
const limit = readNumber(args, "limit");
|
|
6885
7386
|
const response = await context.client.privateGet(
|
|
6886
|
-
|
|
7387
|
+
PATH_LEADERBOARD,
|
|
6887
7388
|
compactObject({
|
|
6888
|
-
|
|
6889
|
-
ts,
|
|
6890
|
-
instType: readString(args, "instType"),
|
|
7389
|
+
updateTime: readString(args, "updateTime"),
|
|
6891
7390
|
...readPoolFilters(args),
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
topInstruments: readString(args, "topInstruments")
|
|
7391
|
+
after: readString(args, "after"),
|
|
7392
|
+
before: readString(args, "before"),
|
|
7393
|
+
limit
|
|
6896
7394
|
}),
|
|
6897
|
-
publicRateLimit("
|
|
7395
|
+
publicRateLimit("smartmoney_get_traders_by_filter", SMARTMONEY_RPS)
|
|
6898
7396
|
);
|
|
6899
|
-
|
|
7397
|
+
const normalized = normalizeResponse(response);
|
|
7398
|
+
const { items, updateTime } = extractLeaderboardEnvelope(normalized.data);
|
|
7399
|
+
return {
|
|
7400
|
+
...normalized,
|
|
7401
|
+
data: items,
|
|
7402
|
+
...updateTime ? { updateTime } : {},
|
|
7403
|
+
pagination: buildPagination(items, limit ?? 10, "authorId")
|
|
7404
|
+
};
|
|
6900
7405
|
}
|
|
6901
7406
|
},
|
|
6902
|
-
/* ----------
|
|
7407
|
+
/* ---------- T2. Trader performance (by authorIds) ---------- */
|
|
6903
7408
|
{
|
|
6904
|
-
name: "
|
|
7409
|
+
name: "smartmoney_get_performance_by_trader",
|
|
6905
7410
|
module: "smartmoney",
|
|
6906
|
-
description: "
|
|
7411
|
+
description: "PnL / win-rate / drawdown profile for one or more traders looked up by `authorIds`. Use when: caller already has trader IDs and needs their performance metrics. See also: `smartmoney_search_trader` (resolve nickname \u2192 authorId), `smartmoney_get_traders_by_filter` (criteria-based discovery). Note: response `updateTime` is 12-digit `yyyyMMddHHmm` UTC+8 \u2014 do not pass to signal-side tools' `asOfTime` (10-digit UTC).",
|
|
6907
7412
|
isWrite: false,
|
|
7413
|
+
outputSchema: envelope(
|
|
7414
|
+
{ type: "array", items: { type: "object", properties: TRADER_ITEM_PROPS } },
|
|
7415
|
+
{
|
|
7416
|
+
updateTime: {
|
|
7417
|
+
type: "string",
|
|
7418
|
+
description: "Snapshot version of the leaderboard, in `yyyyMMddHHmm` (UTC+8, e.g. `202604301815`). Lives at the response top level (shared by every item in `data`), NOT inside each trader row."
|
|
7419
|
+
}
|
|
7420
|
+
}
|
|
7421
|
+
),
|
|
6908
7422
|
inputSchema: {
|
|
6909
7423
|
type: "object",
|
|
6910
7424
|
properties: {
|
|
6911
|
-
|
|
6912
|
-
type: "
|
|
6913
|
-
|
|
7425
|
+
authorIds: {
|
|
7426
|
+
type: "array",
|
|
7427
|
+
items: { type: "string" },
|
|
7428
|
+
minItems: 1,
|
|
7429
|
+
description: 'Trader IDs to look up, e.g. `["1001", "1002"]`. Required.'
|
|
6914
7430
|
},
|
|
6915
|
-
|
|
7431
|
+
sortBy: {
|
|
6916
7432
|
type: "string",
|
|
6917
|
-
|
|
7433
|
+
enum: ["pnl", "pnlRatio"],
|
|
7434
|
+
default: "pnl",
|
|
7435
|
+
description: 'Required. Result sort key. `pnl` = absolute USD profit; `pnlRatio` = percentage return. Default `"pnl"`.'
|
|
6918
7436
|
},
|
|
6919
|
-
|
|
7437
|
+
period: {
|
|
6920
7438
|
type: "string",
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
7439
|
+
enum: PERIOD_DAYS,
|
|
7440
|
+
default: "90",
|
|
7441
|
+
description: 'Required. Performance lookback window in days. One of `"3"` / `"7"` / `"30"` / `"90"`. Default `"90"`.'
|
|
7442
|
+
}
|
|
7443
|
+
},
|
|
7444
|
+
required: ["authorIds", "sortBy", "period"]
|
|
7445
|
+
},
|
|
7446
|
+
handler: async (rawArgs, context) => {
|
|
7447
|
+
const args = asRecord(rawArgs);
|
|
7448
|
+
assertEnum2(args, "sortBy", ["pnl", "pnlRatio"]);
|
|
7449
|
+
assertEnum2(args, "period", PERIOD_DAYS);
|
|
7450
|
+
const authorIds = readArrayAsCsv(args, "authorIds");
|
|
7451
|
+
if (!authorIds) {
|
|
7452
|
+
throw actionableError(
|
|
7453
|
+
'"authorIds" is required and must be a non-empty array.',
|
|
7454
|
+
'Discover trader IDs via `smartmoney_get_traders_by_filter`, then pass them as an array (e.g. ["1001", "1002"]).'
|
|
7455
|
+
);
|
|
7456
|
+
}
|
|
7457
|
+
const response = await context.client.privateGet(
|
|
7458
|
+
PATH_LEADERBOARD,
|
|
7459
|
+
compactObject({
|
|
7460
|
+
authorIds,
|
|
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"
|
|
7465
|
+
}),
|
|
7466
|
+
publicRateLimit("smartmoney_get_performance_by_trader", SMARTMONEY_RPS)
|
|
7467
|
+
);
|
|
7468
|
+
const normalized = normalizeResponse(response);
|
|
7469
|
+
const { items, updateTime } = extractLeaderboardEnvelope(normalized.data);
|
|
7470
|
+
return {
|
|
7471
|
+
...normalized,
|
|
7472
|
+
data: items,
|
|
7473
|
+
...updateTime ? { updateTime } : {}
|
|
7474
|
+
};
|
|
7475
|
+
}
|
|
7476
|
+
},
|
|
7477
|
+
/* ---------- T3. Trader current positions ---------- */
|
|
7478
|
+
{
|
|
7479
|
+
name: "smartmoney_get_trader_positions",
|
|
7480
|
+
module: "smartmoney",
|
|
7481
|
+
description: "Currently-open positions held by a single trader (direction, size, leverage, entry, conviction). Use when: inspecting what a top trader is holding RIGHT NOW. See also: `smartmoney_get_trader_positions_history` (closed positions), `smartmoney_search_trader` (nickname \u2192 authorId), `smartmoney_get_traders_by_filter` (discover trader).",
|
|
7482
|
+
isWrite: false,
|
|
7483
|
+
outputSchema: envelope({
|
|
7484
|
+
type: "array",
|
|
7485
|
+
items: {
|
|
7486
|
+
type: "object",
|
|
7487
|
+
properties: {
|
|
7488
|
+
posId: { type: "string", description: "Unique position ID. Stable across the position's lifetime." },
|
|
7489
|
+
instId: { type: "string", description: "Instrument ID e.g. BTC-USDT-SWAP." },
|
|
7490
|
+
instType: {
|
|
7491
|
+
type: "string",
|
|
7492
|
+
description: "Instrument business line: `SWAP` (perpetual) | `SPOT` | `FUTURES` (delivery) | `MARGIN` | `OPTION`."
|
|
7493
|
+
},
|
|
7494
|
+
posSide: {
|
|
7495
|
+
type: "string",
|
|
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."
|
|
7497
|
+
},
|
|
7498
|
+
direction: {
|
|
7499
|
+
type: "string",
|
|
7500
|
+
enum: ["long", "short"],
|
|
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.'
|
|
7502
|
+
},
|
|
7503
|
+
posCcy: { type: "string", description: 'Position currency \u2014 the asset being held, e.g. "BTC".' },
|
|
7504
|
+
quoteCcy: { type: "string", description: 'Quote currency the position is priced/settled in, e.g. "USDT".' },
|
|
7505
|
+
pos: {
|
|
7506
|
+
type: "string",
|
|
7507
|
+
description: "Position size (numeric string). Unit depends on instType: coins for SPOT/MARGIN, contracts (\u5F20) for SWAP/FUTURES/OPTION."
|
|
7508
|
+
},
|
|
7509
|
+
lever: { type: "string", description: 'Leverage multiplier (numeric string; "1" for spot).' },
|
|
7510
|
+
avgPx: { type: "string", description: "Volume-weighted average entry price (numeric string)." },
|
|
7511
|
+
last: { type: "string", description: "Latest market/mark price for the instrument (numeric string)." },
|
|
7512
|
+
notionalUsd: { type: "string", description: "Current position notional value in USD." },
|
|
7513
|
+
upl: { type: "string", description: "Unrealized (floating) PnL, denominated in `quoteCcy`." },
|
|
7514
|
+
pnl: { type: "string", description: "Realized PnL accrued on this position so far, denominated in `quoteCcy`." },
|
|
7515
|
+
cTime: { type: "string", description: "Position open time as Unix milliseconds (numeric string)." },
|
|
7516
|
+
positionIntensity: {
|
|
7517
|
+
type: "string",
|
|
7518
|
+
description: "Conviction metric = notionalUsd / trader.asset (this position's notional as a share of the trader's AUM). Higher = the trader is betting a larger fraction of their book on this position."
|
|
7519
|
+
}
|
|
7520
|
+
}
|
|
7521
|
+
}
|
|
7522
|
+
}),
|
|
7523
|
+
inputSchema: {
|
|
7524
|
+
type: "object",
|
|
7525
|
+
properties: {
|
|
7526
|
+
authorId: {
|
|
6929
7527
|
type: "string",
|
|
6930
|
-
description: "Trader
|
|
7528
|
+
description: "Trader's unique ID (obtain from `smartmoney_get_traders_by_filter`)."
|
|
6931
7529
|
},
|
|
6932
|
-
|
|
7530
|
+
instId: {
|
|
6933
7531
|
type: "string",
|
|
6934
|
-
description: "
|
|
7532
|
+
description: 'Optional instrument filter. Accepts either full instId (e.g. "BTC-USDT-SWAP") or bare base currency (e.g. "BTC") \u2014 the handler extracts the base currency for the upstream filter.'
|
|
6935
7533
|
}
|
|
6936
|
-
}
|
|
7534
|
+
},
|
|
7535
|
+
required: ["authorId"]
|
|
6937
7536
|
},
|
|
6938
7537
|
handler: async (rawArgs, context) => {
|
|
6939
7538
|
const args = asRecord(rawArgs);
|
|
6940
|
-
const
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
const ts = readString(args, "ts");
|
|
6947
|
-
if (!dv && !ts) {
|
|
6948
|
-
throw new ValidationError('Either "dataVersion" or "ts" is required for smartmoney_get_signal.');
|
|
7539
|
+
const authorId = readString(args, "authorId");
|
|
7540
|
+
if (!authorId) {
|
|
7541
|
+
throw actionableError(
|
|
7542
|
+
'"authorId" is required.',
|
|
7543
|
+
"Discover trader IDs via `smartmoney_get_traders_by_filter` and pass one ID here."
|
|
7544
|
+
);
|
|
6949
7545
|
}
|
|
6950
7546
|
const response = await context.client.privateGet(
|
|
6951
|
-
|
|
7547
|
+
PATH_POSITION_CURRENT,
|
|
6952
7548
|
compactObject({
|
|
6953
|
-
|
|
6954
|
-
instCcy,
|
|
6955
|
-
dataVersion: dv,
|
|
6956
|
-
ts,
|
|
6957
|
-
...readPoolFilters(args),
|
|
6958
|
-
lmtNum: readString(args, "lmtNum"),
|
|
6959
|
-
authorIds: readString(args, "authorIds")
|
|
7549
|
+
authorId,
|
|
7550
|
+
instCcy: extractBaseCcy(readString(args, "instId"))
|
|
6960
7551
|
}),
|
|
6961
|
-
publicRateLimit("
|
|
7552
|
+
publicRateLimit("smartmoney_get_trader_positions", SMARTMONEY_RPS)
|
|
6962
7553
|
);
|
|
6963
|
-
|
|
7554
|
+
const normalized = normalizeResponse(response);
|
|
7555
|
+
return { ...normalized, data: extractPositionData(normalized.data) };
|
|
6964
7556
|
}
|
|
6965
7557
|
},
|
|
6966
|
-
/* ----------
|
|
7558
|
+
/* ---------- T4. Trader closed-position history ---------- */
|
|
6967
7559
|
{
|
|
6968
|
-
name: "
|
|
7560
|
+
name: "smartmoney_get_trader_positions_history",
|
|
6969
7561
|
module: "smartmoney",
|
|
6970
|
-
description: "
|
|
7562
|
+
description: "Closed-position history of a single trader, paginated by `posId` cursor. Use when: studying realized PnL pattern, holding duration, win/loss streaks, or how positions ended (closed vs liquidated). See also: `smartmoney_get_trader_positions` (currently-open), `smartmoney_search_trader` (nickname \u2192 authorId), `smartmoney_get_traders_by_filter` (discover trader).",
|
|
6971
7563
|
isWrite: false,
|
|
7564
|
+
outputSchema: envelope(
|
|
7565
|
+
{
|
|
7566
|
+
type: "array",
|
|
7567
|
+
items: {
|
|
7568
|
+
type: "object",
|
|
7569
|
+
properties: {
|
|
7570
|
+
posId: { type: "string", description: "Unique closed-position ID. Use as the `after` / `before` cursor when paginating." },
|
|
7571
|
+
instId: { type: "string", description: "Instrument ID e.g. BTC-USDT-SWAP." },
|
|
7572
|
+
instType: {
|
|
7573
|
+
type: "string",
|
|
7574
|
+
description: "Instrument business line: `SWAP` (perpetual) | `FUTURES` (delivery) | `MARGIN` | `SPOT`."
|
|
7575
|
+
},
|
|
7576
|
+
ctVal: {
|
|
7577
|
+
type: "string",
|
|
7578
|
+
description: "Contract face value \u2014 USD value of a single contract (\u5F20). Numeric string. Empty/0 for non-contract instruments."
|
|
7579
|
+
},
|
|
7580
|
+
posSide: {
|
|
7581
|
+
type: "string",
|
|
7582
|
+
description: "Position direction at close. `long` = was long-side; `short` = was short-side."
|
|
7583
|
+
},
|
|
7584
|
+
lever: { type: "string", description: "Leverage multiplier used for this position (numeric string)." },
|
|
7585
|
+
mgnMode: {
|
|
7586
|
+
type: "string",
|
|
7587
|
+
description: "Margin mode used for this position. `cross` = cross-margin (shared collateral pool); `isolated` = isolated-margin (per-position collateral)."
|
|
7588
|
+
},
|
|
7589
|
+
marginCcy: {
|
|
7590
|
+
type: "string",
|
|
7591
|
+
description: 'Margin currency held as collateral for this position, e.g. "BTC" or "USDT".'
|
|
7592
|
+
},
|
|
7593
|
+
quoteCcy: { type: "string", description: 'Quote currency the position settled in, e.g. "USDT".' },
|
|
7594
|
+
openAvgPx: { type: "string", description: "Volume-weighted average price across all open fills (numeric string)." },
|
|
7595
|
+
closeAvgPx: { type: "string", description: "Volume-weighted average price across all close fills (numeric string)." },
|
|
7596
|
+
openMaxAmount: {
|
|
7597
|
+
type: "string",
|
|
7598
|
+
description: "Peak position size held during the position's lifetime, in contracts (\u5F20)."
|
|
7599
|
+
},
|
|
7600
|
+
closeAmount: {
|
|
7601
|
+
type: "string",
|
|
7602
|
+
description: "Total amount closed across all close fills, in contracts for SWAP/FUTURES or in base currency for SPOT/MARGIN (numeric string)."
|
|
7603
|
+
},
|
|
7604
|
+
realizedPnl: { type: "string", description: "Cumulative realized PnL during the position's lifetime, in `quoteCcy` units." },
|
|
7605
|
+
pnl: {
|
|
7606
|
+
type: "string",
|
|
7607
|
+
description: "Total realized PnL for this position including fees and funding, denominated in quoteCcy (numeric string). Differs from `realizedPnl` which may exclude fees."
|
|
7608
|
+
},
|
|
7609
|
+
pnlRatio: {
|
|
7610
|
+
type: "string",
|
|
7611
|
+
description: 'Realized PnL as a decimal ratio of cost basis (e.g. "0.15" = +15%, "-0.20" = \u221220%).'
|
|
7612
|
+
},
|
|
7613
|
+
fee: {
|
|
7614
|
+
type: "string",
|
|
7615
|
+
description: "Cumulative trading fee paid over the position's lifetime, denominated in quoteCcy (numeric string, negative = cost)."
|
|
7616
|
+
},
|
|
7617
|
+
fundingFee: {
|
|
7618
|
+
type: "string",
|
|
7619
|
+
description: "Cumulative funding fee paid or received over the position's lifetime, denominated in quoteCcy (numeric string; negative = paid, positive = received)."
|
|
7620
|
+
},
|
|
7621
|
+
liquidationStatus: {
|
|
7622
|
+
type: "string",
|
|
7623
|
+
description: 'Whether the position was liquidated. `"0"` = normal close (not liquidated); `"1"` = liquidated. Use this dedicated field for liquidation checks; `closeType` may also encode liquidation via the `liquidateClose` / `liquidateReceive` / `adl` values.'
|
|
7624
|
+
},
|
|
7625
|
+
closeType: {
|
|
7626
|
+
type: "string",
|
|
7627
|
+
description: "How the position was closed. `allClose` = entire position closed in one action; `partClose` = partially closed (position reduced but not fully exited); `liquidateClose` = forced liquidation; `liquidateReceive` = received liquidation transfer; `adl` = auto-deleveraging."
|
|
7628
|
+
},
|
|
7629
|
+
cTime: { type: "string", description: "Position open time as Unix milliseconds (numeric string)." },
|
|
7630
|
+
uTime: { type: "string", description: "Position close time as Unix milliseconds (numeric string)." }
|
|
7631
|
+
}
|
|
7632
|
+
}
|
|
7633
|
+
},
|
|
7634
|
+
{ pagination: PAGINATION_PROP }
|
|
7635
|
+
),
|
|
6972
7636
|
inputSchema: {
|
|
6973
7637
|
type: "object",
|
|
6974
7638
|
properties: {
|
|
6975
|
-
|
|
7639
|
+
authorId: {
|
|
6976
7640
|
type: "string",
|
|
6977
|
-
description: "
|
|
7641
|
+
description: "Trader's unique ID (obtain from `smartmoney_get_traders_by_filter`)."
|
|
6978
7642
|
},
|
|
6979
|
-
|
|
7643
|
+
instId: {
|
|
6980
7644
|
type: "string",
|
|
6981
|
-
description:
|
|
7645
|
+
description: 'Optional instrument filter. Accepts either full instId (e.g. "BTC-USDT-SWAP") or bare base currency (e.g. "BTC") \u2014 the handler extracts the base currency for the upstream filter.'
|
|
6982
7646
|
},
|
|
6983
|
-
|
|
7647
|
+
after: {
|
|
6984
7648
|
type: "string",
|
|
6985
|
-
description:
|
|
7649
|
+
description: 'Pagination cursor (older) \u2014 returns positions with `posId` smaller than this value. Pass the `posId` as a string, e.g. `"872913470357110787"`.'
|
|
6986
7650
|
},
|
|
6987
|
-
|
|
7651
|
+
before: {
|
|
6988
7652
|
type: "string",
|
|
6989
|
-
description:
|
|
7653
|
+
description: 'Pagination cursor (newer) \u2014 returns positions with `posId` greater than this value. Pass the `posId` as a string, e.g. `"872913470357110787"`.'
|
|
6990
7654
|
},
|
|
6991
7655
|
limit: {
|
|
6992
|
-
type: "
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
7656
|
+
type: "integer",
|
|
7657
|
+
minimum: 1,
|
|
7658
|
+
maximum: 100,
|
|
7659
|
+
default: 10,
|
|
7660
|
+
description: "Max positions per page (default 10, max 100)."
|
|
7661
|
+
}
|
|
6996
7662
|
},
|
|
6997
|
-
required: ["
|
|
7663
|
+
required: ["authorId"]
|
|
6998
7664
|
},
|
|
6999
7665
|
handler: async (rawArgs, context) => {
|
|
7000
7666
|
const args = asRecord(rawArgs);
|
|
7001
|
-
const
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7667
|
+
const authorId = readString(args, "authorId");
|
|
7668
|
+
if (!authorId) {
|
|
7669
|
+
throw actionableError(
|
|
7670
|
+
'"authorId" is required.',
|
|
7671
|
+
"Discover trader IDs via `smartmoney_get_traders_by_filter`."
|
|
7672
|
+
);
|
|
7005
7673
|
}
|
|
7674
|
+
const limit = readNumber(args, "limit");
|
|
7006
7675
|
const response = await context.client.privateGet(
|
|
7007
|
-
|
|
7676
|
+
PATH_POSITION_HISTORY,
|
|
7008
7677
|
compactObject({
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
limit
|
|
7014
|
-
...readPoolFilters(args)
|
|
7678
|
+
authorId,
|
|
7679
|
+
instCcy: extractBaseCcy(readString(args, "instId")),
|
|
7680
|
+
after: readString(args, "after"),
|
|
7681
|
+
before: readString(args, "before"),
|
|
7682
|
+
limit
|
|
7015
7683
|
}),
|
|
7016
|
-
publicRateLimit("
|
|
7684
|
+
publicRateLimit("smartmoney_get_trader_positions_history", SMARTMONEY_RPS)
|
|
7017
7685
|
);
|
|
7018
|
-
|
|
7686
|
+
const normalized = normalizeResponse(response);
|
|
7687
|
+
const data = Array.isArray(normalized.data) ? normalized.data : [];
|
|
7688
|
+
return {
|
|
7689
|
+
...normalized,
|
|
7690
|
+
data,
|
|
7691
|
+
pagination: buildPagination(data, limit ?? 10, "posId")
|
|
7692
|
+
};
|
|
7019
7693
|
}
|
|
7020
7694
|
},
|
|
7021
|
-
/* ----------
|
|
7695
|
+
/* ---------- T5. Trader order history ---------- */
|
|
7022
7696
|
{
|
|
7023
|
-
name: "
|
|
7697
|
+
name: "smartmoney_get_trader_orders_history",
|
|
7024
7698
|
module: "smartmoney",
|
|
7025
|
-
description: "
|
|
7699
|
+
description: "Recent orders/fills placed by a single trader (direction, size, price, leverage), paginated by `ordId` cursor. Aligned with the cross-module `*_get_orders` family. Use when: tracking a top trader's latest trade activity. See also: `smartmoney_search_trader` (nickname \u2192 authorId), `smartmoney_get_traders_by_filter` (discover trader).",
|
|
7026
7700
|
isWrite: false,
|
|
7701
|
+
outputSchema: envelope(
|
|
7702
|
+
{
|
|
7703
|
+
type: "array",
|
|
7704
|
+
items: {
|
|
7705
|
+
type: "object",
|
|
7706
|
+
properties: {
|
|
7707
|
+
ordId: { type: "string", description: "Unique order ID. Use as the `after` / `before` cursor when paginating." },
|
|
7708
|
+
instId: { type: "string", description: "Instrument ID e.g. BTC-USDT-SWAP." },
|
|
7709
|
+
displayId: { type: "string", description: "Display-form instrument ID used in OKX UI." },
|
|
7710
|
+
instType: {
|
|
7711
|
+
type: "string",
|
|
7712
|
+
description: "Instrument business line: `SWAP` (perpetual contract) | `SPOT`."
|
|
7713
|
+
},
|
|
7714
|
+
baseName: { type: "string", description: 'Base currency symbol, e.g. "BTC".' },
|
|
7715
|
+
quoteName: { type: "string", description: 'Quote currency symbol, e.g. "USD".' },
|
|
7716
|
+
tradeQuoteCcy: { type: "string", description: "Quote currency the fill actually settled in." },
|
|
7717
|
+
side: {
|
|
7718
|
+
type: "string",
|
|
7719
|
+
description: "Order side. `buy` = open long / close short; `sell` = open short / close long."
|
|
7720
|
+
},
|
|
7721
|
+
posSide: {
|
|
7722
|
+
type: "string",
|
|
7723
|
+
description: "Position direction the order applies to: `long` | `short`. Indicates whether the trader was opening/closing a long-side or short-side position."
|
|
7724
|
+
},
|
|
7725
|
+
ordType: {
|
|
7726
|
+
type: "string",
|
|
7727
|
+
description: "Order type. `limit` = price-protected limit order; `market` = immediate at best available price."
|
|
7728
|
+
},
|
|
7729
|
+
lever: { type: "string", description: 'Leverage multiplier used for this order (numeric string; "1" for spot).' },
|
|
7730
|
+
px: { type: "string", description: "Submitted order price (numeric string). For market orders this may be empty/0." },
|
|
7731
|
+
avgPx: { type: "string", description: "Volume-weighted average fill price (numeric string)." },
|
|
7732
|
+
sz: {
|
|
7733
|
+
type: "string",
|
|
7734
|
+
description: "Order size. Unit depends on instType: coins (\u5E01) for SPOT, contracts (\u5F20) for SWAP/FUTURES."
|
|
7735
|
+
},
|
|
7736
|
+
value: {
|
|
7737
|
+
type: "string",
|
|
7738
|
+
description: "Order notional value, denominated in `quoteName` units."
|
|
7739
|
+
},
|
|
7740
|
+
cTime: { type: "string", description: "Order creation time as Unix milliseconds (numeric string)." },
|
|
7741
|
+
fillTime: {
|
|
7742
|
+
type: "string",
|
|
7743
|
+
description: "Timestamp when the order was last filled, as Unix milliseconds (numeric string)."
|
|
7744
|
+
},
|
|
7745
|
+
uTime: {
|
|
7746
|
+
type: "string",
|
|
7747
|
+
description: "Timestamp when the order record was last updated, as Unix milliseconds (numeric string)."
|
|
7748
|
+
}
|
|
7749
|
+
}
|
|
7750
|
+
}
|
|
7751
|
+
},
|
|
7752
|
+
{ pagination: PAGINATION_PROP }
|
|
7753
|
+
),
|
|
7027
7754
|
inputSchema: {
|
|
7028
7755
|
type: "object",
|
|
7029
7756
|
properties: {
|
|
7030
|
-
|
|
7757
|
+
authorId: {
|
|
7031
7758
|
type: "string",
|
|
7032
|
-
description: "
|
|
7759
|
+
description: "Trader's unique ID (obtain from `smartmoney_get_traders_by_filter`)."
|
|
7033
7760
|
},
|
|
7034
|
-
|
|
7035
|
-
authorIds: {
|
|
7761
|
+
instId: {
|
|
7036
7762
|
type: "string",
|
|
7037
|
-
description: "
|
|
7763
|
+
description: 'Optional instrument filter. Accepts either full instId (e.g. "BTC-USDT-SWAP") or bare base currency (e.g. "BTC") \u2014 the handler extracts the base currency for the upstream filter.'
|
|
7038
7764
|
},
|
|
7039
7765
|
after: {
|
|
7040
7766
|
type: "string",
|
|
7041
|
-
description:
|
|
7767
|
+
description: 'Pagination cursor (older) \u2014 returns trades with `ordId` smaller than this value. Pass the `ordId` as a string, e.g. `"872913470357110787"`.'
|
|
7042
7768
|
},
|
|
7043
7769
|
before: {
|
|
7044
7770
|
type: "string",
|
|
7045
|
-
description:
|
|
7771
|
+
description: 'Pagination cursor (newer) \u2014 returns trades with `ordId` greater than this value. Pass the `ordId` as a string, e.g. `"872913470357110787"`.'
|
|
7046
7772
|
},
|
|
7047
7773
|
limit: {
|
|
7048
|
-
type: "
|
|
7049
|
-
|
|
7774
|
+
type: "integer",
|
|
7775
|
+
minimum: 1,
|
|
7776
|
+
maximum: 100,
|
|
7777
|
+
default: 10,
|
|
7778
|
+
description: "Max trades per page (default 10, max 100)."
|
|
7050
7779
|
}
|
|
7051
|
-
}
|
|
7780
|
+
},
|
|
7781
|
+
required: ["authorId"]
|
|
7052
7782
|
},
|
|
7053
7783
|
handler: async (rawArgs, context) => {
|
|
7054
7784
|
const args = asRecord(rawArgs);
|
|
7785
|
+
const authorId = readString(args, "authorId");
|
|
7786
|
+
if (!authorId) {
|
|
7787
|
+
throw actionableError(
|
|
7788
|
+
'"authorId" is required.',
|
|
7789
|
+
"Discover trader IDs via `smartmoney_get_traders_by_filter`."
|
|
7790
|
+
);
|
|
7791
|
+
}
|
|
7792
|
+
const limit = readNumber(args, "limit");
|
|
7055
7793
|
const response = await context.client.privateGet(
|
|
7056
|
-
|
|
7794
|
+
PATH_TRADE_RECORDS,
|
|
7057
7795
|
compactObject({
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
authorIds: readString(args, "authorIds"),
|
|
7796
|
+
authorId,
|
|
7797
|
+
instCcy: extractBaseCcy(readString(args, "instId")),
|
|
7061
7798
|
after: readString(args, "after"),
|
|
7062
7799
|
before: readString(args, "before"),
|
|
7063
|
-
limit
|
|
7800
|
+
limit
|
|
7064
7801
|
}),
|
|
7065
|
-
publicRateLimit("
|
|
7802
|
+
publicRateLimit("smartmoney_get_trader_orders_history", SMARTMONEY_RPS)
|
|
7066
7803
|
);
|
|
7067
7804
|
const normalized = normalizeResponse(response);
|
|
7068
|
-
|
|
7805
|
+
const data = Array.isArray(normalized.data) ? normalized.data : [];
|
|
7806
|
+
return {
|
|
7807
|
+
...normalized,
|
|
7808
|
+
data,
|
|
7809
|
+
pagination: buildPagination(data, limit ?? 10, "ordId")
|
|
7810
|
+
};
|
|
7069
7811
|
}
|
|
7070
7812
|
},
|
|
7071
|
-
/* ----------
|
|
7813
|
+
/* ---------- T6. Search top traders by nickname keyword ---------- */
|
|
7072
7814
|
{
|
|
7073
|
-
name: "
|
|
7815
|
+
name: "smartmoney_search_trader",
|
|
7074
7816
|
module: "smartmoney",
|
|
7075
|
-
description: "Trader
|
|
7817
|
+
description: "Search Top Traders by nickname keyword, ranked by OKX-platform follower count DESC. Returns up to 10 matches; intersects KOL full-text recall with the Top Trader set. Use when: resolving a nickname or partial name to `authorId`(s) before calling other `smartmoney_get_trader_*` tools. See also: `smartmoney_get_traders_by_filter` (discover top performers by criteria), `smartmoney_get_performance_by_trader` (lookup by known authorId).",
|
|
7076
7818
|
isWrite: false,
|
|
7819
|
+
outputSchema: envelope({
|
|
7820
|
+
type: "array",
|
|
7821
|
+
description: "Matched Top Traders (\u226410), sorted by `followerCount` DESC. Empty array when no recall intersects the Top Trader set.",
|
|
7822
|
+
items: {
|
|
7823
|
+
type: "object",
|
|
7824
|
+
properties: {
|
|
7825
|
+
authorId: { type: "string", description: "Trader's unique ID \u2014 pass to other `smartmoney_get_trader_*` tools." },
|
|
7826
|
+
nickName: { type: "string", description: "Display nickname matched against the keyword." },
|
|
7827
|
+
followerCount: { type: "string", description: "OKX-platform follower count (numeric string; Twitter followers excluded). Sort key." }
|
|
7828
|
+
}
|
|
7829
|
+
}
|
|
7830
|
+
}),
|
|
7077
7831
|
inputSchema: {
|
|
7078
7832
|
type: "object",
|
|
7079
7833
|
properties: {
|
|
7080
|
-
|
|
7834
|
+
keyword: {
|
|
7835
|
+
type: "string",
|
|
7836
|
+
description: "Nickname search keyword. Required, must be non-empty / non-whitespace. Matched candidates are intersected with the Top Trader set."
|
|
7837
|
+
}
|
|
7838
|
+
},
|
|
7839
|
+
required: ["keyword"]
|
|
7840
|
+
},
|
|
7841
|
+
handler: async (rawArgs, context) => {
|
|
7842
|
+
const args = asRecord(rawArgs);
|
|
7843
|
+
const keyword = readString(args, "keyword");
|
|
7844
|
+
if (!keyword || keyword.trim() === "") {
|
|
7845
|
+
throw actionableError(
|
|
7846
|
+
'"keyword" is required and must be non-empty.',
|
|
7847
|
+
'Pass a nickname fragment (e.g. "alice", "\u5C0F\u660E"). For known author IDs use `smartmoney_get_performance_by_trader` instead.'
|
|
7848
|
+
);
|
|
7849
|
+
}
|
|
7850
|
+
const response = await context.client.privateGet(
|
|
7851
|
+
PATH_TOP_TRADER_SEARCH,
|
|
7852
|
+
compactObject({ keyword }),
|
|
7853
|
+
publicRateLimit("smartmoney_search_trader", SMARTMONEY_RPS)
|
|
7854
|
+
);
|
|
7855
|
+
const normalized = normalizeResponse(response);
|
|
7856
|
+
const data = Array.isArray(normalized.data) ? normalized.data : [];
|
|
7857
|
+
return { ...normalized, data };
|
|
7858
|
+
}
|
|
7859
|
+
},
|
|
7860
|
+
/* ===================================================== */
|
|
7861
|
+
/* Signal/Coin family (4) */
|
|
7862
|
+
/* ===================================================== */
|
|
7863
|
+
/* ---------- S1. Signal overview by filter (multi-asset, tier-filtered pool) ---------- */
|
|
7864
|
+
{
|
|
7865
|
+
name: "smartmoney_get_signal_overview_by_filter",
|
|
7866
|
+
module: "smartmoney",
|
|
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).",
|
|
7868
|
+
isWrite: false,
|
|
7869
|
+
outputSchema: envelope({
|
|
7870
|
+
type: "array",
|
|
7871
|
+
description: "Per-instrument snapshot, one element per requested coin.",
|
|
7872
|
+
items: { type: "object", properties: SIGNAL_ITEM_PROPS }
|
|
7873
|
+
}),
|
|
7874
|
+
inputSchema: {
|
|
7875
|
+
type: "object",
|
|
7876
|
+
properties: {
|
|
7877
|
+
topInstruments: {
|
|
7878
|
+
type: "integer",
|
|
7879
|
+
minimum: 1,
|
|
7880
|
+
maximum: 100,
|
|
7881
|
+
default: 20,
|
|
7882
|
+
description: "Top-N hottest instruments to aggregate (sorted by `tradersWithPosition` DESC). Mutually exclusive with `instCcyList`; one of the two is required (default 20 if neither provided)."
|
|
7883
|
+
},
|
|
7884
|
+
instCcyList: {
|
|
7885
|
+
type: "array",
|
|
7886
|
+
items: { type: "string" },
|
|
7887
|
+
minItems: 1,
|
|
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.'
|
|
7889
|
+
},
|
|
7890
|
+
...SIGNAL_POOL_FILTER_PROPS,
|
|
7891
|
+
lmtNum: {
|
|
7892
|
+
type: "integer",
|
|
7893
|
+
minimum: 1,
|
|
7894
|
+
maximum: 2e3,
|
|
7895
|
+
default: 100,
|
|
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."
|
|
7897
|
+
}
|
|
7898
|
+
},
|
|
7899
|
+
required: ["sortBy", "period"]
|
|
7900
|
+
},
|
|
7901
|
+
handler: async (rawArgs, context) => {
|
|
7902
|
+
const args = asRecord(rawArgs);
|
|
7903
|
+
const instCcyList = readArrayAsCsv(args, "instCcyList");
|
|
7904
|
+
const topInstrumentsRaw = readNumber(args, "topInstruments");
|
|
7905
|
+
if (instCcyList && topInstrumentsRaw !== void 0) {
|
|
7906
|
+
throw actionableError(
|
|
7907
|
+
'"topInstruments" and "instCcyList" are mutually exclusive.',
|
|
7908
|
+
"Pass exactly one \u2014 `topInstruments` for top-N hottest coins, or `instCcyList` for specific coins."
|
|
7909
|
+
);
|
|
7910
|
+
}
|
|
7911
|
+
const response = await context.client.privateGet(
|
|
7912
|
+
PATH_OVERVIEW,
|
|
7913
|
+
compactObject({
|
|
7914
|
+
...instCcyList ? { instCcyList } : { topInstruments: topInstrumentsRaw ?? 20 },
|
|
7915
|
+
...readSignalPoolFilters(args),
|
|
7916
|
+
lmtNum: readNumber(args, "lmtNum")
|
|
7917
|
+
}),
|
|
7918
|
+
publicRateLimit("smartmoney_get_signal_overview_by_filter", SMARTMONEY_RPS)
|
|
7919
|
+
);
|
|
7920
|
+
return normalizeResponse(response);
|
|
7921
|
+
}
|
|
7922
|
+
},
|
|
7923
|
+
/* ---------- S2. Signal overview by trader (multi-asset, authorIds-restricted) ---------- */
|
|
7924
|
+
{
|
|
7925
|
+
name: "smartmoney_get_signal_overview_by_trader",
|
|
7926
|
+
module: "smartmoney",
|
|
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).",
|
|
7928
|
+
isWrite: false,
|
|
7929
|
+
outputSchema: envelope({
|
|
7930
|
+
type: "array",
|
|
7931
|
+
description: "Per-instrument snapshot, one element per requested coin.",
|
|
7932
|
+
items: { type: "object", properties: SIGNAL_ITEM_PROPS }
|
|
7933
|
+
}),
|
|
7934
|
+
inputSchema: {
|
|
7935
|
+
type: "object",
|
|
7936
|
+
properties: {
|
|
7937
|
+
authorIds: {
|
|
7938
|
+
type: "array",
|
|
7939
|
+
items: { type: "string" },
|
|
7940
|
+
minItems: 1,
|
|
7941
|
+
description: 'Trader IDs to aggregate over, e.g. `["1001", "1002"]`. Required.'
|
|
7942
|
+
},
|
|
7943
|
+
topInstruments: {
|
|
7944
|
+
type: "integer",
|
|
7945
|
+
minimum: 1,
|
|
7946
|
+
maximum: 100,
|
|
7947
|
+
default: 20,
|
|
7948
|
+
description: "Top-N hottest instruments held by the given traders (sorted by `tradersWithPosition` DESC). Mutually exclusive with `instCcyList`; one of the two is required (default 20 if neither provided)."
|
|
7949
|
+
},
|
|
7950
|
+
instCcyList: {
|
|
7951
|
+
type: "array",
|
|
7952
|
+
items: { type: "string" },
|
|
7953
|
+
minItems: 1,
|
|
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: {
|
|
7081
7957
|
type: "string",
|
|
7082
|
-
|
|
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"`.'
|
|
7083
7961
|
},
|
|
7084
7962
|
period: {
|
|
7085
7963
|
type: "string",
|
|
7086
|
-
|
|
7087
|
-
|
|
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.'
|
|
7967
|
+
}
|
|
7968
|
+
},
|
|
7969
|
+
required: ["authorIds", "sortBy", "period"]
|
|
7970
|
+
},
|
|
7971
|
+
handler: async (rawArgs, context) => {
|
|
7972
|
+
const args = asRecord(rawArgs);
|
|
7973
|
+
assertEnum2(args, "sortBy", ["pnl", "pnlRatio"]);
|
|
7974
|
+
assertEnum2(args, "period", PERIOD_DAYS);
|
|
7975
|
+
const authorIds = readArrayAsCsv(args, "authorIds");
|
|
7976
|
+
if (!authorIds) {
|
|
7977
|
+
throw actionableError(
|
|
7978
|
+
'"authorIds" is required and must be a non-empty array.',
|
|
7979
|
+
'Pass IDs from `smartmoney_get_traders_by_filter` as an array (e.g. ["1001", "1002"]).'
|
|
7980
|
+
);
|
|
7981
|
+
}
|
|
7982
|
+
const instCcyList = readArrayAsCsv(args, "instCcyList");
|
|
7983
|
+
const topInstrumentsRaw = readNumber(args, "topInstruments");
|
|
7984
|
+
if (instCcyList && topInstrumentsRaw !== void 0) {
|
|
7985
|
+
throw actionableError(
|
|
7986
|
+
'"topInstruments" and "instCcyList" are mutually exclusive.',
|
|
7987
|
+
"Pass exactly one \u2014 `topInstruments` for top-N hottest coins, or `instCcyList` for specific coins."
|
|
7988
|
+
);
|
|
7989
|
+
}
|
|
7990
|
+
const response = await context.client.privateGet(
|
|
7991
|
+
PATH_OVERVIEW,
|
|
7992
|
+
compactObject({
|
|
7993
|
+
authorIds,
|
|
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"
|
|
7999
|
+
}),
|
|
8000
|
+
publicRateLimit("smartmoney_get_signal_overview_by_trader", SMARTMONEY_RPS)
|
|
8001
|
+
);
|
|
8002
|
+
return normalizeResponse(response);
|
|
8003
|
+
}
|
|
8004
|
+
},
|
|
8005
|
+
/* ---------- S3. Signal trend by filter (single-asset, tier-filtered pool, asOfTime anchor) ---------- */
|
|
8006
|
+
{
|
|
8007
|
+
name: "smartmoney_get_signal_trend_by_filter",
|
|
8008
|
+
module: "smartmoney",
|
|
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.",
|
|
8010
|
+
isWrite: false,
|
|
8011
|
+
outputSchema: envelope({
|
|
8012
|
+
type: "array",
|
|
8013
|
+
description: "Time-bucket series for the requested instrument, sorted by time DESC (newest first).",
|
|
8014
|
+
items: { type: "object", properties: SIGNAL_HISTORY_ITEM_PROPS }
|
|
8015
|
+
}),
|
|
8016
|
+
inputSchema: {
|
|
8017
|
+
type: "object",
|
|
8018
|
+
properties: {
|
|
7088
8019
|
instCcy: {
|
|
7089
8020
|
type: "string",
|
|
7090
|
-
description:
|
|
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.'
|
|
7091
8022
|
},
|
|
7092
|
-
|
|
8023
|
+
asOfTime: {
|
|
7093
8024
|
type: "string",
|
|
7094
|
-
description:
|
|
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.'
|
|
8026
|
+
},
|
|
8027
|
+
granularity: {
|
|
8028
|
+
type: "string",
|
|
8029
|
+
enum: ["1h", "1d"],
|
|
8030
|
+
default: "1h",
|
|
8031
|
+
description: "Time-bucket size. `1h` = hourly snapshots (intraday/short-term trend), `1d` = daily snapshots (multi-day trend)."
|
|
8032
|
+
},
|
|
8033
|
+
limit: {
|
|
8034
|
+
type: "integer",
|
|
8035
|
+
minimum: 1,
|
|
8036
|
+
maximum: 500,
|
|
8037
|
+
default: 24,
|
|
8038
|
+
description: "Number of buckets to return (newest first), ending at `asOfTime`. Default 24, max 500."
|
|
8039
|
+
},
|
|
8040
|
+
...SIGNAL_POOL_FILTER_PROPS,
|
|
8041
|
+
lmtNum: {
|
|
8042
|
+
type: "integer",
|
|
8043
|
+
minimum: 1,
|
|
8044
|
+
maximum: 2e3,
|
|
8045
|
+
default: 100,
|
|
8046
|
+
description: "Top-N traders to pull into the aggregation pool, ranked by `sortBy` (DESC). Default 100, max 2000."
|
|
7095
8047
|
}
|
|
7096
8048
|
},
|
|
7097
|
-
required: ["
|
|
8049
|
+
required: ["instCcy", "granularity", "sortBy", "period"]
|
|
7098
8050
|
},
|
|
7099
8051
|
handler: async (rawArgs, context) => {
|
|
7100
8052
|
const args = asRecord(rawArgs);
|
|
7101
|
-
|
|
7102
|
-
const period = readString(args, "period");
|
|
8053
|
+
assertEnum2(args, "granularity", ["1h", "1d"]);
|
|
7103
8054
|
const instCcy = readString(args, "instCcy");
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
)
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
8055
|
+
if (!instCcy) {
|
|
8056
|
+
throw actionableError(
|
|
8057
|
+
'"instCcy" is required.',
|
|
8058
|
+
'Pass a base currency, e.g. "BTC".'
|
|
8059
|
+
);
|
|
8060
|
+
}
|
|
8061
|
+
const response = await context.client.privateGet(
|
|
8062
|
+
PATH_SIGNAL_HISTORY,
|
|
8063
|
+
compactObject({
|
|
8064
|
+
instCcy,
|
|
8065
|
+
asOfTime: readString(args, "asOfTime"),
|
|
8066
|
+
// Apply schema default explicitly (CLI bypasses MCP `required` validation).
|
|
8067
|
+
granularity: readString(args, "granularity") ?? "1h",
|
|
8068
|
+
limit: readNumber(args, "limit"),
|
|
8069
|
+
...readSignalPoolFilters(args),
|
|
8070
|
+
lmtNum: readNumber(args, "lmtNum")
|
|
8071
|
+
}),
|
|
8072
|
+
publicRateLimit("smartmoney_get_signal_trend_by_filter", SMARTMONEY_RPS)
|
|
8073
|
+
);
|
|
8074
|
+
return normalizeResponse(response);
|
|
8075
|
+
}
|
|
8076
|
+
},
|
|
8077
|
+
/* ---------- S4. Signal trend by trader (single-asset, authorIds-restricted) ---------- */
|
|
8078
|
+
{
|
|
8079
|
+
name: "smartmoney_get_signal_trend_by_trader",
|
|
8080
|
+
module: "smartmoney",
|
|
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.",
|
|
8082
|
+
isWrite: false,
|
|
8083
|
+
outputSchema: envelope({
|
|
8084
|
+
type: "array",
|
|
8085
|
+
description: "Time-bucket series for the requested instrument, sorted by time DESC (newest first).",
|
|
8086
|
+
items: { type: "object", properties: SIGNAL_HISTORY_ITEM_PROPS }
|
|
8087
|
+
}),
|
|
8088
|
+
inputSchema: {
|
|
8089
|
+
type: "object",
|
|
8090
|
+
properties: {
|
|
8091
|
+
authorIds: {
|
|
8092
|
+
type: "array",
|
|
8093
|
+
items: { type: "string" },
|
|
8094
|
+
minItems: 1,
|
|
8095
|
+
description: 'Trader IDs to aggregate over, e.g. `["1001", "1002"]`. Required.'
|
|
8096
|
+
},
|
|
8097
|
+
instCcy: {
|
|
8098
|
+
type: "string",
|
|
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.'
|
|
8100
|
+
},
|
|
8101
|
+
asOfTime: {
|
|
8102
|
+
type: "string",
|
|
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.'
|
|
8104
|
+
},
|
|
8105
|
+
granularity: {
|
|
8106
|
+
type: "string",
|
|
8107
|
+
enum: ["1h", "1d"],
|
|
8108
|
+
default: "1h",
|
|
8109
|
+
description: "Time-bucket size. `1h` = hourly snapshots (intraday/short-term trend), `1d` = daily snapshots (multi-day trend)."
|
|
8110
|
+
},
|
|
8111
|
+
limit: {
|
|
8112
|
+
type: "integer",
|
|
8113
|
+
minimum: 1,
|
|
8114
|
+
maximum: 500,
|
|
8115
|
+
default: 24,
|
|
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).'
|
|
7132
8129
|
}
|
|
7133
|
-
}
|
|
8130
|
+
},
|
|
8131
|
+
required: ["authorIds", "instCcy", "granularity", "sortBy", "period"]
|
|
8132
|
+
},
|
|
8133
|
+
handler: async (rawArgs, context) => {
|
|
8134
|
+
const args = asRecord(rawArgs);
|
|
8135
|
+
assertEnum2(args, "granularity", ["1h", "1d"]);
|
|
8136
|
+
assertEnum2(args, "sortBy", ["pnl", "pnlRatio"]);
|
|
8137
|
+
assertEnum2(args, "period", PERIOD_DAYS);
|
|
8138
|
+
const authorIds = readArrayAsCsv(args, "authorIds");
|
|
8139
|
+
const instCcy = readString(args, "instCcy");
|
|
8140
|
+
if (!authorIds) {
|
|
8141
|
+
throw actionableError(
|
|
8142
|
+
'"authorIds" is required and must be a non-empty array.',
|
|
8143
|
+
'Pass IDs from `smartmoney_get_traders_by_filter` as an array (e.g. ["1001", "1002"]).'
|
|
8144
|
+
);
|
|
8145
|
+
}
|
|
8146
|
+
if (!instCcy) {
|
|
8147
|
+
throw actionableError(
|
|
8148
|
+
'"instCcy" is required.',
|
|
8149
|
+
'Pass a base currency, e.g. "BTC".'
|
|
8150
|
+
);
|
|
8151
|
+
}
|
|
8152
|
+
const response = await context.client.privateGet(
|
|
8153
|
+
PATH_SIGNAL_HISTORY,
|
|
8154
|
+
compactObject({
|
|
8155
|
+
authorIds,
|
|
8156
|
+
instCcy,
|
|
8157
|
+
asOfTime: readString(args, "asOfTime"),
|
|
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"
|
|
8164
|
+
}),
|
|
8165
|
+
publicRateLimit("smartmoney_get_signal_trend_by_trader", SMARTMONEY_RPS)
|
|
8166
|
+
);
|
|
8167
|
+
return normalizeResponse(response);
|
|
7134
8168
|
}
|
|
7135
8169
|
}
|
|
7136
8170
|
];
|
|
@@ -7189,8 +8223,12 @@ function buildContractTradeTools(cfg) {
|
|
|
7189
8223
|
clOrdId: { type: "string", description: "Client order ID (max 32 chars)" },
|
|
7190
8224
|
tpTriggerPx: { type: "string", description: "TP trigger price" },
|
|
7191
8225
|
tpOrdPx: { type: "string", description: "TP order price; -1=market" },
|
|
8226
|
+
tpOrdKind: TP_ORD_KIND_SCHEMA,
|
|
8227
|
+
tpTriggerPxType: TP_TRIGGER_PX_TYPE_SCHEMA,
|
|
7192
8228
|
slTriggerPx: { type: "string", description: "SL trigger price" },
|
|
7193
|
-
slOrdPx: { type: "string", description: "SL order price; -1=market" }
|
|
8229
|
+
slOrdPx: { type: "string", description: "SL order price; -1=market" },
|
|
8230
|
+
slTriggerPxType: SL_TRIGGER_PX_TYPE_SCHEMA,
|
|
8231
|
+
stpMode: STP_MODE_SCHEMA
|
|
7194
8232
|
},
|
|
7195
8233
|
required: ["instId", "tdMode", "side", "ordType", "sz"]
|
|
7196
8234
|
},
|
|
@@ -7219,6 +8257,9 @@ function buildContractTradeTools(cfg) {
|
|
|
7219
8257
|
px: readString(args, "px"),
|
|
7220
8258
|
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
7221
8259
|
clOrdId: readString(args, "clOrdId"),
|
|
8260
|
+
stpMode: readString(args, "stpMode"),
|
|
8261
|
+
// Phase 3c CLI power-user flag (issue #182, CLI-only no MCP/skill exposure)
|
|
8262
|
+
pxAmendType: readString(args, "pxAmendType"),
|
|
7222
8263
|
tag: context.config.sourceTag,
|
|
7223
8264
|
attachAlgoOrds
|
|
7224
8265
|
}),
|
|
@@ -9218,6 +10259,8 @@ function registerOptionTools() {
|
|
|
9218
10259
|
type: "string",
|
|
9219
10260
|
description: "TP order price; -1=market"
|
|
9220
10261
|
},
|
|
10262
|
+
tpOrdKind: TP_ORD_KIND_SCHEMA,
|
|
10263
|
+
tpTriggerPxType: TP_TRIGGER_PX_TYPE_SCHEMA,
|
|
9221
10264
|
slTriggerPx: {
|
|
9222
10265
|
type: "string",
|
|
9223
10266
|
description: "SL trigger price"
|
|
@@ -9225,7 +10268,9 @@ function registerOptionTools() {
|
|
|
9225
10268
|
slOrdPx: {
|
|
9226
10269
|
type: "string",
|
|
9227
10270
|
description: "SL order price; -1=market"
|
|
9228
|
-
}
|
|
10271
|
+
},
|
|
10272
|
+
slTriggerPxType: SL_TRIGGER_PX_TYPE_SCHEMA,
|
|
10273
|
+
stpMode: STP_MODE_SCHEMA
|
|
9229
10274
|
},
|
|
9230
10275
|
required: ["instId", "tdMode", "side", "ordType", "sz"]
|
|
9231
10276
|
},
|
|
@@ -9253,6 +10298,7 @@ function registerOptionTools() {
|
|
|
9253
10298
|
px: readString(args, "px"),
|
|
9254
10299
|
reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
|
|
9255
10300
|
clOrdId: readString(args, "clOrdId"),
|
|
10301
|
+
stpMode: readString(args, "stpMode"),
|
|
9256
10302
|
tag: context.config.sourceTag,
|
|
9257
10303
|
attachAlgoOrds
|
|
9258
10304
|
}),
|
|
@@ -9621,6 +10667,8 @@ function registerSpotTradeTools() {
|
|
|
9621
10667
|
type: "string",
|
|
9622
10668
|
description: "TP order price, -1=market"
|
|
9623
10669
|
},
|
|
10670
|
+
tpOrdKind: TP_ORD_KIND_SCHEMA,
|
|
10671
|
+
tpTriggerPxType: TP_TRIGGER_PX_TYPE_SCHEMA,
|
|
9624
10672
|
slTriggerPx: {
|
|
9625
10673
|
type: "string",
|
|
9626
10674
|
description: "SL trigger price"
|
|
@@ -9628,13 +10676,16 @@ function registerSpotTradeTools() {
|
|
|
9628
10676
|
slOrdPx: {
|
|
9629
10677
|
type: "string",
|
|
9630
10678
|
description: "SL order price, -1=market"
|
|
9631
|
-
}
|
|
10679
|
+
},
|
|
10680
|
+
slTriggerPxType: SL_TRIGGER_PX_TYPE_SCHEMA,
|
|
10681
|
+
stpMode: STP_MODE_SCHEMA
|
|
9632
10682
|
},
|
|
9633
10683
|
required: ["instId", "tdMode", "side", "ordType", "sz"]
|
|
9634
10684
|
},
|
|
9635
10685
|
handler: async (rawArgs, context) => {
|
|
9636
10686
|
const args = asRecord(rawArgs);
|
|
9637
10687
|
const attachAlgoOrds = buildAttachAlgoOrds(args);
|
|
10688
|
+
const banAmend = args.banAmend;
|
|
9638
10689
|
const response = await context.client.privatePost(
|
|
9639
10690
|
"/api/v5/trade/order",
|
|
9640
10691
|
compactObject({
|
|
@@ -9646,6 +10697,11 @@ function registerSpotTradeTools() {
|
|
|
9646
10697
|
tgtCcy: readString(args, "tgtCcy"),
|
|
9647
10698
|
px: readString(args, "px"),
|
|
9648
10699
|
clOrdId: readString(args, "clOrdId"),
|
|
10700
|
+
stpMode: readString(args, "stpMode"),
|
|
10701
|
+
// Phase 3c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
10702
|
+
tradeQuoteCcy: readString(args, "tradeQuoteCcy"),
|
|
10703
|
+
banAmend: typeof banAmend === "boolean" ? String(banAmend) : void 0,
|
|
10704
|
+
pxAmendType: readString(args, "pxAmendType"),
|
|
9649
10705
|
tag: context.config.sourceTag,
|
|
9650
10706
|
attachAlgoOrds
|
|
9651
10707
|
}),
|
|
@@ -9810,7 +10866,7 @@ function registerSpotTradeTools() {
|
|
|
9810
10866
|
{
|
|
9811
10867
|
name: "spot_place_algo_order",
|
|
9812
10868
|
module: "spot",
|
|
9813
|
-
description: "Place a spot algo order: TP/SL
|
|
10869
|
+
description: "Place a spot algo order. [CAUTION] Executes real trades. conditional: single TP/SL. oco: TP+SL pair. move_order_stop: trailing stop. trigger: pending order at triggerPx. chase: follow best bid/ask. iceberg: split large order into child orders. twap: time-weighted split.",
|
|
9814
10870
|
isWrite: true,
|
|
9815
10871
|
inputSchema: {
|
|
9816
10872
|
type: "object",
|
|
@@ -9830,8 +10886,8 @@ function registerSpotTradeTools() {
|
|
|
9830
10886
|
},
|
|
9831
10887
|
ordType: {
|
|
9832
10888
|
type: "string",
|
|
9833
|
-
enum: ["conditional", "oco", "move_order_stop"],
|
|
9834
|
-
description: "conditional=single TP/SL, oco=TP+SL pair, move_order_stop=trailing stop"
|
|
10889
|
+
enum: ["conditional", "oco", "move_order_stop", "trigger", "chase", "iceberg", "twap"],
|
|
10890
|
+
description: "conditional=single TP/SL, oco=TP+SL pair, move_order_stop=trailing stop, trigger=pending order, chase=follow best bid/ask, iceberg=split order, twap=time-weighted split"
|
|
9835
10891
|
},
|
|
9836
10892
|
sz: {
|
|
9837
10893
|
type: "string",
|
|
@@ -9845,6 +10901,8 @@ function registerSpotTradeTools() {
|
|
|
9845
10901
|
type: "string",
|
|
9846
10902
|
description: "TP order price, -1=market (conditional/oco only)"
|
|
9847
10903
|
},
|
|
10904
|
+
tpOrdKind: TP_ORD_KIND_SCHEMA,
|
|
10905
|
+
tpTriggerPxType: TP_TRIGGER_PX_TYPE_SCHEMA,
|
|
9848
10906
|
slTriggerPx: {
|
|
9849
10907
|
type: "string",
|
|
9850
10908
|
description: "SL trigger price (conditional/oco only)"
|
|
@@ -9853,6 +10911,8 @@ function registerSpotTradeTools() {
|
|
|
9853
10911
|
type: "string",
|
|
9854
10912
|
description: "SL order price, -1=market (conditional/oco only)"
|
|
9855
10913
|
},
|
|
10914
|
+
slTriggerPxType: SL_TRIGGER_PX_TYPE_SCHEMA,
|
|
10915
|
+
stpMode: STP_MODE_SCHEMA,
|
|
9856
10916
|
tgtCcy: {
|
|
9857
10917
|
type: "string",
|
|
9858
10918
|
enum: ["base_ccy", "quote_ccy"],
|
|
@@ -9869,30 +10929,50 @@ function registerSpotTradeTools() {
|
|
|
9869
10929
|
activePx: {
|
|
9870
10930
|
type: "string",
|
|
9871
10931
|
description: "Activation price, trailing starts when market hits this (move_order_stop only)"
|
|
9872
|
-
}
|
|
10932
|
+
},
|
|
10933
|
+
...TRIGGER_FLAGS_SCHEMA,
|
|
10934
|
+
...CHASE_FLAGS_SCHEMA,
|
|
10935
|
+
...ICEBERG_TWAP_FLAGS_SCHEMA
|
|
9873
10936
|
},
|
|
9874
10937
|
required: ["instId", "side", "ordType", "sz"]
|
|
9875
10938
|
},
|
|
9876
10939
|
handler: async (rawArgs, context) => {
|
|
9877
10940
|
const args = asRecord(rawArgs);
|
|
10941
|
+
const ordType = requireString(args, "ordType");
|
|
10942
|
+
const base = compactObject({
|
|
10943
|
+
instId: requireString(args, "instId"),
|
|
10944
|
+
tdMode: readString(args, "tdMode") ?? "cash",
|
|
10945
|
+
side: requireString(args, "side"),
|
|
10946
|
+
ordType,
|
|
10947
|
+
sz: requireString(args, "sz"),
|
|
10948
|
+
tgtCcy: readString(args, "tgtCcy"),
|
|
10949
|
+
stpMode: readString(args, "stpMode"),
|
|
10950
|
+
// Phase 3a+c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
10951
|
+
pxAmendType: readString(args, "pxAmendType"),
|
|
10952
|
+
tag: context.config.sourceTag
|
|
10953
|
+
});
|
|
10954
|
+
switch (ordType) {
|
|
10955
|
+
case "trigger":
|
|
10956
|
+
Object.assign(base, buildTriggerOrdTypeBody(args));
|
|
10957
|
+
break;
|
|
10958
|
+
case "chase":
|
|
10959
|
+
Object.assign(base, buildChaseOrdTypeBody(args));
|
|
10960
|
+
break;
|
|
10961
|
+
case "iceberg":
|
|
10962
|
+
case "twap":
|
|
10963
|
+
Object.assign(base, buildIcebergTwapOrdTypeBody(args));
|
|
10964
|
+
break;
|
|
10965
|
+
default:
|
|
10966
|
+
Object.assign(base, compactObject({
|
|
10967
|
+
...buildAlgoConditionalCommonFields(args),
|
|
10968
|
+
callbackRatio: readString(args, "callbackRatio"),
|
|
10969
|
+
callbackSpread: readString(args, "callbackSpread")
|
|
10970
|
+
}));
|
|
10971
|
+
break;
|
|
10972
|
+
}
|
|
9878
10973
|
const response = await context.client.privatePost(
|
|
9879
10974
|
"/api/v5/trade/order-algo",
|
|
9880
|
-
|
|
9881
|
-
instId: requireString(args, "instId"),
|
|
9882
|
-
tdMode: readString(args, "tdMode") ?? "cash",
|
|
9883
|
-
side: requireString(args, "side"),
|
|
9884
|
-
ordType: requireString(args, "ordType"),
|
|
9885
|
-
sz: requireString(args, "sz"),
|
|
9886
|
-
tgtCcy: readString(args, "tgtCcy"),
|
|
9887
|
-
tpTriggerPx: readString(args, "tpTriggerPx"),
|
|
9888
|
-
tpOrdPx: readString(args, "tpOrdPx"),
|
|
9889
|
-
slTriggerPx: readString(args, "slTriggerPx"),
|
|
9890
|
-
slOrdPx: readString(args, "slOrdPx"),
|
|
9891
|
-
callbackRatio: readString(args, "callbackRatio"),
|
|
9892
|
-
callbackSpread: readString(args, "callbackSpread"),
|
|
9893
|
-
activePx: readString(args, "activePx"),
|
|
9894
|
-
tag: context.config.sourceTag
|
|
9895
|
-
}),
|
|
10975
|
+
base,
|
|
9896
10976
|
privateRateLimit("spot_place_algo_order", 20)
|
|
9897
10977
|
);
|
|
9898
10978
|
return normalizeResponse(response);
|
|
@@ -10931,6 +12011,78 @@ function runSetup(options) {
|
|
|
10931
12011
|
`);
|
|
10932
12012
|
}
|
|
10933
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
|
+
}
|
|
10934
12086
|
var CDN_SOURCES = [
|
|
10935
12087
|
{ host: "static.jingyunyilian.com", protocol: "https" },
|
|
10936
12088
|
{ host: "static.okx.com", protocol: "https" },
|
|
@@ -10941,7 +12093,7 @@ var DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
|
10941
12093
|
var PLATFORM_MAP = {
|
|
10942
12094
|
"darwin-arm64": "darwin-arm64",
|
|
10943
12095
|
"darwin-x64": "darwin-x64",
|
|
10944
|
-
"linux-arm64": "linux-
|
|
12096
|
+
"linux-arm64": "linux-arm64",
|
|
10945
12097
|
"linux-x64": "linux-x64",
|
|
10946
12098
|
"win32-arm64": "win32-arm64",
|
|
10947
12099
|
"win32-x64": "win32-x64"
|
|
@@ -11044,7 +12196,7 @@ async function downloadAndVerify(host, protocol, binaryPath, tmpPath, checksum,
|
|
|
11044
12196
|
function atomicReplace(tmpPath, resolvedDest) {
|
|
11045
12197
|
if (platform() === "win32") {
|
|
11046
12198
|
try {
|
|
11047
|
-
|
|
12199
|
+
unlinkSync4(resolvedDest);
|
|
11048
12200
|
} catch {
|
|
11049
12201
|
}
|
|
11050
12202
|
}
|
|
@@ -11100,7 +12252,7 @@ async function installPilotBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
|
11100
12252
|
return { status: "installed", source: host };
|
|
11101
12253
|
} catch (err) {
|
|
11102
12254
|
try {
|
|
11103
|
-
|
|
12255
|
+
unlinkSync4(tmpPath);
|
|
11104
12256
|
} catch {
|
|
11105
12257
|
}
|
|
11106
12258
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -11114,7 +12266,7 @@ ${errors.join("\n")}` };
|
|
|
11114
12266
|
function removePilotBinary(binaryPath) {
|
|
11115
12267
|
const resolvedPath = binaryPath ?? getPilotBinaryPath();
|
|
11116
12268
|
try {
|
|
11117
|
-
|
|
12269
|
+
unlinkSync4(resolvedPath);
|
|
11118
12270
|
return { status: "removed" };
|
|
11119
12271
|
} catch (err) {
|
|
11120
12272
|
if (err.code === "ENOENT") {
|
|
@@ -11124,78 +12276,6 @@ function removePilotBinary(binaryPath) {
|
|
|
11124
12276
|
throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
|
|
11125
12277
|
}
|
|
11126
12278
|
}
|
|
11127
|
-
function isRedirect(statusCode) {
|
|
11128
|
-
return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
|
|
11129
|
-
}
|
|
11130
|
-
function validateRedirect(res, requestUrl, redirectCount, maxRedirects) {
|
|
11131
|
-
if (redirectCount > maxRedirects) {
|
|
11132
|
-
throw new Error(`Too many redirects (${maxRedirects})`);
|
|
11133
|
-
}
|
|
11134
|
-
const location = res.headers.location;
|
|
11135
|
-
if (requestUrl.startsWith("https") && !location.startsWith("https")) {
|
|
11136
|
-
throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
|
|
11137
|
-
}
|
|
11138
|
-
return location;
|
|
11139
|
-
}
|
|
11140
|
-
function fetchResponse(url, timeoutMs) {
|
|
11141
|
-
return new Promise((resolve3, reject) => {
|
|
11142
|
-
let redirects = 0;
|
|
11143
|
-
const maxRedirects = 5;
|
|
11144
|
-
function doRequest(requestUrl) {
|
|
11145
|
-
const reqFn = requestUrl.startsWith("https") ? httpsGet : httpGet;
|
|
11146
|
-
const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
|
|
11147
|
-
if (isRedirect(res.statusCode) && res.headers.location) {
|
|
11148
|
-
redirects++;
|
|
11149
|
-
try {
|
|
11150
|
-
const location = validateRedirect(res, requestUrl, redirects, maxRedirects);
|
|
11151
|
-
res.resume();
|
|
11152
|
-
doRequest(location);
|
|
11153
|
-
} catch (err) {
|
|
11154
|
-
reject(err);
|
|
11155
|
-
}
|
|
11156
|
-
return;
|
|
11157
|
-
}
|
|
11158
|
-
if (res.statusCode !== 200) {
|
|
11159
|
-
reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
|
|
11160
|
-
return;
|
|
11161
|
-
}
|
|
11162
|
-
resolve3(res);
|
|
11163
|
-
});
|
|
11164
|
-
req.on("error", reject);
|
|
11165
|
-
req.on("timeout", () => {
|
|
11166
|
-
req.destroy();
|
|
11167
|
-
reject(new Error("Download timed out"));
|
|
11168
|
-
});
|
|
11169
|
-
}
|
|
11170
|
-
doRequest(url);
|
|
11171
|
-
});
|
|
11172
|
-
}
|
|
11173
|
-
function download(url, destPath, timeoutMs) {
|
|
11174
|
-
return fetchResponse(url, timeoutMs).then(
|
|
11175
|
-
(res) => new Promise((resolve3, reject) => {
|
|
11176
|
-
const file = createWriteStream2(destPath);
|
|
11177
|
-
res.pipe(file);
|
|
11178
|
-
file.on("finish", () => file.close(() => resolve3()));
|
|
11179
|
-
file.on("error", (err) => {
|
|
11180
|
-
try {
|
|
11181
|
-
unlinkSync3(destPath);
|
|
11182
|
-
} catch {
|
|
11183
|
-
}
|
|
11184
|
-
reject(err);
|
|
11185
|
-
});
|
|
11186
|
-
})
|
|
11187
|
-
);
|
|
11188
|
-
}
|
|
11189
|
-
function downloadText(url, timeoutMs) {
|
|
11190
|
-
return fetchResponse(url, timeoutMs).then(
|
|
11191
|
-
(res) => new Promise((resolve3, reject) => {
|
|
11192
|
-
const chunks = [];
|
|
11193
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
11194
|
-
res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
|
|
11195
|
-
res.on("error", reject);
|
|
11196
|
-
})
|
|
11197
|
-
);
|
|
11198
|
-
}
|
|
11199
12279
|
var AUTH_CDN_PATH_PREFIX = "/upgradeapp/tools/oauth";
|
|
11200
12280
|
function getAuthBinaryName() {
|
|
11201
12281
|
return platform2() === "win32" ? "okx-auth.exe" : "okx-auth";
|
|
@@ -11219,7 +12299,7 @@ async function fetchAuthCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_
|
|
|
11219
12299
|
for (const { host, protocol } of sources) {
|
|
11220
12300
|
try {
|
|
11221
12301
|
const url = `${protocol}://${host}${checksumPath}`;
|
|
11222
|
-
const raw = await
|
|
12302
|
+
const raw = await downloadText(url, timeoutMs);
|
|
11223
12303
|
const data = JSON.parse(raw);
|
|
11224
12304
|
if (typeof data.sha256 !== "string" || typeof data.size !== "number" || typeof data.target !== "string") {
|
|
11225
12305
|
continue;
|
|
@@ -11233,7 +12313,7 @@ async function fetchAuthCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_
|
|
|
11233
12313
|
async function fetchAndValidateChecksum2(host, protocol, checksumPath, platformDir, timeoutMs, onProgress) {
|
|
11234
12314
|
const checksumUrl = `${protocol}://${host}${checksumPath}`;
|
|
11235
12315
|
onProgress?.(`Fetching checksum from ${host}...`);
|
|
11236
|
-
const raw = await
|
|
12316
|
+
const raw = await downloadText(checksumUrl, timeoutMs);
|
|
11237
12317
|
const checksum = JSON.parse(raw);
|
|
11238
12318
|
if (typeof checksum.sha256 !== "string" || typeof checksum.size !== "number" || typeof checksum.target !== "string") {
|
|
11239
12319
|
throw new Error("Invalid checksum.json: missing sha256, size, or target");
|
|
@@ -11246,7 +12326,7 @@ async function fetchAndValidateChecksum2(host, protocol, checksumPath, platformD
|
|
|
11246
12326
|
async function downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, timeoutMs, onProgress) {
|
|
11247
12327
|
const binaryUrl = `${protocol}://${host}${binaryPath}`;
|
|
11248
12328
|
onProgress?.(`Downloading binary from ${host}...`);
|
|
11249
|
-
await
|
|
12329
|
+
await download(binaryUrl, tmpPath, timeoutMs);
|
|
11250
12330
|
const actual = hashFile(tmpPath);
|
|
11251
12331
|
if (actual.size !== checksum.size) {
|
|
11252
12332
|
throw new Error(`Size mismatch: expected ${checksum.size}, got ${actual.size}`);
|
|
@@ -11258,7 +12338,7 @@ async function downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum,
|
|
|
11258
12338
|
function atomicReplace2(tmpPath, resolvedDest) {
|
|
11259
12339
|
if (platform2() === "win32") {
|
|
11260
12340
|
try {
|
|
11261
|
-
|
|
12341
|
+
unlinkSync5(resolvedDest);
|
|
11262
12342
|
} catch {
|
|
11263
12343
|
}
|
|
11264
12344
|
}
|
|
@@ -11314,7 +12394,7 @@ async function installAuthBinary(destPath, sources = CDN_SOURCES, onProgress) {
|
|
|
11314
12394
|
return { status: "installed", source: host };
|
|
11315
12395
|
} catch (err) {
|
|
11316
12396
|
try {
|
|
11317
|
-
|
|
12397
|
+
unlinkSync5(tmpPath);
|
|
11318
12398
|
} catch {
|
|
11319
12399
|
}
|
|
11320
12400
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -11328,7 +12408,7 @@ ${errors.join("\n")}` };
|
|
|
11328
12408
|
function removeAuthBinary(binaryPath) {
|
|
11329
12409
|
const resolvedPath = binaryPath ?? getAuthBinaryPath();
|
|
11330
12410
|
try {
|
|
11331
|
-
|
|
12411
|
+
unlinkSync5(resolvedPath);
|
|
11332
12412
|
return { status: "removed" };
|
|
11333
12413
|
} catch (err) {
|
|
11334
12414
|
if (err.code === "ENOENT") {
|
|
@@ -11338,78 +12418,6 @@ function removeAuthBinary(binaryPath) {
|
|
|
11338
12418
|
throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
|
|
11339
12419
|
}
|
|
11340
12420
|
}
|
|
11341
|
-
function isRedirect2(statusCode) {
|
|
11342
|
-
return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
|
|
11343
|
-
}
|
|
11344
|
-
function validateRedirect2(res, requestUrl, redirectCount, maxRedirects) {
|
|
11345
|
-
if (redirectCount > maxRedirects) {
|
|
11346
|
-
throw new Error(`Too many redirects (${maxRedirects})`);
|
|
11347
|
-
}
|
|
11348
|
-
const location = res.headers.location;
|
|
11349
|
-
if (requestUrl.startsWith("https") && !location.startsWith("https")) {
|
|
11350
|
-
throw new Error("Refused HTTPS \u2192 HTTP redirect downgrade");
|
|
11351
|
-
}
|
|
11352
|
-
return location;
|
|
11353
|
-
}
|
|
11354
|
-
function fetchResponse2(url, timeoutMs) {
|
|
11355
|
-
return new Promise((resolve3, reject) => {
|
|
11356
|
-
let redirects = 0;
|
|
11357
|
-
const maxRedirects = 5;
|
|
11358
|
-
function doRequest(requestUrl) {
|
|
11359
|
-
const reqFn = requestUrl.startsWith("https") ? httpsGet2 : httpGet2;
|
|
11360
|
-
const req = reqFn(requestUrl, { timeout: timeoutMs }, (res) => {
|
|
11361
|
-
if (isRedirect2(res.statusCode) && res.headers.location) {
|
|
11362
|
-
redirects++;
|
|
11363
|
-
try {
|
|
11364
|
-
const location = validateRedirect2(res, requestUrl, redirects, maxRedirects);
|
|
11365
|
-
res.resume();
|
|
11366
|
-
doRequest(location);
|
|
11367
|
-
} catch (err) {
|
|
11368
|
-
reject(err);
|
|
11369
|
-
}
|
|
11370
|
-
return;
|
|
11371
|
-
}
|
|
11372
|
-
if (res.statusCode !== 200) {
|
|
11373
|
-
reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
|
|
11374
|
-
return;
|
|
11375
|
-
}
|
|
11376
|
-
resolve3(res);
|
|
11377
|
-
});
|
|
11378
|
-
req.on("error", reject);
|
|
11379
|
-
req.on("timeout", () => {
|
|
11380
|
-
req.destroy();
|
|
11381
|
-
reject(new Error("Download timed out"));
|
|
11382
|
-
});
|
|
11383
|
-
}
|
|
11384
|
-
doRequest(url);
|
|
11385
|
-
});
|
|
11386
|
-
}
|
|
11387
|
-
function download2(url, destPath, timeoutMs) {
|
|
11388
|
-
return fetchResponse2(url, timeoutMs).then(
|
|
11389
|
-
(res) => new Promise((resolve3, reject) => {
|
|
11390
|
-
const file = createWriteStream3(destPath);
|
|
11391
|
-
res.pipe(file);
|
|
11392
|
-
file.on("finish", () => file.close(() => resolve3()));
|
|
11393
|
-
file.on("error", (err) => {
|
|
11394
|
-
try {
|
|
11395
|
-
unlinkSync4(destPath);
|
|
11396
|
-
} catch {
|
|
11397
|
-
}
|
|
11398
|
-
reject(err);
|
|
11399
|
-
});
|
|
11400
|
-
})
|
|
11401
|
-
);
|
|
11402
|
-
}
|
|
11403
|
-
function downloadText2(url, timeoutMs) {
|
|
11404
|
-
return fetchResponse2(url, timeoutMs).then(
|
|
11405
|
-
(res) => new Promise((resolve3, reject) => {
|
|
11406
|
-
const chunks = [];
|
|
11407
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
11408
|
-
res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
|
|
11409
|
-
res.on("error", reject);
|
|
11410
|
-
})
|
|
11411
|
-
);
|
|
11412
|
-
}
|
|
11413
12421
|
var CACHE_PATH = join12(homedir10(), ".okx", "auth-binary-check.json");
|
|
11414
12422
|
var CHECK_INTERVAL_MS2 = 2 * 60 * 60 * 1e3;
|
|
11415
12423
|
function readCache3() {
|
|
@@ -11458,7 +12466,7 @@ function updateAuthBinaryCache(sha256) {
|
|
|
11458
12466
|
}
|
|
11459
12467
|
function clearAuthBinaryCache() {
|
|
11460
12468
|
try {
|
|
11461
|
-
|
|
12469
|
+
unlinkSync6(CACHE_PATH);
|
|
11462
12470
|
} catch {
|
|
11463
12471
|
}
|
|
11464
12472
|
}
|
|
@@ -12374,7 +13382,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
12374
13382
|
|
|
12375
13383
|
// src/commands/diagnose.ts
|
|
12376
13384
|
var CLI_VERSION = readCliVersion();
|
|
12377
|
-
var GIT_HASH = true ? "
|
|
13385
|
+
var GIT_HASH = true ? "e8a0930a" : "dev";
|
|
12378
13386
|
function maskKey2(key) {
|
|
12379
13387
|
if (!key) return "(not set)";
|
|
12380
13388
|
if (key.length <= 8) return "****";
|
|
@@ -13066,7 +14074,7 @@ var CLI_REGISTRY = {
|
|
|
13066
14074
|
},
|
|
13067
14075
|
place: {
|
|
13068
14076
|
toolName: "spot_place_order",
|
|
13069
|
-
usage:
|
|
14077
|
+
usage: 'okx spot place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--px <price>] [--tdMode <cash|cross|isolated>]\n [--tgtCcy <base_ccy|quote_ccy>] [--clOrdId <id>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--tpOrdKind <condition|limit>] [--tpTriggerPxType <last|index|mark>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--slTriggerPxType <last|index|mark>]\n [--stpMode <cancel_maker|cancel_taker|cancel_both>]\n power-user (CLI-only): [--tradeQuoteCcy <USDT|USDC|BTC>] [--banAmend] [--pxAmendType <0|1>]\n power-user (CLI-only): [--tpLevel "px:78000,sz:0.5,kind:limit"] [--tpLevel "px:81000,sz:0.5"] (repeatable; split multi-tier take-profit; mutually exclusive with --tpTriggerPx/--tpOrdPx)',
|
|
13070
14078
|
description: "Place a new spot order (supports attached TP/SL)"
|
|
13071
14079
|
},
|
|
13072
14080
|
amend: {
|
|
@@ -13102,8 +14110,8 @@ var CLI_REGISTRY = {
|
|
|
13102
14110
|
},
|
|
13103
14111
|
place: {
|
|
13104
14112
|
toolName: "spot_place_algo_order",
|
|
13105
|
-
usage:
|
|
13106
|
-
description: "Place a spot algo order (
|
|
14113
|
+
usage: 'okx spot algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco|move_order_stop|trigger|chase|iceberg|twap>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--tpOrdKind <condition|limit>] [--tpTriggerPxType <last|index|mark>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--slTriggerPxType <last|index|mark>]\n [--stpMode <cancel_maker|cancel_taker|cancel_both>] [--tdMode <cash|cross|isolated>]\n trigger: [--triggerPx <price>] [--orderPx <price|-1>] [--advanceOrdType <fok|ioc>] [--triggerPxType <last|index|mark>]\n chase: [--chaseType <distance|ratio>] [--chaseVal <n>] [--maxChaseType <distance|ratio>] [--maxChaseVal <n>]\n iceberg/twap: [--pxVar <n>|--pxSpread <n>] [--szLimit <n>] [--pxLimit <price>] [--timeInterval <secs>]\n power-user (CLI-only): [--tpTriggerRatio <ratio>] [--slTriggerRatio <ratio>] [--closeFraction <frac>] [--pxAmendType <0|1>]\n power-user (CLI-only): [--tpLevel "px:78000,sz:0.5,kind:limit"] [--tpLevel "px:81000,sz:0.5"] (repeatable; split multi-tier take-profit)',
|
|
14114
|
+
description: "Place a spot algo order (TP/SL, pending order, chase, iceberg, twap)"
|
|
13107
14115
|
},
|
|
13108
14116
|
trail: {
|
|
13109
14117
|
toolName: "spot_place_algo_order",
|
|
@@ -13150,7 +14158,7 @@ var CLI_REGISTRY = {
|
|
|
13150
14158
|
},
|
|
13151
14159
|
place: {
|
|
13152
14160
|
toolName: "swap_place_order",
|
|
13153
|
-
usage:
|
|
14161
|
+
usage: 'okx swap place --instId <id> --side <buy|sell> --ordType <type> --sz <n> [--posSide <side>] [--px <price>]\n [--tdMode <cross|isolated>] [--tgtCcy <base_ccy|quote_ccy|margin>] [--reduceOnly] [--clOrdId <id>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--tpOrdKind <condition|limit>] [--tpTriggerPxType <last|index|mark>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--slTriggerPxType <last|index|mark>]\n [--stpMode <cancel_maker|cancel_taker|cancel_both>]\n power-user (CLI-only): [--pxAmendType <0|1>]\n power-user (CLI-only): [--tpLevel "px:78000,sz:0.5,kind:limit"] [--tpLevel "px:81000,sz:0.5"] (repeatable; split multi-tier take-profit; mutually exclusive with --tpTriggerPx/--tpOrdPx)',
|
|
13154
14162
|
description: "Place a new perpetual swap order (supports attached TP/SL)"
|
|
13155
14163
|
},
|
|
13156
14164
|
cancel: {
|
|
@@ -13202,8 +14210,8 @@ var CLI_REGISTRY = {
|
|
|
13202
14210
|
},
|
|
13203
14211
|
place: {
|
|
13204
14212
|
toolName: "swap_place_algo_order",
|
|
13205
|
-
usage:
|
|
13206
|
-
description: "Place a swap algo order (
|
|
14213
|
+
usage: 'okx swap algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco|move_order_stop|trigger|chase|iceberg|twap>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--tpOrdKind <condition|limit>] [--tpTriggerPxType <last|index|mark>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--slTriggerPxType <last|index|mark>]\n [--stpMode <cancel_maker|cancel_taker|cancel_both>] [--cxlOnClosePos]\n [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]\n trigger: [--triggerPx <price>] [--orderPx <price|-1>] [--advanceOrdType <fok|ioc>] [--triggerPxType <last|index|mark>]\n chase: [--chaseType <distance|ratio>] [--chaseVal <n>] [--maxChaseType <distance|ratio>] [--maxChaseVal <n>]\n iceberg/twap: [--pxVar <n>|--pxSpread <n>] [--szLimit <n>] [--pxLimit <price>] [--timeInterval <secs>]\n power-user (CLI-only): [--tpTriggerRatio <ratio>] [--slTriggerRatio <ratio>] [--closeFraction <frac>] [--pxAmendType <0|1>]\n power-user (CLI-only): [--tpLevel "px:78000,sz:0.5,kind:limit"] [--tpLevel "px:81000,sz:0.5"] (repeatable; split multi-tier take-profit)',
|
|
14214
|
+
description: "Place a swap algo order (TP/SL, pending order, chase, iceberg, twap)"
|
|
13207
14215
|
},
|
|
13208
14216
|
amend: {
|
|
13209
14217
|
toolName: "swap_amend_algo_order",
|
|
@@ -13240,7 +14248,7 @@ var CLI_REGISTRY = {
|
|
|
13240
14248
|
},
|
|
13241
14249
|
place: {
|
|
13242
14250
|
toolName: "futures_place_order",
|
|
13243
|
-
usage:
|
|
14251
|
+
usage: 'okx futures place --instId <id> --side <buy|sell> --ordType <type> --sz <n>\n [--tdMode <cross|isolated>] [--posSide <net|long|short>] [--px <price>] [--reduceOnly]\n [--tgtCcy <base_ccy|quote_ccy|margin>] [--clOrdId <id>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--tpOrdKind <condition|limit>] [--tpTriggerPxType <last|index|mark>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--slTriggerPxType <last|index|mark>]\n [--stpMode <cancel_maker|cancel_taker|cancel_both>]\n power-user (CLI-only): [--pxAmendType <0|1>]\n power-user (CLI-only): [--tpLevel "px:78000,sz:0.5,kind:limit"] [--tpLevel "px:81000,sz:0.5"] (repeatable; split multi-tier take-profit; mutually exclusive with --tpTriggerPx/--tpOrdPx)',
|
|
13244
14252
|
description: "Place a new futures order (supports attached TP/SL)"
|
|
13245
14253
|
},
|
|
13246
14254
|
cancel: {
|
|
@@ -13296,7 +14304,7 @@ var CLI_REGISTRY = {
|
|
|
13296
14304
|
},
|
|
13297
14305
|
place: {
|
|
13298
14306
|
toolName: "futures_place_algo_order",
|
|
13299
|
-
usage:
|
|
14307
|
+
usage: 'okx futures algo place --instId <id> --side <buy|sell> --sz <n> [--ordType <conditional|oco|move_order_stop|trigger|chase|iceberg|twap>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--tpOrdKind <condition|limit>] [--tpTriggerPxType <last|index|mark>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--slTriggerPxType <last|index|mark>]\n [--stpMode <cancel_maker|cancel_taker|cancel_both>] [--cxlOnClosePos]\n [--posSide <net|long|short>] [--tdMode <cross|isolated>] [--reduceOnly]\n trigger: [--triggerPx <price>] [--orderPx <price|-1>] [--advanceOrdType <fok|ioc>] [--triggerPxType <last|index|mark>]\n chase: [--chaseType <distance|ratio>] [--chaseVal <n>] [--maxChaseType <distance|ratio>] [--maxChaseVal <n>]\n iceberg/twap: [--pxVar <n>|--pxSpread <n>] [--szLimit <n>] [--pxLimit <price>] [--timeInterval <secs>]\n power-user (CLI-only): [--tpTriggerRatio <ratio>] [--slTriggerRatio <ratio>] [--closeFraction <frac>] [--pxAmendType <0|1>]\n power-user (CLI-only): [--tpLevel "px:78000,sz:0.5,kind:limit"] [--tpLevel "px:81000,sz:0.5"] (repeatable; split multi-tier take-profit)',
|
|
13300
14308
|
description: "Place a futures algo order (take-profit/stop-loss)"
|
|
13301
14309
|
},
|
|
13302
14310
|
amend: {
|
|
@@ -13349,7 +14357,7 @@ var CLI_REGISTRY = {
|
|
|
13349
14357
|
},
|
|
13350
14358
|
place: {
|
|
13351
14359
|
toolName: "option_place_order",
|
|
13352
|
-
usage: "okx option place --instId <id> --tdMode <cash|cross|isolated> --side <buy|sell> --ordType <type> --sz <n>\n [--px <price>] [--tgtCcy <base_ccy|quote_ccy|margin>] [--reduceOnly] [--clOrdId <id>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--slTriggerPx <price>] [--slOrdPx <price|-1>]",
|
|
14360
|
+
usage: "okx option place --instId <id> --tdMode <cash|cross|isolated> --side <buy|sell> --ordType <type> --sz <n>\n [--px <price>] [--tgtCcy <base_ccy|quote_ccy|margin>] [--reduceOnly] [--clOrdId <id>]\n [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--tpOrdKind <condition|limit>] [--tpTriggerPxType <last|index|mark>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--slTriggerPxType <last|index|mark>]\n [--stpMode <cancel_maker|cancel_taker|cancel_both>]",
|
|
13353
14361
|
description: "Place a new option order"
|
|
13354
14362
|
},
|
|
13355
14363
|
cancel: {
|
|
@@ -13379,7 +14387,7 @@ var CLI_REGISTRY = {
|
|
|
13379
14387
|
},
|
|
13380
14388
|
place: {
|
|
13381
14389
|
toolName: "option_place_algo_order",
|
|
13382
|
-
usage: "okx option algo place --instId <id> --tdMode <cash|cross|isolated> --side <buy|sell> --sz <n>\n [--ordType <conditional|oco>] [--tpTriggerPx <price>] [--tpOrdPx <price|-1>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--reduceOnly] [--clOrdId <id>]",
|
|
14390
|
+
usage: "okx option algo place --instId <id> --tdMode <cash|cross|isolated> --side <buy|sell> --sz <n>\n [--ordType <conditional|oco>] [--tpTriggerPx <price>] [--tpOrdPx <price|-1>] [--tpTriggerPxType <last|index|mark>]\n [--slTriggerPx <price>] [--slOrdPx <price|-1>] [--slTriggerPxType <last|index|mark>]\n [--reduceOnly] [--clOrdId <id>]",
|
|
13383
14391
|
description: "Place an option algo order (take-profit/stop-loss)"
|
|
13384
14392
|
},
|
|
13385
14393
|
amend: {
|
|
@@ -13678,32 +14686,57 @@ var CLI_REGISTRY = {
|
|
|
13678
14686
|
},
|
|
13679
14687
|
// ── smartmoney ─────────────────────────────────────────────────────────────
|
|
13680
14688
|
smartmoney: {
|
|
13681
|
-
description: "Smart money
|
|
14689
|
+
description: "Smart money analytics \u2014 trader leaderboard, consensus signals, and position analysis",
|
|
13682
14690
|
commands: {
|
|
13683
|
-
|
|
13684
|
-
toolName: "
|
|
13685
|
-
usage: "okx smartmoney
|
|
13686
|
-
description: "
|
|
13687
|
-
},
|
|
13688
|
-
|
|
13689
|
-
toolName: "
|
|
13690
|
-
usage: "okx smartmoney
|
|
13691
|
-
description: "
|
|
13692
|
-
},
|
|
13693
|
-
"
|
|
13694
|
-
toolName: "
|
|
13695
|
-
usage: "okx smartmoney
|
|
13696
|
-
description: "
|
|
13697
|
-
},
|
|
13698
|
-
|
|
13699
|
-
toolName: "
|
|
13700
|
-
usage:
|
|
13701
|
-
description: "
|
|
13702
|
-
},
|
|
13703
|
-
trader: {
|
|
13704
|
-
toolName: "
|
|
13705
|
-
usage: "okx smartmoney trader --authorId <id> [--
|
|
13706
|
-
description: "
|
|
14691
|
+
"traders-by-filter": {
|
|
14692
|
+
toolName: "smartmoney_get_traders_by_filter",
|
|
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]",
|
|
14694
|
+
description: "Leaderboard of top smart-money traders, ranked and filtered by pool conditions"
|
|
14695
|
+
},
|
|
14696
|
+
"performance-by-trader": {
|
|
14697
|
+
toolName: "smartmoney_get_performance_by_trader",
|
|
14698
|
+
usage: "okx smartmoney performance-by-trader --authorIds <id1,id2> [--sortBy <pnl|pnlRatio, default pnl>] [--period <3|7|30|90, default 90>] [--json]",
|
|
14699
|
+
description: "PnL / win-rate / drawdown profile for one or more traders by authorIds"
|
|
14700
|
+
},
|
|
14701
|
+
"trader-positions": {
|
|
14702
|
+
toolName: "smartmoney_get_trader_positions",
|
|
14703
|
+
usage: "okx smartmoney trader-positions --authorId <id> [--instId <id>] [--json]",
|
|
14704
|
+
description: "Currently-open positions held by a single trader"
|
|
14705
|
+
},
|
|
14706
|
+
"trader-positions-history": {
|
|
14707
|
+
toolName: "smartmoney_get_trader_positions_history",
|
|
14708
|
+
usage: "okx smartmoney trader-positions-history --authorId <id> [--instId <id>] [--after <posId>] [--before <posId>] [--limit <n, default 10>] [--json]",
|
|
14709
|
+
description: "Closed-position history of a single trader (paginated)"
|
|
14710
|
+
},
|
|
14711
|
+
"trader-orders-history": {
|
|
14712
|
+
toolName: "smartmoney_get_trader_orders_history",
|
|
14713
|
+
usage: "okx smartmoney trader-orders-history --authorId <id> [--instId <id>] [--after <ordId>] [--before <ordId>] [--limit <n, default 10>] [--json]",
|
|
14714
|
+
description: "Recent orders/fills placed by a single trader (paginated)"
|
|
14715
|
+
},
|
|
14716
|
+
"search-trader": {
|
|
14717
|
+
toolName: "smartmoney_search_trader",
|
|
14718
|
+
usage: "okx smartmoney search-trader --keyword <name> [--json]",
|
|
14719
|
+
description: "Search Top Traders by nickname keyword (\u226410 results, ranked by follower count)"
|
|
14720
|
+
},
|
|
14721
|
+
"signal-overview-by-filter": {
|
|
14722
|
+
toolName: "smartmoney_get_signal_overview_by_filter",
|
|
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]",
|
|
14724
|
+
description: "Multi-asset smart-money consensus signal aggregated over a tier-filtered pool"
|
|
14725
|
+
},
|
|
14726
|
+
"signal-overview-by-trader": {
|
|
14727
|
+
toolName: "smartmoney_get_signal_overview_by_trader",
|
|
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]",
|
|
14729
|
+
description: "Multi-asset smart-money signal aggregated over a hand-picked set of traders (authorIds-direct-lookup; pool filters not exposed)"
|
|
14730
|
+
},
|
|
14731
|
+
"signal-trend-by-filter": {
|
|
14732
|
+
toolName: "smartmoney_get_signal_trend_by_filter",
|
|
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]",
|
|
14734
|
+
description: "Single-coin smart-money signal time-series aggregated over a tier-filtered pool, anchored at asOfTime"
|
|
14735
|
+
},
|
|
14736
|
+
"signal-trend-by-trader": {
|
|
14737
|
+
toolName: "smartmoney_get_signal_trend_by_trader",
|
|
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]",
|
|
14739
|
+
description: "Single-coin smart-money signal time-series aggregated over a hand-picked set of traders (authorIds-direct-lookup; pool filters not exposed)"
|
|
13707
14740
|
}
|
|
13708
14741
|
}
|
|
13709
14742
|
},
|
|
@@ -14407,6 +15440,33 @@ var CLI_OPTIONS = {
|
|
|
14407
15440
|
tpOrdPx: { type: "string" },
|
|
14408
15441
|
slTriggerPx: { type: "string" },
|
|
14409
15442
|
slOrdPx: { type: "string" },
|
|
15443
|
+
// Phase 1 algo order flags (issue #178)
|
|
15444
|
+
tpOrdKind: { type: "string" },
|
|
15445
|
+
tpTriggerPxType: { type: "string" },
|
|
15446
|
+
slTriggerPxType: { type: "string" },
|
|
15447
|
+
stpMode: { type: "string" },
|
|
15448
|
+
cxlOnClosePos: { type: "boolean", default: false },
|
|
15449
|
+
// Phase 3a+c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
15450
|
+
tpTriggerRatio: { type: "string" },
|
|
15451
|
+
slTriggerRatio: { type: "string" },
|
|
15452
|
+
closeFraction: { type: "string" },
|
|
15453
|
+
banAmend: { type: "boolean", default: false },
|
|
15454
|
+
pxAmendType: { type: "string" },
|
|
15455
|
+
// Phase 3b CLI power-user flag (issue #183, CLI-only no MCP/skill exposure)
|
|
15456
|
+
tpLevel: { type: "string", multiple: true },
|
|
15457
|
+
// Phase 2 algo ordType flags (issue #181)
|
|
15458
|
+
orderPx: { type: "string" },
|
|
15459
|
+
advanceOrdType: { type: "string" },
|
|
15460
|
+
triggerPxType: { type: "string" },
|
|
15461
|
+
chaseType: { type: "string" },
|
|
15462
|
+
chaseVal: { type: "string" },
|
|
15463
|
+
maxChaseType: { type: "string" },
|
|
15464
|
+
maxChaseVal: { type: "string" },
|
|
15465
|
+
pxVar: { type: "string" },
|
|
15466
|
+
pxSpread: { type: "string" },
|
|
15467
|
+
szLimit: { type: "string" },
|
|
15468
|
+
pxLimit: { type: "string" },
|
|
15469
|
+
timeInterval: { type: "string" },
|
|
14410
15470
|
algoId: { type: "string" },
|
|
14411
15471
|
reduceOnly: { type: "boolean", default: false },
|
|
14412
15472
|
// algo amend
|
|
@@ -14494,19 +15554,23 @@ var CLI_OPTIONS = {
|
|
|
14494
15554
|
// smartmoney
|
|
14495
15555
|
authorId: { type: "string" },
|
|
14496
15556
|
authorIds: { type: "string" },
|
|
14497
|
-
|
|
14498
|
-
sortType: { type: "string" },
|
|
15557
|
+
updateTime: { type: "string" },
|
|
14499
15558
|
granularity: { type: "string" },
|
|
14500
15559
|
lmtNum: { type: "string" },
|
|
14501
15560
|
instCcy: { type: "string" },
|
|
14502
15561
|
instCcyList: { type: "string" },
|
|
14503
15562
|
topInstruments: { type: "string" },
|
|
14504
|
-
|
|
14505
|
-
// smartmoney pool filters
|
|
14506
|
-
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
15563
|
+
asOfTime: { type: "string" },
|
|
15564
|
+
// smartmoney pool filters — leaderboard (numeric thresholds)
|
|
15565
|
+
minPnl: { type: "string" },
|
|
15566
|
+
minWinRate: { type: "string" },
|
|
15567
|
+
maxDrawdown: { type: "string" },
|
|
15568
|
+
minAum: { type: "string" },
|
|
15569
|
+
// smartmoney pool filters — signal endpoints (enum tiers)
|
|
15570
|
+
pnlTier: { type: "string" },
|
|
15571
|
+
winRateTier: { type: "string" },
|
|
15572
|
+
maxDrawdownTier: { type: "string" },
|
|
15573
|
+
aumTier: { type: "string" },
|
|
14510
15574
|
// upgrade
|
|
14511
15575
|
beta: { type: "boolean", default: false },
|
|
14512
15576
|
check: { type: "boolean", default: false },
|
|
@@ -14593,6 +15657,42 @@ var CLI_OPTIONS = {
|
|
|
14593
15657
|
output: { type: "string" }
|
|
14594
15658
|
// diagnose --output only: save report to file
|
|
14595
15659
|
};
|
|
15660
|
+
var TP_LEVEL_KEY_MAP = {
|
|
15661
|
+
px: "tpOrdPx",
|
|
15662
|
+
sz: "sz",
|
|
15663
|
+
kind: "tpOrdKind",
|
|
15664
|
+
triggerPx: "tpTriggerPx",
|
|
15665
|
+
triggerPxType: "tpTriggerPxType",
|
|
15666
|
+
amendPxOnTrigger: "amendPxOnTriggerType",
|
|
15667
|
+
clOrdId: "attachAlgoClOrdId"
|
|
15668
|
+
};
|
|
15669
|
+
function parseTpLevel(s) {
|
|
15670
|
+
if (!s || !s.includes(":")) {
|
|
15671
|
+
throw new Error(
|
|
15672
|
+
`Invalid --tpLevel format: "${s}". Expected "key:value,key:value,..." (e.g. "px:78000,sz:0.5,kind:limit")`
|
|
15673
|
+
);
|
|
15674
|
+
}
|
|
15675
|
+
const result = {};
|
|
15676
|
+
const pairs = s.split(",");
|
|
15677
|
+
for (const pair of pairs) {
|
|
15678
|
+
const colonIdx = pair.indexOf(":");
|
|
15679
|
+
if (colonIdx < 1) {
|
|
15680
|
+
throw new Error(
|
|
15681
|
+
`Invalid --tpLevel format: "${pair}". Each entry must be "key:value", not "${pair}". Valid keys: ${Object.keys(TP_LEVEL_KEY_MAP).join(", ")}`
|
|
15682
|
+
);
|
|
15683
|
+
}
|
|
15684
|
+
const key = pair.slice(0, colonIdx).trim();
|
|
15685
|
+
const value = pair.slice(colonIdx + 1).trim();
|
|
15686
|
+
const mapped = TP_LEVEL_KEY_MAP[key];
|
|
15687
|
+
if (!mapped) {
|
|
15688
|
+
throw new Error(
|
|
15689
|
+
`Unknown --tpLevel key: "${key}". Valid keys: ${Object.keys(TP_LEVEL_KEY_MAP).join(", ")}`
|
|
15690
|
+
);
|
|
15691
|
+
}
|
|
15692
|
+
result[mapped] = value;
|
|
15693
|
+
}
|
|
15694
|
+
return result;
|
|
15695
|
+
}
|
|
14596
15696
|
function parseCli(argv) {
|
|
14597
15697
|
const negated = /* @__PURE__ */ new Set();
|
|
14598
15698
|
const filtered = argv.filter((arg) => {
|
|
@@ -15338,8 +16438,16 @@ async function cmdSpotPlace(run, opts) {
|
|
|
15338
16438
|
clOrdId: opts.clOrdId,
|
|
15339
16439
|
tpTriggerPx: opts.tpTriggerPx,
|
|
15340
16440
|
tpOrdPx: opts.tpOrdPx,
|
|
16441
|
+
tpOrdKind: opts.tpOrdKind,
|
|
16442
|
+
tpTriggerPxType: opts.tpTriggerPxType,
|
|
15341
16443
|
slTriggerPx: opts.slTriggerPx,
|
|
15342
|
-
slOrdPx: opts.slOrdPx
|
|
16444
|
+
slOrdPx: opts.slOrdPx,
|
|
16445
|
+
slTriggerPxType: opts.slTriggerPxType,
|
|
16446
|
+
stpMode: opts.stpMode,
|
|
16447
|
+
tradeQuoteCcy: opts.tradeQuoteCcy,
|
|
16448
|
+
banAmend: opts.banAmend,
|
|
16449
|
+
pxAmendType: opts.pxAmendType,
|
|
16450
|
+
tpLevels: opts.tpLevels
|
|
15343
16451
|
});
|
|
15344
16452
|
const data = getData4(result);
|
|
15345
16453
|
if (opts.json) return printJson(data);
|
|
@@ -15364,11 +16472,33 @@ async function cmdSpotAlgoPlace(run, opts) {
|
|
|
15364
16472
|
tgtCcy: opts.tgtCcy,
|
|
15365
16473
|
tpTriggerPx: opts.tpTriggerPx,
|
|
15366
16474
|
tpOrdPx: opts.tpOrdPx,
|
|
16475
|
+
tpOrdKind: opts.tpOrdKind,
|
|
16476
|
+
tpTriggerPxType: opts.tpTriggerPxType,
|
|
15367
16477
|
slTriggerPx: opts.slTriggerPx,
|
|
15368
16478
|
slOrdPx: opts.slOrdPx,
|
|
16479
|
+
slTriggerPxType: opts.slTriggerPxType,
|
|
16480
|
+
stpMode: opts.stpMode,
|
|
15369
16481
|
callbackRatio: opts.callbackRatio,
|
|
15370
16482
|
callbackSpread: opts.callbackSpread,
|
|
15371
|
-
activePx: opts.activePx
|
|
16483
|
+
activePx: opts.activePx,
|
|
16484
|
+
triggerPx: opts.triggerPx,
|
|
16485
|
+
orderPx: opts.orderPx,
|
|
16486
|
+
advanceOrdType: opts.advanceOrdType,
|
|
16487
|
+
triggerPxType: opts.triggerPxType,
|
|
16488
|
+
chaseType: opts.chaseType,
|
|
16489
|
+
chaseVal: opts.chaseVal,
|
|
16490
|
+
maxChaseType: opts.maxChaseType,
|
|
16491
|
+
maxChaseVal: opts.maxChaseVal,
|
|
16492
|
+
pxVar: opts.pxVar,
|
|
16493
|
+
pxSpread: opts.pxSpread,
|
|
16494
|
+
szLimit: opts.szLimit,
|
|
16495
|
+
pxLimit: opts.pxLimit,
|
|
16496
|
+
timeInterval: opts.timeInterval,
|
|
16497
|
+
tpTriggerRatio: opts.tpTriggerRatio,
|
|
16498
|
+
slTriggerRatio: opts.slTriggerRatio,
|
|
16499
|
+
closeFraction: opts.closeFraction,
|
|
16500
|
+
pxAmendType: opts.pxAmendType,
|
|
16501
|
+
tpLevels: opts.tpLevels
|
|
15372
16502
|
});
|
|
15373
16503
|
const data = getData4(result);
|
|
15374
16504
|
if (opts.json) return printJson(data);
|
|
@@ -15602,8 +16732,14 @@ async function cmdSwapPlace(run, opts) {
|
|
|
15602
16732
|
clOrdId: opts.clOrdId,
|
|
15603
16733
|
tpTriggerPx: opts.tpTriggerPx,
|
|
15604
16734
|
tpOrdPx: opts.tpOrdPx,
|
|
16735
|
+
tpOrdKind: opts.tpOrdKind,
|
|
16736
|
+
tpTriggerPxType: opts.tpTriggerPxType,
|
|
15605
16737
|
slTriggerPx: opts.slTriggerPx,
|
|
15606
|
-
slOrdPx: opts.slOrdPx
|
|
16738
|
+
slOrdPx: opts.slOrdPx,
|
|
16739
|
+
slTriggerPxType: opts.slTriggerPxType,
|
|
16740
|
+
stpMode: opts.stpMode,
|
|
16741
|
+
pxAmendType: opts.pxAmendType,
|
|
16742
|
+
tpLevels: opts.tpLevels
|
|
15607
16743
|
});
|
|
15608
16744
|
const data = getData5(result);
|
|
15609
16745
|
if (opts.json) return printJson(data);
|
|
@@ -15629,12 +16765,35 @@ async function cmdSwapAlgoPlace(run, opts) {
|
|
|
15629
16765
|
posSide: opts.posSide,
|
|
15630
16766
|
tpTriggerPx: opts.tpTriggerPx,
|
|
15631
16767
|
tpOrdPx: opts.tpOrdPx,
|
|
16768
|
+
tpOrdKind: opts.tpOrdKind,
|
|
16769
|
+
tpTriggerPxType: opts.tpTriggerPxType,
|
|
15632
16770
|
slTriggerPx: opts.slTriggerPx,
|
|
15633
16771
|
slOrdPx: opts.slOrdPx,
|
|
16772
|
+
slTriggerPxType: opts.slTriggerPxType,
|
|
16773
|
+
stpMode: opts.stpMode,
|
|
16774
|
+
cxlOnClosePos: opts.cxlOnClosePos,
|
|
15634
16775
|
reduceOnly: opts.reduceOnly,
|
|
15635
16776
|
callbackRatio: opts.callbackRatio,
|
|
15636
16777
|
callbackSpread: opts.callbackSpread,
|
|
15637
|
-
activePx: opts.activePx
|
|
16778
|
+
activePx: opts.activePx,
|
|
16779
|
+
triggerPx: opts.triggerPx,
|
|
16780
|
+
orderPx: opts.orderPx,
|
|
16781
|
+
advanceOrdType: opts.advanceOrdType,
|
|
16782
|
+
triggerPxType: opts.triggerPxType,
|
|
16783
|
+
chaseType: opts.chaseType,
|
|
16784
|
+
chaseVal: opts.chaseVal,
|
|
16785
|
+
maxChaseType: opts.maxChaseType,
|
|
16786
|
+
maxChaseVal: opts.maxChaseVal,
|
|
16787
|
+
pxVar: opts.pxVar,
|
|
16788
|
+
pxSpread: opts.pxSpread,
|
|
16789
|
+
szLimit: opts.szLimit,
|
|
16790
|
+
pxLimit: opts.pxLimit,
|
|
16791
|
+
timeInterval: opts.timeInterval,
|
|
16792
|
+
tpTriggerRatio: opts.tpTriggerRatio,
|
|
16793
|
+
slTriggerRatio: opts.slTriggerRatio,
|
|
16794
|
+
closeFraction: opts.closeFraction,
|
|
16795
|
+
pxAmendType: opts.pxAmendType,
|
|
16796
|
+
tpLevels: opts.tpLevels
|
|
15638
16797
|
});
|
|
15639
16798
|
const data = getData5(result);
|
|
15640
16799
|
if (opts.json) return printJson(data);
|
|
@@ -15908,8 +17067,14 @@ async function cmdFuturesPlace(run, opts) {
|
|
|
15908
17067
|
clOrdId: opts.clOrdId,
|
|
15909
17068
|
tpTriggerPx: opts.tpTriggerPx,
|
|
15910
17069
|
tpOrdPx: opts.tpOrdPx,
|
|
17070
|
+
tpOrdKind: opts.tpOrdKind,
|
|
17071
|
+
tpTriggerPxType: opts.tpTriggerPxType,
|
|
15911
17072
|
slTriggerPx: opts.slTriggerPx,
|
|
15912
|
-
slOrdPx: opts.slOrdPx
|
|
17073
|
+
slOrdPx: opts.slOrdPx,
|
|
17074
|
+
slTriggerPxType: opts.slTriggerPxType,
|
|
17075
|
+
stpMode: opts.stpMode,
|
|
17076
|
+
pxAmendType: opts.pxAmendType,
|
|
17077
|
+
tpLevels: opts.tpLevels
|
|
15913
17078
|
});
|
|
15914
17079
|
const data = getData6(result);
|
|
15915
17080
|
if (opts.json) return printJson(data);
|
|
@@ -16037,12 +17202,35 @@ async function cmdFuturesAlgoPlace(run, opts) {
|
|
|
16037
17202
|
posSide: opts.posSide,
|
|
16038
17203
|
tpTriggerPx: opts.tpTriggerPx,
|
|
16039
17204
|
tpOrdPx: opts.tpOrdPx,
|
|
17205
|
+
tpOrdKind: opts.tpOrdKind,
|
|
17206
|
+
tpTriggerPxType: opts.tpTriggerPxType,
|
|
16040
17207
|
slTriggerPx: opts.slTriggerPx,
|
|
16041
17208
|
slOrdPx: opts.slOrdPx,
|
|
17209
|
+
slTriggerPxType: opts.slTriggerPxType,
|
|
17210
|
+
stpMode: opts.stpMode,
|
|
17211
|
+
cxlOnClosePos: opts.cxlOnClosePos,
|
|
16042
17212
|
reduceOnly: opts.reduceOnly,
|
|
16043
17213
|
callbackRatio: opts.callbackRatio,
|
|
16044
17214
|
callbackSpread: opts.callbackSpread,
|
|
16045
|
-
activePx: opts.activePx
|
|
17215
|
+
activePx: opts.activePx,
|
|
17216
|
+
triggerPx: opts.triggerPx,
|
|
17217
|
+
orderPx: opts.orderPx,
|
|
17218
|
+
advanceOrdType: opts.advanceOrdType,
|
|
17219
|
+
triggerPxType: opts.triggerPxType,
|
|
17220
|
+
chaseType: opts.chaseType,
|
|
17221
|
+
chaseVal: opts.chaseVal,
|
|
17222
|
+
maxChaseType: opts.maxChaseType,
|
|
17223
|
+
maxChaseVal: opts.maxChaseVal,
|
|
17224
|
+
pxVar: opts.pxVar,
|
|
17225
|
+
pxSpread: opts.pxSpread,
|
|
17226
|
+
szLimit: opts.szLimit,
|
|
17227
|
+
pxLimit: opts.pxLimit,
|
|
17228
|
+
timeInterval: opts.timeInterval,
|
|
17229
|
+
tpTriggerRatio: opts.tpTriggerRatio,
|
|
17230
|
+
slTriggerRatio: opts.slTriggerRatio,
|
|
17231
|
+
closeFraction: opts.closeFraction,
|
|
17232
|
+
pxAmendType: opts.pxAmendType,
|
|
17233
|
+
tpLevels: opts.tpLevels
|
|
16046
17234
|
});
|
|
16047
17235
|
const data = getData6(result);
|
|
16048
17236
|
if (opts.json) return printJson(data);
|
|
@@ -16274,8 +17462,12 @@ async function cmdOptionPlace(run, opts) {
|
|
|
16274
17462
|
clOrdId: opts.clOrdId,
|
|
16275
17463
|
tpTriggerPx: opts.tpTriggerPx,
|
|
16276
17464
|
tpOrdPx: opts.tpOrdPx,
|
|
17465
|
+
tpOrdKind: opts.tpOrdKind,
|
|
17466
|
+
tpTriggerPxType: opts.tpTriggerPxType,
|
|
16277
17467
|
slTriggerPx: opts.slTriggerPx,
|
|
16278
|
-
slOrdPx: opts.slOrdPx
|
|
17468
|
+
slOrdPx: opts.slOrdPx,
|
|
17469
|
+
slTriggerPxType: opts.slTriggerPxType,
|
|
17470
|
+
stpMode: opts.stpMode
|
|
16279
17471
|
});
|
|
16280
17472
|
const data = getData7(result);
|
|
16281
17473
|
if (opts.json) return printJson(data);
|
|
@@ -16894,175 +18086,272 @@ function extractFixedOffers(result) {
|
|
|
16894
18086
|
}
|
|
16895
18087
|
|
|
16896
18088
|
// src/commands/smartmoney.ts
|
|
16897
|
-
function
|
|
16898
|
-
if (json) {
|
|
16899
|
-
printJson(data);
|
|
16900
|
-
return;
|
|
16901
|
-
}
|
|
18089
|
+
function printDataTable(data, emptyMsg, mapper) {
|
|
16902
18090
|
if (!data.length) {
|
|
16903
18091
|
outputLine(emptyMsg);
|
|
16904
18092
|
return;
|
|
16905
18093
|
}
|
|
16906
18094
|
printTable(data.map(mapper));
|
|
16907
18095
|
}
|
|
16908
|
-
function
|
|
18096
|
+
function csvToArray(value) {
|
|
18097
|
+
if (!value) return void 0;
|
|
18098
|
+
const arr = value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
18099
|
+
return arr.length > 0 ? arr : void 0;
|
|
18100
|
+
}
|
|
18101
|
+
function printPaginationHint(result) {
|
|
18102
|
+
if (!result || typeof result !== "object") return;
|
|
18103
|
+
const pagination = result.pagination;
|
|
18104
|
+
if (!pagination || typeof pagination !== "object") return;
|
|
18105
|
+
const { hasMore, nextAfter } = pagination;
|
|
18106
|
+
if (hasMore !== true) return;
|
|
18107
|
+
const cursor = typeof nextAfter === "string" || typeof nextAfter === "number" ? String(nextAfter) : "";
|
|
18108
|
+
errorLine(cursor ? `more results \u2014 pass --after ${cursor} for next page` : "more results \u2014 pass --after <cursor> for next page");
|
|
18109
|
+
}
|
|
18110
|
+
function signalPoolFilterArgs(o) {
|
|
16909
18111
|
const result = {};
|
|
16910
|
-
if (o.
|
|
18112
|
+
if (o.sortBy) result.sortBy = o.sortBy;
|
|
16911
18113
|
if (o.period) result.period = o.period;
|
|
16912
|
-
if (o.
|
|
16913
|
-
if (o.
|
|
16914
|
-
if (o.
|
|
16915
|
-
if (o.
|
|
18114
|
+
if (o.pnlTier) result.pnlTier = o.pnlTier;
|
|
18115
|
+
if (o.winRateTier) result.winRateTier = o.winRateTier;
|
|
18116
|
+
if (o.maxDrawdownTier) result.maxDrawdownTier = o.maxDrawdownTier;
|
|
18117
|
+
if (o.aumTier) result.aumTier = o.aumTier;
|
|
16916
18118
|
return result;
|
|
16917
18119
|
}
|
|
16918
|
-
|
|
16919
|
-
const result =
|
|
16920
|
-
|
|
16921
|
-
|
|
16922
|
-
|
|
16923
|
-
|
|
16924
|
-
|
|
16925
|
-
|
|
16926
|
-
|
|
16927
|
-
|
|
18120
|
+
function leaderboardPoolFilterArgs(o) {
|
|
18121
|
+
const result = {};
|
|
18122
|
+
if (o.sortBy) result.sortBy = o.sortBy;
|
|
18123
|
+
if (o.period) result.period = o.period;
|
|
18124
|
+
if (o.minPnl) result.minPnl = o.minPnl;
|
|
18125
|
+
if (o.minWinRate) result.minWinRate = o.minWinRate;
|
|
18126
|
+
if (o.maxDrawdown) result.maxDrawdown = o.maxDrawdown;
|
|
18127
|
+
if (o.minAum) result.minAum = o.minAum;
|
|
18128
|
+
return result;
|
|
18129
|
+
}
|
|
18130
|
+
async function cmdSmartmoneyTradersByFilter(run, opts) {
|
|
18131
|
+
const result = await run("smartmoney_get_traders_by_filter", {
|
|
18132
|
+
updateTime: opts.updateTime,
|
|
18133
|
+
...leaderboardPoolFilterArgs(opts),
|
|
18134
|
+
after: opts.after,
|
|
18135
|
+
before: opts.before,
|
|
18136
|
+
limit: opts.limit
|
|
16928
18137
|
});
|
|
18138
|
+
if (opts.json) {
|
|
18139
|
+
printJson(result);
|
|
18140
|
+
return;
|
|
18141
|
+
}
|
|
16929
18142
|
const data = extractData(result);
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
18143
|
+
printDataTable(data, "No traders found", (r) => ({
|
|
18144
|
+
authorId: r["authorId"],
|
|
18145
|
+
nickName: r["nickName"],
|
|
18146
|
+
pnl: r["pnl"],
|
|
18147
|
+
pnlRatio: r["pnlRatio"],
|
|
18148
|
+
winRate: r["winRate"],
|
|
18149
|
+
maxDrawdown: r["maxDrawdown"],
|
|
18150
|
+
asset: r["asset"]
|
|
16937
18151
|
}));
|
|
18152
|
+
printPaginationHint(result);
|
|
16938
18153
|
}
|
|
16939
|
-
async function
|
|
16940
|
-
const result = await run("
|
|
16941
|
-
|
|
16942
|
-
|
|
16943
|
-
|
|
16944
|
-
ts: opts.ts,
|
|
16945
|
-
...poolFilterArgs(opts),
|
|
16946
|
-
lmtNum: opts.lmtNum,
|
|
16947
|
-
authorIds: opts.authorIds
|
|
18154
|
+
async function cmdSmartmoneyPerformanceByTrader(run, opts) {
|
|
18155
|
+
const result = await run("smartmoney_get_performance_by_trader", {
|
|
18156
|
+
authorIds: csvToArray(opts.authorIds),
|
|
18157
|
+
sortBy: opts.sortBy,
|
|
18158
|
+
period: opts.period
|
|
16948
18159
|
});
|
|
16949
|
-
const data = extractData(result);
|
|
16950
|
-
const signal = data[0];
|
|
16951
18160
|
if (opts.json) {
|
|
16952
|
-
printJson(
|
|
18161
|
+
printJson(result);
|
|
16953
18162
|
return;
|
|
16954
18163
|
}
|
|
16955
|
-
|
|
16956
|
-
|
|
18164
|
+
const data = extractData(result);
|
|
18165
|
+
printDataTable(data, "No traders found", (r) => ({
|
|
18166
|
+
authorId: r["authorId"],
|
|
18167
|
+
nickName: r["nickName"],
|
|
18168
|
+
pnl: r["pnl"],
|
|
18169
|
+
pnlRatio: r["pnlRatio"],
|
|
18170
|
+
winRate: r["winRate"],
|
|
18171
|
+
maxDrawdown: r["maxDrawdown"],
|
|
18172
|
+
asset: r["asset"]
|
|
18173
|
+
}));
|
|
18174
|
+
}
|
|
18175
|
+
async function cmdSmartmoneyTraderPositions(run, opts) {
|
|
18176
|
+
const result = await run("smartmoney_get_trader_positions", {
|
|
18177
|
+
authorId: opts.authorId,
|
|
18178
|
+
instId: opts.instId
|
|
18179
|
+
});
|
|
18180
|
+
if (opts.json) {
|
|
18181
|
+
printJson(result);
|
|
16957
18182
|
return;
|
|
16958
18183
|
}
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
|
|
16966
|
-
|
|
16967
|
-
|
|
16968
|
-
|
|
16969
|
-
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
shortTraders: signal["shortTraders"],
|
|
16973
|
-
vs1h: signal["vs1h"],
|
|
16974
|
-
vs24h: signal["vs24h"],
|
|
16975
|
-
vs7d: signal["vs7d"],
|
|
16976
|
-
smartMoneyLongAvgEntry: signal["smartMoneyLongAvgEntry"],
|
|
16977
|
-
smartMoneyShortAvgEntry: signal["smartMoneyShortAvgEntry"],
|
|
16978
|
-
totalNotionalVs24h: signal["totalNotionalVs24h"],
|
|
16979
|
-
currentPrice: signal["currentPrice"],
|
|
16980
|
-
priceChange24h: signal["priceChange24h"],
|
|
16981
|
-
fundingRate: signal["fundingRate"],
|
|
16982
|
-
openInterest: signal["openInterest"],
|
|
16983
|
-
longShortAccountRatio: signal["longShortAccountRatio"]
|
|
16984
|
-
});
|
|
18184
|
+
const data = extractData(result);
|
|
18185
|
+
printDataTable(data, "No open positions", (r) => ({
|
|
18186
|
+
instId: r["instId"],
|
|
18187
|
+
direction: r["direction"] ?? r["posSide"],
|
|
18188
|
+
pos: r["pos"],
|
|
18189
|
+
lever: r["lever"],
|
|
18190
|
+
avgPx: r["avgPx"],
|
|
18191
|
+
last: r["last"],
|
|
18192
|
+
notionalUsd: r["notionalUsd"],
|
|
18193
|
+
upl: r["upl"],
|
|
18194
|
+
pnl: r["pnl"],
|
|
18195
|
+
positionIntensity: r["positionIntensity"]
|
|
18196
|
+
}));
|
|
16985
18197
|
}
|
|
16986
|
-
async function
|
|
16987
|
-
const result = await run("
|
|
18198
|
+
async function cmdSmartmoneyTraderPositionsHistory(run, opts) {
|
|
18199
|
+
const result = await run("smartmoney_get_trader_positions_history", {
|
|
18200
|
+
authorId: opts.authorId,
|
|
16988
18201
|
instId: opts.instId,
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
limit: opts.limit,
|
|
16993
|
-
...poolFilterArgs(opts)
|
|
18202
|
+
after: opts.after,
|
|
18203
|
+
before: opts.before,
|
|
18204
|
+
limit: opts.limit
|
|
16994
18205
|
});
|
|
18206
|
+
if (opts.json) {
|
|
18207
|
+
printJson(result);
|
|
18208
|
+
return;
|
|
18209
|
+
}
|
|
16995
18210
|
const data = extractData(result);
|
|
16996
|
-
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
18211
|
+
printDataTable(data, "No closed positions", (r) => ({
|
|
18212
|
+
cTime: r["cTime"],
|
|
18213
|
+
uTime: r["uTime"],
|
|
18214
|
+
instId: r["instId"],
|
|
18215
|
+
posSide: r["posSide"],
|
|
18216
|
+
openAvgPx: r["openAvgPx"],
|
|
18217
|
+
closeAvgPx: r["closeAvgPx"],
|
|
18218
|
+
pnl: r["pnl"],
|
|
18219
|
+
pnlRatio: r["pnlRatio"],
|
|
18220
|
+
closeType: r["closeType"]
|
|
17004
18221
|
}));
|
|
18222
|
+
printPaginationHint(result);
|
|
17005
18223
|
}
|
|
17006
|
-
async function
|
|
17007
|
-
const
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
authorIds: opts.authorIds,
|
|
18224
|
+
async function cmdSmartmoneyTraderOrdersHistory(run, opts) {
|
|
18225
|
+
const result = await run("smartmoney_get_trader_orders_history", {
|
|
18226
|
+
authorId: opts.authorId,
|
|
18227
|
+
instId: opts.instId,
|
|
17011
18228
|
after: opts.after,
|
|
17012
18229
|
before: opts.before,
|
|
17013
18230
|
limit: opts.limit
|
|
18231
|
+
});
|
|
18232
|
+
if (opts.json) {
|
|
18233
|
+
printJson(result);
|
|
18234
|
+
return;
|
|
18235
|
+
}
|
|
18236
|
+
const data = extractData(result);
|
|
18237
|
+
printDataTable(data, "No order history", (r) => ({
|
|
18238
|
+
cTime: r["cTime"],
|
|
18239
|
+
instId: r["instId"],
|
|
18240
|
+
side: r["side"],
|
|
18241
|
+
posSide: r["posSide"],
|
|
18242
|
+
ordType: r["ordType"],
|
|
18243
|
+
avgPx: r["avgPx"],
|
|
18244
|
+
sz: r["sz"],
|
|
18245
|
+
value: r["value"]
|
|
17014
18246
|
}));
|
|
17015
|
-
|
|
18247
|
+
printPaginationHint(result);
|
|
18248
|
+
}
|
|
18249
|
+
async function cmdSmartmoneySearchTrader(run, opts) {
|
|
18250
|
+
const result = await run("smartmoney_search_trader", {
|
|
18251
|
+
keyword: opts.keyword
|
|
18252
|
+
});
|
|
18253
|
+
if (opts.json) {
|
|
18254
|
+
printJson(result);
|
|
18255
|
+
return;
|
|
18256
|
+
}
|
|
18257
|
+
const data = extractData(result);
|
|
18258
|
+
printDataTable(data, "No matching top traders", (r) => ({
|
|
17016
18259
|
authorId: r["authorId"],
|
|
17017
18260
|
nickName: r["nickName"],
|
|
17018
|
-
|
|
17019
|
-
pnlRatio: r["pnlRatio"],
|
|
17020
|
-
winRatio: r["winRatio"],
|
|
17021
|
-
asset: r["asset"]
|
|
18261
|
+
followerCount: r["followerCount"]
|
|
17022
18262
|
}));
|
|
17023
18263
|
}
|
|
17024
|
-
|
|
17025
|
-
const
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
18264
|
+
var signalRowMapper = (r) => {
|
|
18265
|
+
const lsr = r["longShortRatio"] ?? {};
|
|
18266
|
+
const notional = r["notional"] ?? {};
|
|
18267
|
+
return {
|
|
18268
|
+
ccy: r["ccy"],
|
|
18269
|
+
tradersWithPosition: r["tradersWithPosition"],
|
|
18270
|
+
longRatio: lsr["longRatio"],
|
|
18271
|
+
weightedLongRatio: lsr["weightedLongRatio"],
|
|
18272
|
+
longTraders: r["longTraders"],
|
|
18273
|
+
shortTraders: r["shortTraders"],
|
|
18274
|
+
netNotionalUsdt: notional["netNotionalUsdt"],
|
|
18275
|
+
longRatioVs1h: lsr["longRatioVs1h"],
|
|
18276
|
+
longRatioVs24h: lsr["longRatioVs24h"],
|
|
18277
|
+
longRatioVs7d: lsr["longRatioVs7d"]
|
|
18278
|
+
};
|
|
18279
|
+
};
|
|
18280
|
+
async function cmdSmartmoneySignalOverviewByFilter(run, opts) {
|
|
18281
|
+
const result = await run("smartmoney_get_signal_overview_by_filter", {
|
|
18282
|
+
topInstruments: opts.topInstruments,
|
|
18283
|
+
instCcyList: csvToArray(opts.instCcyList),
|
|
18284
|
+
...signalPoolFilterArgs(opts),
|
|
18285
|
+
lmtNum: opts.lmtNum
|
|
17030
18286
|
});
|
|
17031
|
-
const data = result;
|
|
17032
|
-
const inner = data["data"];
|
|
17033
18287
|
if (opts.json) {
|
|
17034
|
-
printJson(
|
|
18288
|
+
printJson(result);
|
|
17035
18289
|
return;
|
|
17036
18290
|
}
|
|
17037
|
-
|
|
17038
|
-
|
|
18291
|
+
const data = extractData(result);
|
|
18292
|
+
printDataTable(data, "No signal data", signalRowMapper);
|
|
18293
|
+
}
|
|
18294
|
+
async function cmdSmartmoneySignalOverviewByTrader(run, opts) {
|
|
18295
|
+
const result = await run("smartmoney_get_signal_overview_by_trader", {
|
|
18296
|
+
authorIds: csvToArray(opts.authorIds),
|
|
18297
|
+
topInstruments: opts.topInstruments,
|
|
18298
|
+
instCcyList: csvToArray(opts.instCcyList),
|
|
18299
|
+
sortBy: opts.sortBy,
|
|
18300
|
+
period: opts.period
|
|
18301
|
+
});
|
|
18302
|
+
if (opts.json) {
|
|
18303
|
+
printJson(result);
|
|
17039
18304
|
return;
|
|
17040
18305
|
}
|
|
17041
|
-
const
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
18306
|
+
const data = extractData(result);
|
|
18307
|
+
printDataTable(data, "No signal data", signalRowMapper);
|
|
18308
|
+
}
|
|
18309
|
+
var trendRowMapper = (r) => ({
|
|
18310
|
+
dataVersion: r["dataVersion"],
|
|
18311
|
+
ccy: r["ccy"],
|
|
18312
|
+
longRatio: r["longRatio"],
|
|
18313
|
+
shortRatio: r["shortRatio"],
|
|
18314
|
+
weightedLongRatio: r["weightedLongRatio"],
|
|
18315
|
+
weightedShortRatio: r["weightedShortRatio"],
|
|
18316
|
+
longTraders: r["longTraders"],
|
|
18317
|
+
shortTraders: r["shortTraders"],
|
|
18318
|
+
tradersWithPosition: r["tradersWithPosition"],
|
|
18319
|
+
tradersQualified: r["tradersQualified"],
|
|
18320
|
+
netNotionalUsdt: r["netNotionalUsdt"],
|
|
18321
|
+
totalNotionalUsdt: r["totalNotionalUsdt"]
|
|
18322
|
+
});
|
|
18323
|
+
async function cmdSmartmoneySignalTrendByFilter(run, opts) {
|
|
18324
|
+
const result = await run("smartmoney_get_signal_trend_by_filter", {
|
|
18325
|
+
instCcy: opts.instCcy,
|
|
18326
|
+
asOfTime: opts.asOfTime,
|
|
18327
|
+
granularity: opts.granularity,
|
|
18328
|
+
limit: opts.limit,
|
|
18329
|
+
...signalPoolFilterArgs(opts),
|
|
18330
|
+
lmtNum: opts.lmtNum
|
|
18331
|
+
});
|
|
18332
|
+
if (opts.json) {
|
|
18333
|
+
printJson(result);
|
|
18334
|
+
return;
|
|
17060
18335
|
}
|
|
17061
|
-
const
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
18336
|
+
const data = extractData(result);
|
|
18337
|
+
printDataTable(data, "No signal trend data", trendRowMapper);
|
|
18338
|
+
}
|
|
18339
|
+
async function cmdSmartmoneySignalTrendByTrader(run, opts) {
|
|
18340
|
+
const result = await run("smartmoney_get_signal_trend_by_trader", {
|
|
18341
|
+
authorIds: csvToArray(opts.authorIds),
|
|
18342
|
+
instCcy: opts.instCcy,
|
|
18343
|
+
asOfTime: opts.asOfTime,
|
|
18344
|
+
granularity: opts.granularity,
|
|
18345
|
+
limit: opts.limit,
|
|
18346
|
+
sortBy: opts.sortBy,
|
|
18347
|
+
period: opts.period
|
|
18348
|
+
});
|
|
18349
|
+
if (opts.json) {
|
|
18350
|
+
printJson(result);
|
|
18351
|
+
return;
|
|
17065
18352
|
}
|
|
18353
|
+
const data = extractData(result);
|
|
18354
|
+
printDataTable(data, "No signal trend data", trendRowMapper);
|
|
17066
18355
|
}
|
|
17067
18356
|
|
|
17068
18357
|
// src/commands/auto-earn.ts
|
|
@@ -18579,7 +19868,7 @@ async function cmdEventCancel(run, opts) {
|
|
|
18579
19868
|
// src/index.ts
|
|
18580
19869
|
var _require3 = createRequire3(import.meta.url);
|
|
18581
19870
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
18582
|
-
var GIT_HASH2 = true ? "
|
|
19871
|
+
var GIT_HASH2 = true ? "e8a0930a" : "dev";
|
|
18583
19872
|
function handlePilotCommand(action, json, force, binaryPath) {
|
|
18584
19873
|
if (action === "status") return cmdPilotStatus(json, binaryPath);
|
|
18585
19874
|
if (action === "install") return cmdPilotInstall(json, binaryPath);
|
|
@@ -18809,7 +20098,8 @@ function handleSpotAlgoCommand(run, subAction, v, json) {
|
|
|
18809
20098
|
tdMode: v.tdMode,
|
|
18810
20099
|
json
|
|
18811
20100
|
});
|
|
18812
|
-
if (subAction === "place")
|
|
20101
|
+
if (subAction === "place") {
|
|
20102
|
+
assertNoTpConflict(v.tpLevel, { tpTriggerPx: v.tpTriggerPx, tpOrdPx: v.tpOrdPx });
|
|
18813
20103
|
return cmdSpotAlgoPlace(run, {
|
|
18814
20104
|
instId: v.instId,
|
|
18815
20105
|
tdMode: v.tdMode,
|
|
@@ -18820,13 +20110,38 @@ function handleSpotAlgoCommand(run, subAction, v, json) {
|
|
|
18820
20110
|
tgtCcy: v.tgtCcy,
|
|
18821
20111
|
tpTriggerPx: v.tpTriggerPx,
|
|
18822
20112
|
tpOrdPx: v.tpOrdPx,
|
|
20113
|
+
tpOrdKind: v.tpOrdKind,
|
|
20114
|
+
tpTriggerPxType: v.tpTriggerPxType,
|
|
18823
20115
|
slTriggerPx: v.slTriggerPx,
|
|
18824
20116
|
slOrdPx: v.slOrdPx,
|
|
20117
|
+
slTriggerPxType: v.slTriggerPxType,
|
|
20118
|
+
stpMode: v.stpMode,
|
|
18825
20119
|
callbackRatio: v.callbackRatio,
|
|
18826
20120
|
callbackSpread: v.callbackSpread,
|
|
18827
20121
|
activePx: v.activePx,
|
|
20122
|
+
triggerPx: v.triggerPx,
|
|
20123
|
+
orderPx: v.orderPx,
|
|
20124
|
+
advanceOrdType: v.advanceOrdType,
|
|
20125
|
+
triggerPxType: v.triggerPxType,
|
|
20126
|
+
chaseType: v.chaseType,
|
|
20127
|
+
chaseVal: v.chaseVal,
|
|
20128
|
+
maxChaseType: v.maxChaseType,
|
|
20129
|
+
maxChaseVal: v.maxChaseVal,
|
|
20130
|
+
pxVar: v.pxVar,
|
|
20131
|
+
pxSpread: v.pxSpread,
|
|
20132
|
+
szLimit: v.szLimit,
|
|
20133
|
+
pxLimit: v.pxLimit,
|
|
20134
|
+
timeInterval: v.timeInterval,
|
|
20135
|
+
// Phase 3a+c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
20136
|
+
tpTriggerRatio: v.tpTriggerRatio,
|
|
20137
|
+
slTriggerRatio: v.slTriggerRatio,
|
|
20138
|
+
closeFraction: v.closeFraction,
|
|
20139
|
+
pxAmendType: v.pxAmendType,
|
|
20140
|
+
// Phase 3b CLI power-user flag (issue #183, CLI-only no MCP/skill exposure)
|
|
20141
|
+
tpLevels: v.tpLevel?.map(parseTpLevel),
|
|
18828
20142
|
json
|
|
18829
20143
|
});
|
|
20144
|
+
}
|
|
18830
20145
|
if (subAction === "amend")
|
|
18831
20146
|
return cmdSpotAlgoAmend(run, {
|
|
18832
20147
|
instId: v.instId,
|
|
@@ -18849,6 +20164,16 @@ function handleSpotAlgoCommand(run, subAction, v, json) {
|
|
|
18849
20164
|
});
|
|
18850
20165
|
unknownSubcommand("spot algo", subAction, ["trail", "place", "amend", "cancel", "orders"]);
|
|
18851
20166
|
}
|
|
20167
|
+
function assertNoTpConflict(tpLevel, singleFields) {
|
|
20168
|
+
if (!tpLevel || tpLevel.length === 0) return;
|
|
20169
|
+
const conflicting = ["tpTriggerPx", "tpOrdPx"].filter((k) => singleFields[k] !== void 0);
|
|
20170
|
+
if (conflicting.length > 0) {
|
|
20171
|
+
const flagNames = conflicting.map((k) => `--${k}`).join(", ");
|
|
20172
|
+
throw new Error(
|
|
20173
|
+
`Cannot use --tpLevel together with ${flagNames}. Use --tpLevel for split multi-tier take-profit, or single-TP flags for a single TP \u2014 not both.`
|
|
20174
|
+
);
|
|
20175
|
+
}
|
|
20176
|
+
}
|
|
18852
20177
|
function handleSpotCommand(run, action, rest, v, json) {
|
|
18853
20178
|
if (action === "orders")
|
|
18854
20179
|
return cmdSpotOrders(run, {
|
|
@@ -18869,7 +20194,8 @@ function handleSpotCommand(run, action, rest, v, json) {
|
|
|
18869
20194
|
newPx: v.newPx,
|
|
18870
20195
|
json
|
|
18871
20196
|
});
|
|
18872
|
-
if (action === "place")
|
|
20197
|
+
if (action === "place") {
|
|
20198
|
+
assertNoTpConflict(v.tpLevel, { tpTriggerPx: v.tpTriggerPx, tpOrdPx: v.tpOrdPx });
|
|
18873
20199
|
return cmdSpotPlace(run, {
|
|
18874
20200
|
instId: v.instId,
|
|
18875
20201
|
tdMode: v.tdMode,
|
|
@@ -18881,10 +20207,21 @@ function handleSpotCommand(run, action, rest, v, json) {
|
|
|
18881
20207
|
clOrdId: v.clOrdId,
|
|
18882
20208
|
tpTriggerPx: v.tpTriggerPx,
|
|
18883
20209
|
tpOrdPx: v.tpOrdPx,
|
|
20210
|
+
tpOrdKind: v.tpOrdKind,
|
|
20211
|
+
tpTriggerPxType: v.tpTriggerPxType,
|
|
18884
20212
|
slTriggerPx: v.slTriggerPx,
|
|
18885
20213
|
slOrdPx: v.slOrdPx,
|
|
20214
|
+
slTriggerPxType: v.slTriggerPxType,
|
|
20215
|
+
stpMode: v.stpMode,
|
|
20216
|
+
// Phase 3c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
20217
|
+
tradeQuoteCcy: v.tradeQuoteCcy,
|
|
20218
|
+
banAmend: v.banAmend,
|
|
20219
|
+
pxAmendType: v.pxAmendType,
|
|
20220
|
+
// Phase 3b CLI power-user flag (issue #183, CLI-only no MCP/skill exposure)
|
|
20221
|
+
tpLevels: v.tpLevel?.map(parseTpLevel),
|
|
18886
20222
|
json
|
|
18887
20223
|
});
|
|
20224
|
+
}
|
|
18888
20225
|
if (action === "cancel")
|
|
18889
20226
|
return cmdSpotCancel(run, { instId: v.instId ?? rest[0], ordId: v.ordId, clOrdId: v.clOrdId, json });
|
|
18890
20227
|
if (action === "algo")
|
|
@@ -18925,7 +20262,8 @@ function handleSwapAlgoCommand(run, subAction, v, json) {
|
|
|
18925
20262
|
reduceOnly: v.reduceOnly,
|
|
18926
20263
|
json
|
|
18927
20264
|
});
|
|
18928
|
-
if (subAction === "place")
|
|
20265
|
+
if (subAction === "place") {
|
|
20266
|
+
assertNoTpConflict(v.tpLevel, { tpTriggerPx: v.tpTriggerPx, tpOrdPx: v.tpOrdPx });
|
|
18929
20267
|
return cmdSwapAlgoPlace(run, {
|
|
18930
20268
|
instId: v.instId,
|
|
18931
20269
|
side: v.side,
|
|
@@ -18937,14 +20275,40 @@ function handleSwapAlgoCommand(run, subAction, v, json) {
|
|
|
18937
20275
|
tgtCcy: v.tgtCcy,
|
|
18938
20276
|
tpTriggerPx: v.tpTriggerPx,
|
|
18939
20277
|
tpOrdPx: v.tpOrdPx,
|
|
20278
|
+
tpOrdKind: v.tpOrdKind,
|
|
20279
|
+
tpTriggerPxType: v.tpTriggerPxType,
|
|
18940
20280
|
slTriggerPx: v.slTriggerPx,
|
|
18941
20281
|
slOrdPx: v.slOrdPx,
|
|
20282
|
+
slTriggerPxType: v.slTriggerPxType,
|
|
20283
|
+
stpMode: v.stpMode,
|
|
20284
|
+
cxlOnClosePos: v.cxlOnClosePos,
|
|
18942
20285
|
reduceOnly: v.reduceOnly,
|
|
18943
20286
|
callbackRatio: v.callbackRatio,
|
|
18944
20287
|
callbackSpread: v.callbackSpread,
|
|
18945
20288
|
activePx: v.activePx,
|
|
20289
|
+
triggerPx: v.triggerPx,
|
|
20290
|
+
orderPx: v.orderPx,
|
|
20291
|
+
advanceOrdType: v.advanceOrdType,
|
|
20292
|
+
triggerPxType: v.triggerPxType,
|
|
20293
|
+
chaseType: v.chaseType,
|
|
20294
|
+
chaseVal: v.chaseVal,
|
|
20295
|
+
maxChaseType: v.maxChaseType,
|
|
20296
|
+
maxChaseVal: v.maxChaseVal,
|
|
20297
|
+
pxVar: v.pxVar,
|
|
20298
|
+
pxSpread: v.pxSpread,
|
|
20299
|
+
szLimit: v.szLimit,
|
|
20300
|
+
pxLimit: v.pxLimit,
|
|
20301
|
+
timeInterval: v.timeInterval,
|
|
20302
|
+
// Phase 3a+c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
20303
|
+
tpTriggerRatio: v.tpTriggerRatio,
|
|
20304
|
+
slTriggerRatio: v.slTriggerRatio,
|
|
20305
|
+
closeFraction: v.closeFraction,
|
|
20306
|
+
pxAmendType: v.pxAmendType,
|
|
20307
|
+
// Phase 3b CLI power-user flag (issue #183, CLI-only no MCP/skill exposure)
|
|
20308
|
+
tpLevels: v.tpLevel?.map(parseTpLevel),
|
|
18946
20309
|
json
|
|
18947
20310
|
});
|
|
20311
|
+
}
|
|
18948
20312
|
if (subAction === "amend")
|
|
18949
20313
|
return cmdSwapAlgoAmend(run, {
|
|
18950
20314
|
instId: v.instId,
|
|
@@ -19000,7 +20364,8 @@ function handleSwapCommand(run, action, rest, v, json) {
|
|
|
19000
20364
|
autoCxl: v.autoCxl,
|
|
19001
20365
|
json
|
|
19002
20366
|
});
|
|
19003
|
-
if (action === "place")
|
|
20367
|
+
if (action === "place") {
|
|
20368
|
+
assertNoTpConflict(v.tpLevel, { tpTriggerPx: v.tpTriggerPx, tpOrdPx: v.tpOrdPx });
|
|
19004
20369
|
return cmdSwapPlace(run, {
|
|
19005
20370
|
instId: v.instId,
|
|
19006
20371
|
side: v.side,
|
|
@@ -19014,10 +20379,19 @@ function handleSwapCommand(run, action, rest, v, json) {
|
|
|
19014
20379
|
clOrdId: v.clOrdId,
|
|
19015
20380
|
tpTriggerPx: v.tpTriggerPx,
|
|
19016
20381
|
tpOrdPx: v.tpOrdPx,
|
|
20382
|
+
tpOrdKind: v.tpOrdKind,
|
|
20383
|
+
tpTriggerPxType: v.tpTriggerPxType,
|
|
19017
20384
|
slTriggerPx: v.slTriggerPx,
|
|
19018
20385
|
slOrdPx: v.slOrdPx,
|
|
20386
|
+
slTriggerPxType: v.slTriggerPxType,
|
|
20387
|
+
stpMode: v.stpMode,
|
|
20388
|
+
// Phase 3c CLI power-user flag (issue #182, CLI-only no MCP/skill exposure)
|
|
20389
|
+
pxAmendType: v.pxAmendType,
|
|
20390
|
+
// Phase 3b CLI power-user flag (issue #183, CLI-only no MCP/skill exposure)
|
|
20391
|
+
tpLevels: v.tpLevel?.map(parseTpLevel),
|
|
19019
20392
|
json
|
|
19020
20393
|
});
|
|
20394
|
+
}
|
|
19021
20395
|
if (action === "cancel")
|
|
19022
20396
|
return cmdSwapCancel(run, { instId: v.instId ?? rest[0], ordId: v.ordId, clOrdId: v.clOrdId, json });
|
|
19023
20397
|
if (action === "amend")
|
|
@@ -19125,8 +20499,12 @@ function handleOptionCommand(run, action, rest, v, json) {
|
|
|
19125
20499
|
clOrdId: v.clOrdId,
|
|
19126
20500
|
tpTriggerPx: v.tpTriggerPx,
|
|
19127
20501
|
tpOrdPx: v.tpOrdPx,
|
|
20502
|
+
tpOrdKind: v.tpOrdKind,
|
|
20503
|
+
tpTriggerPxType: v.tpTriggerPxType,
|
|
19128
20504
|
slTriggerPx: v.slTriggerPx,
|
|
19129
20505
|
slOrdPx: v.slOrdPx,
|
|
20506
|
+
slTriggerPxType: v.slTriggerPxType,
|
|
20507
|
+
stpMode: v.stpMode,
|
|
19130
20508
|
json
|
|
19131
20509
|
});
|
|
19132
20510
|
if (action === "cancel")
|
|
@@ -19172,7 +20550,8 @@ function handleFuturesAlgoCommand(run, subAction, v, json) {
|
|
|
19172
20550
|
reduceOnly: v.reduceOnly,
|
|
19173
20551
|
json
|
|
19174
20552
|
});
|
|
19175
|
-
if (subAction === "place")
|
|
20553
|
+
if (subAction === "place") {
|
|
20554
|
+
assertNoTpConflict(v.tpLevel, { tpTriggerPx: v.tpTriggerPx, tpOrdPx: v.tpOrdPx });
|
|
19176
20555
|
return cmdFuturesAlgoPlace(run, {
|
|
19177
20556
|
instId: v.instId,
|
|
19178
20557
|
side: v.side,
|
|
@@ -19184,14 +20563,40 @@ function handleFuturesAlgoCommand(run, subAction, v, json) {
|
|
|
19184
20563
|
tgtCcy: v.tgtCcy,
|
|
19185
20564
|
tpTriggerPx: v.tpTriggerPx,
|
|
19186
20565
|
tpOrdPx: v.tpOrdPx,
|
|
20566
|
+
tpOrdKind: v.tpOrdKind,
|
|
20567
|
+
tpTriggerPxType: v.tpTriggerPxType,
|
|
19187
20568
|
slTriggerPx: v.slTriggerPx,
|
|
19188
20569
|
slOrdPx: v.slOrdPx,
|
|
20570
|
+
slTriggerPxType: v.slTriggerPxType,
|
|
20571
|
+
stpMode: v.stpMode,
|
|
20572
|
+
cxlOnClosePos: v.cxlOnClosePos,
|
|
19189
20573
|
reduceOnly: v.reduceOnly,
|
|
19190
20574
|
callbackRatio: v.callbackRatio,
|
|
19191
20575
|
callbackSpread: v.callbackSpread,
|
|
19192
20576
|
activePx: v.activePx,
|
|
20577
|
+
triggerPx: v.triggerPx,
|
|
20578
|
+
orderPx: v.orderPx,
|
|
20579
|
+
advanceOrdType: v.advanceOrdType,
|
|
20580
|
+
triggerPxType: v.triggerPxType,
|
|
20581
|
+
chaseType: v.chaseType,
|
|
20582
|
+
chaseVal: v.chaseVal,
|
|
20583
|
+
maxChaseType: v.maxChaseType,
|
|
20584
|
+
maxChaseVal: v.maxChaseVal,
|
|
20585
|
+
pxVar: v.pxVar,
|
|
20586
|
+
pxSpread: v.pxSpread,
|
|
20587
|
+
szLimit: v.szLimit,
|
|
20588
|
+
pxLimit: v.pxLimit,
|
|
20589
|
+
timeInterval: v.timeInterval,
|
|
20590
|
+
// Phase 3a+c CLI power-user flags (issue #182, CLI-only no MCP/skill exposure)
|
|
20591
|
+
tpTriggerRatio: v.tpTriggerRatio,
|
|
20592
|
+
slTriggerRatio: v.slTriggerRatio,
|
|
20593
|
+
closeFraction: v.closeFraction,
|
|
20594
|
+
pxAmendType: v.pxAmendType,
|
|
20595
|
+
// Phase 3b CLI power-user flag (issue #183, CLI-only no MCP/skill exposure)
|
|
20596
|
+
tpLevels: v.tpLevel?.map(parseTpLevel),
|
|
19193
20597
|
json
|
|
19194
20598
|
});
|
|
20599
|
+
}
|
|
19195
20600
|
if (subAction === "amend")
|
|
19196
20601
|
return cmdFuturesAlgoAmend(run, {
|
|
19197
20602
|
instId: v.instId,
|
|
@@ -19239,7 +20644,8 @@ function handleFuturesQuery(run, action, v, json) {
|
|
|
19239
20644
|
function handleFuturesCommand(run, action, rest, v, json) {
|
|
19240
20645
|
const queryResult = handleFuturesQuery(run, action, v, json);
|
|
19241
20646
|
if (queryResult !== void 0) return queryResult;
|
|
19242
|
-
if (action === "place")
|
|
20647
|
+
if (action === "place") {
|
|
20648
|
+
assertNoTpConflict(v.tpLevel, { tpTriggerPx: v.tpTriggerPx, tpOrdPx: v.tpOrdPx });
|
|
19243
20649
|
return cmdFuturesPlace(run, {
|
|
19244
20650
|
instId: v.instId,
|
|
19245
20651
|
side: v.side,
|
|
@@ -19253,10 +20659,19 @@ function handleFuturesCommand(run, action, rest, v, json) {
|
|
|
19253
20659
|
clOrdId: v.clOrdId,
|
|
19254
20660
|
tpTriggerPx: v.tpTriggerPx,
|
|
19255
20661
|
tpOrdPx: v.tpOrdPx,
|
|
20662
|
+
tpOrdKind: v.tpOrdKind,
|
|
20663
|
+
tpTriggerPxType: v.tpTriggerPxType,
|
|
19256
20664
|
slTriggerPx: v.slTriggerPx,
|
|
19257
20665
|
slOrdPx: v.slOrdPx,
|
|
20666
|
+
slTriggerPxType: v.slTriggerPxType,
|
|
20667
|
+
stpMode: v.stpMode,
|
|
20668
|
+
// Phase 3c CLI power-user flag (issue #182, CLI-only no MCP/skill exposure)
|
|
20669
|
+
pxAmendType: v.pxAmendType,
|
|
20670
|
+
// Phase 3b CLI power-user flag (issue #183, CLI-only no MCP/skill exposure)
|
|
20671
|
+
tpLevels: v.tpLevel?.map(parseTpLevel),
|
|
19258
20672
|
json
|
|
19259
20673
|
});
|
|
20674
|
+
}
|
|
19260
20675
|
if (action === "cancel")
|
|
19261
20676
|
return cmdFuturesCancel(run, { instId: v.instId ?? rest[0], ordId: v.ordId, clOrdId: v.clOrdId, json });
|
|
19262
20677
|
if (action === "amend")
|
|
@@ -19457,79 +20872,176 @@ function handleEarnFlashEarnCommand(run, action, v, json) {
|
|
|
19457
20872
|
process.exitCode = 1;
|
|
19458
20873
|
}
|
|
19459
20874
|
function handleSmartmoneyCommand(run, action, rest, v, json) {
|
|
19460
|
-
|
|
19461
|
-
|
|
20875
|
+
void rest;
|
|
20876
|
+
const signalPoolFilters = {
|
|
20877
|
+
sortBy: v.sortBy,
|
|
19462
20878
|
period: v.period,
|
|
19463
|
-
|
|
19464
|
-
|
|
19465
|
-
|
|
19466
|
-
|
|
20879
|
+
pnlTier: v.pnlTier,
|
|
20880
|
+
winRateTier: v.winRateTier,
|
|
20881
|
+
maxDrawdownTier: v.maxDrawdownTier,
|
|
20882
|
+
aumTier: v.aumTier
|
|
19467
20883
|
};
|
|
19468
|
-
|
|
19469
|
-
|
|
19470
|
-
|
|
19471
|
-
|
|
19472
|
-
|
|
19473
|
-
|
|
19474
|
-
|
|
19475
|
-
|
|
19476
|
-
|
|
19477
|
-
|
|
20884
|
+
const leaderboardPoolFilters = {
|
|
20885
|
+
sortBy: v.sortBy,
|
|
20886
|
+
period: v.period,
|
|
20887
|
+
minPnl: v.minPnl,
|
|
20888
|
+
minWinRate: v.minWinRate,
|
|
20889
|
+
maxDrawdown: v.maxDrawdown,
|
|
20890
|
+
minAum: v.minAum
|
|
20891
|
+
};
|
|
20892
|
+
if (action === "traders-by-filter")
|
|
20893
|
+
return cmdSmartmoneyTradersByFilter(run, {
|
|
20894
|
+
updateTime: v.updateTime,
|
|
20895
|
+
...leaderboardPoolFilters,
|
|
20896
|
+
after: v.after,
|
|
20897
|
+
before: v.before,
|
|
20898
|
+
limit: v.limit,
|
|
19478
20899
|
json
|
|
19479
20900
|
});
|
|
19480
|
-
if (action === "
|
|
19481
|
-
|
|
19482
|
-
|
|
19483
|
-
|
|
19484
|
-
|
|
19485
|
-
|
|
19486
|
-
|
|
19487
|
-
lmtNum: v.lmtNum,
|
|
20901
|
+
if (action === "performance-by-trader") {
|
|
20902
|
+
if (!v.authorIds) {
|
|
20903
|
+
errorLine("Missing required --authorIds: okx smartmoney performance-by-trader --authorIds <id1,id2> [--period <3|7|30|90>]");
|
|
20904
|
+
process.exitCode = 1;
|
|
20905
|
+
return;
|
|
20906
|
+
}
|
|
20907
|
+
return cmdSmartmoneyPerformanceByTrader(run, {
|
|
19488
20908
|
authorIds: v.authorIds,
|
|
20909
|
+
sortBy: v.sortBy,
|
|
20910
|
+
period: v.period,
|
|
19489
20911
|
json
|
|
19490
20912
|
});
|
|
19491
|
-
|
|
19492
|
-
|
|
19493
|
-
|
|
20913
|
+
}
|
|
20914
|
+
if (action === "trader-positions") {
|
|
20915
|
+
if (!v.authorId) {
|
|
20916
|
+
errorLine("Missing required --authorId: okx smartmoney trader-positions --authorId <id> [--instId <id>]");
|
|
19494
20917
|
process.exitCode = 1;
|
|
19495
20918
|
return;
|
|
19496
20919
|
}
|
|
19497
|
-
return
|
|
20920
|
+
return cmdSmartmoneyTraderPositions(run, {
|
|
20921
|
+
authorId: v.authorId,
|
|
19498
20922
|
instId: v.instId,
|
|
19499
|
-
dataVersion: v.dataVersion,
|
|
19500
|
-
ts: v.ts,
|
|
19501
|
-
granularity: v.granularity,
|
|
19502
|
-
limit: v.limit,
|
|
19503
|
-
...poolFilters,
|
|
19504
20923
|
json
|
|
19505
20924
|
});
|
|
19506
20925
|
}
|
|
19507
|
-
if (action === "
|
|
19508
|
-
|
|
19509
|
-
|
|
19510
|
-
|
|
19511
|
-
|
|
20926
|
+
if (action === "trader-positions-history") {
|
|
20927
|
+
if (!v.authorId) {
|
|
20928
|
+
errorLine("Missing required --authorId: okx smartmoney trader-positions-history --authorId <id> [--instId <id>] [--limit <n>]");
|
|
20929
|
+
process.exitCode = 1;
|
|
20930
|
+
return;
|
|
20931
|
+
}
|
|
20932
|
+
return cmdSmartmoneyTraderPositionsHistory(run, {
|
|
20933
|
+
authorId: v.authorId,
|
|
20934
|
+
instId: v.instId,
|
|
19512
20935
|
after: v.after,
|
|
19513
20936
|
before: v.before,
|
|
19514
20937
|
limit: v.limit,
|
|
19515
20938
|
json
|
|
19516
20939
|
});
|
|
19517
|
-
|
|
20940
|
+
}
|
|
20941
|
+
if (action === "trader-orders-history") {
|
|
19518
20942
|
if (!v.authorId) {
|
|
19519
|
-
errorLine("Missing required --authorId: okx smartmoney trader --authorId <id>");
|
|
20943
|
+
errorLine("Missing required --authorId: okx smartmoney trader-orders-history --authorId <id> [--instId <id>] [--limit <n>]");
|
|
19520
20944
|
process.exitCode = 1;
|
|
19521
20945
|
return;
|
|
19522
20946
|
}
|
|
19523
|
-
return
|
|
20947
|
+
return cmdSmartmoneyTraderOrdersHistory(run, {
|
|
19524
20948
|
authorId: v.authorId,
|
|
20949
|
+
instId: v.instId,
|
|
20950
|
+
after: v.after,
|
|
20951
|
+
before: v.before,
|
|
20952
|
+
limit: v.limit,
|
|
20953
|
+
json
|
|
20954
|
+
});
|
|
20955
|
+
}
|
|
20956
|
+
if (action === "search-trader") {
|
|
20957
|
+
if (!v.keyword || v.keyword.trim() === "") {
|
|
20958
|
+
errorLine("Missing required --keyword: okx smartmoney search-trader --keyword <name>");
|
|
20959
|
+
process.exitCode = 1;
|
|
20960
|
+
return;
|
|
20961
|
+
}
|
|
20962
|
+
return cmdSmartmoneySearchTrader(run, {
|
|
20963
|
+
keyword: v.keyword,
|
|
20964
|
+
json
|
|
20965
|
+
});
|
|
20966
|
+
}
|
|
20967
|
+
if (action === "signal-overview-by-filter") {
|
|
20968
|
+
if (v.topInstruments && v.instCcyList) {
|
|
20969
|
+
errorLine(
|
|
20970
|
+
"--topInstruments and --instCcyList are mutually exclusive. Pass exactly one \u2014 `--topInstruments` for top-N hottest coins, or `--instCcyList` for specific coins."
|
|
20971
|
+
);
|
|
20972
|
+
process.exitCode = 1;
|
|
20973
|
+
return;
|
|
20974
|
+
}
|
|
20975
|
+
return cmdSmartmoneySignalOverviewByFilter(run, {
|
|
20976
|
+
topInstruments: v.topInstruments,
|
|
20977
|
+
instCcyList: v.instCcyList,
|
|
20978
|
+
...signalPoolFilters,
|
|
20979
|
+
lmtNum: v.lmtNum,
|
|
20980
|
+
json
|
|
20981
|
+
});
|
|
20982
|
+
}
|
|
20983
|
+
if (action === "signal-overview-by-trader") {
|
|
20984
|
+
if (!v.authorIds) {
|
|
20985
|
+
errorLine("Missing required --authorIds: okx smartmoney signal-overview-by-trader --authorIds <id1,id2> [--topInstruments <n> | --instCcyList <BTC,ETH>]");
|
|
20986
|
+
process.exitCode = 1;
|
|
20987
|
+
return;
|
|
20988
|
+
}
|
|
20989
|
+
if (v.topInstruments && v.instCcyList) {
|
|
20990
|
+
errorLine(
|
|
20991
|
+
"--topInstruments and --instCcyList are mutually exclusive. Pass exactly one \u2014 `--topInstruments` for top-N hottest coins, or `--instCcyList` for specific coins."
|
|
20992
|
+
);
|
|
20993
|
+
process.exitCode = 1;
|
|
20994
|
+
return;
|
|
20995
|
+
}
|
|
20996
|
+
return cmdSmartmoneySignalOverviewByTrader(run, {
|
|
20997
|
+
authorIds: v.authorIds,
|
|
20998
|
+
topInstruments: v.topInstruments,
|
|
20999
|
+
instCcyList: v.instCcyList,
|
|
21000
|
+
sortBy: v.sortBy,
|
|
19525
21001
|
period: v.period,
|
|
21002
|
+
json
|
|
21003
|
+
});
|
|
21004
|
+
}
|
|
21005
|
+
if (action === "signal-trend-by-filter") {
|
|
21006
|
+
if (!v.instCcy) {
|
|
21007
|
+
errorLine("Missing required --instCcy: okx smartmoney signal-trend-by-filter --instCcy <ccy> [--asOfTime <yyyyMMddHH>] [--granularity <1h|1d>] [--limit <n>]");
|
|
21008
|
+
process.exitCode = 1;
|
|
21009
|
+
return;
|
|
21010
|
+
}
|
|
21011
|
+
return cmdSmartmoneySignalTrendByFilter(run, {
|
|
21012
|
+
instCcy: v.instCcy,
|
|
21013
|
+
asOfTime: v.asOfTime,
|
|
21014
|
+
granularity: v.granularity,
|
|
21015
|
+
limit: v.limit,
|
|
21016
|
+
...signalPoolFilters,
|
|
21017
|
+
lmtNum: v.lmtNum,
|
|
21018
|
+
json
|
|
21019
|
+
});
|
|
21020
|
+
}
|
|
21021
|
+
if (action === "signal-trend-by-trader") {
|
|
21022
|
+
if (!v.authorIds) {
|
|
21023
|
+
errorLine("Missing required --authorIds: okx smartmoney signal-trend-by-trader --authorIds <id1,id2> --instCcy <ccy> [--asOfTime <yyyyMMddHH>]");
|
|
21024
|
+
process.exitCode = 1;
|
|
21025
|
+
return;
|
|
21026
|
+
}
|
|
21027
|
+
if (!v.instCcy) {
|
|
21028
|
+
errorLine("Missing required --instCcy: okx smartmoney signal-trend-by-trader --authorIds <id1,id2> --instCcy <ccy> [--asOfTime <yyyyMMddHH>]");
|
|
21029
|
+
process.exitCode = 1;
|
|
21030
|
+
return;
|
|
21031
|
+
}
|
|
21032
|
+
return cmdSmartmoneySignalTrendByTrader(run, {
|
|
21033
|
+
authorIds: v.authorIds,
|
|
19526
21034
|
instCcy: v.instCcy,
|
|
19527
|
-
|
|
21035
|
+
asOfTime: v.asOfTime,
|
|
21036
|
+
granularity: v.granularity,
|
|
21037
|
+
limit: v.limit,
|
|
21038
|
+
sortBy: v.sortBy,
|
|
21039
|
+
period: v.period,
|
|
19528
21040
|
json
|
|
19529
21041
|
});
|
|
19530
21042
|
}
|
|
19531
21043
|
errorLine(`Unknown smartmoney command: ${action}`);
|
|
19532
|
-
errorLine("Valid:
|
|
21044
|
+
errorLine("Valid: traders-by-filter, performance-by-trader, trader-positions, trader-positions-history, trader-orders-history, search-trader, signal-overview-by-filter, signal-overview-by-trader, signal-trend-by-filter, signal-trend-by-trader");
|
|
19533
21045
|
process.exitCode = 1;
|
|
19534
21046
|
}
|
|
19535
21047
|
function handleEarnSavingsCommand(run, action, rest, v, json) {
|
|
@@ -19854,12 +21366,14 @@ async function main() {
|
|
|
19854
21366
|
main().catch((error) => {
|
|
19855
21367
|
const payload = toToolErrorPayload(error);
|
|
19856
21368
|
errorLine(`Error: ${payload.message}`);
|
|
21369
|
+
if (payload.code) errorLine(`Code: ${payload.code}`);
|
|
19857
21370
|
if (payload.traceId) errorLine(`TraceId: ${payload.traceId}`);
|
|
19858
21371
|
if (payload.suggestion) errorLine(`Hint: ${payload.suggestion}`);
|
|
19859
21372
|
errorLine(`Version: @okx_ai/okx-trade-cli@${CLI_VERSION2}`);
|
|
19860
21373
|
process.exitCode = 1;
|
|
19861
21374
|
});
|
|
19862
21375
|
export {
|
|
21376
|
+
assertNoTpConflict,
|
|
19863
21377
|
handleAccountWriteCommand,
|
|
19864
21378
|
handleBotCommand,
|
|
19865
21379
|
handleBotDcaCommand,
|