@okx_ai/okx-trade-cli 1.2.7-beta.1 → 1.2.7-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 +323 -130
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3131,32 +3131,44 @@ function registerDcaTools() {
|
|
|
3131
3131
|
{
|
|
3132
3132
|
name: "dca_create_order",
|
|
3133
3133
|
module: "bot.dca",
|
|
3134
|
-
description: "Create
|
|
3134
|
+
description: "Create a DCA (Martingale) bot. [CAUTION] Real trades. contract_dca requires lever; spot_dca must be long. If maxSafetyOrds>0: need safetyOrdAmt, pxSteps.",
|
|
3135
3135
|
isWrite: true,
|
|
3136
3136
|
inputSchema: {
|
|
3137
3137
|
type: "object",
|
|
3138
3138
|
properties: {
|
|
3139
|
-
instId: { type: "string", description: "
|
|
3140
|
-
|
|
3139
|
+
instId: { type: "string", description: "BTC-USDT (spot) or BTC-USDT-SWAP (contract)" },
|
|
3140
|
+
algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"] },
|
|
3141
|
+
lever: { type: "string", description: "Required for contract_dca" },
|
|
3141
3142
|
direction: { type: "string", enum: ["long", "short"] },
|
|
3142
|
-
initOrdAmt: { type: "string", description: "Initial
|
|
3143
|
-
maxSafetyOrds: { type: "string", description: "
|
|
3144
|
-
tpPct: { type: "string", description: "Take-profit ratio,
|
|
3145
|
-
safetyOrdAmt: { type: "string", description: "Safety order amount
|
|
3146
|
-
pxSteps: { type: "string", description: "Price drop
|
|
3147
|
-
pxStepsMult: { type: "string", description: "
|
|
3148
|
-
volMult: { type: "string", description: "
|
|
3149
|
-
slPct: { type: "string", description: "Stop-loss ratio,
|
|
3150
|
-
slMode: { type: "string", enum: ["limit", "market"]
|
|
3151
|
-
allowReinvest: { type: "
|
|
3152
|
-
triggerStrategy: { type: "string", enum: ["instant", "price"
|
|
3153
|
-
triggerPx: { type: "string", description: "
|
|
3143
|
+
initOrdAmt: { type: "string", description: "Initial amount in quote ccy" },
|
|
3144
|
+
maxSafetyOrds: { type: "string", description: "0=no DCA, max 100" },
|
|
3145
|
+
tpPct: { type: "string", description: "Take-profit ratio, 0.03=3%" },
|
|
3146
|
+
safetyOrdAmt: { type: "string", description: "Safety order amount. Need if maxSafetyOrds>0" },
|
|
3147
|
+
pxSteps: { type: "string", description: "Price drop per safety order. Need if maxSafetyOrds>0" },
|
|
3148
|
+
pxStepsMult: { type: "string", description: "Step multiplier. Required when maxSafetyOrds>0, e.g. '1'" },
|
|
3149
|
+
volMult: { type: "string", description: "Size multiplier. Required when maxSafetyOrds>0, e.g. '1'" },
|
|
3150
|
+
slPct: { type: "string", description: "Stop-loss ratio, 0.05=5%" },
|
|
3151
|
+
slMode: { type: "string", enum: ["limit", "market"] },
|
|
3152
|
+
allowReinvest: { type: "boolean", description: "Default true" },
|
|
3153
|
+
triggerStrategy: { type: "string", enum: ["instant", "price"] },
|
|
3154
|
+
triggerPx: { type: "string", description: "Need if triggerStrategy=price" },
|
|
3155
|
+
algoClOrdId: { type: "string", description: "Client order ID, 1-32 chars" },
|
|
3156
|
+
// Backend expects boolean, but kept as string for backward compatibility with older clients.
|
|
3157
|
+
reserveFunds: { type: "string", description: "'true' or 'false', default 'true'" },
|
|
3158
|
+
tradeQuoteCcy: { type: "string" }
|
|
3154
3159
|
},
|
|
3155
|
-
required: ["instId", "
|
|
3160
|
+
required: ["instId", "algoOrdType", "direction", "initOrdAmt", "maxSafetyOrds", "tpPct"]
|
|
3156
3161
|
},
|
|
3157
3162
|
handler: async (rawArgs, context) => {
|
|
3158
3163
|
const args = asRecord(rawArgs);
|
|
3159
3164
|
const instId = requireString(args, "instId");
|
|
3165
|
+
const algoOrdType = requireString(args, "algoOrdType");
|
|
3166
|
+
if (algoOrdType === "contract_dca" && !readString(args, "lever")) {
|
|
3167
|
+
throw new OkxApiError("lever is required for contract_dca", {
|
|
3168
|
+
code: "VALIDATION",
|
|
3169
|
+
endpoint: `${BASE}/create`
|
|
3170
|
+
});
|
|
3171
|
+
}
|
|
3160
3172
|
const triggerStrategy = readString(args, "triggerStrategy") ?? "instant";
|
|
3161
3173
|
const triggerParam = {
|
|
3162
3174
|
triggerAction: "start",
|
|
@@ -3165,24 +3177,55 @@ function registerDcaTools() {
|
|
|
3165
3177
|
if (triggerStrategy === "price") {
|
|
3166
3178
|
triggerParam["triggerPx"] = requireString(args, "triggerPx");
|
|
3167
3179
|
}
|
|
3180
|
+
const maxSafetyOrds = requireString(args, "maxSafetyOrds");
|
|
3181
|
+
if (Number(maxSafetyOrds) > 0) {
|
|
3182
|
+
if (!readString(args, "safetyOrdAmt")) {
|
|
3183
|
+
throw new OkxApiError("safetyOrdAmt is required when maxSafetyOrds > 0", {
|
|
3184
|
+
code: "VALIDATION",
|
|
3185
|
+
endpoint: `${BASE}/create`
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
if (!readString(args, "pxSteps")) {
|
|
3189
|
+
throw new OkxApiError("pxSteps is required when maxSafetyOrds > 0", {
|
|
3190
|
+
code: "VALIDATION",
|
|
3191
|
+
endpoint: `${BASE}/create`
|
|
3192
|
+
});
|
|
3193
|
+
}
|
|
3194
|
+
if (!readString(args, "pxStepsMult")) {
|
|
3195
|
+
throw new OkxApiError("pxStepsMult is required when maxSafetyOrds > 0", {
|
|
3196
|
+
code: "VALIDATION",
|
|
3197
|
+
endpoint: `${BASE}/create`
|
|
3198
|
+
});
|
|
3199
|
+
}
|
|
3200
|
+
if (!readString(args, "volMult")) {
|
|
3201
|
+
throw new OkxApiError("volMult is required when maxSafetyOrds > 0", {
|
|
3202
|
+
code: "VALIDATION",
|
|
3203
|
+
endpoint: `${BASE}/create`
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3168
3207
|
const response = await context.client.privatePost(
|
|
3169
3208
|
`${BASE}/create`,
|
|
3170
3209
|
compactObject({
|
|
3171
3210
|
instId,
|
|
3172
|
-
algoOrdType
|
|
3173
|
-
lever:
|
|
3211
|
+
algoOrdType,
|
|
3212
|
+
lever: readString(args, "lever"),
|
|
3174
3213
|
direction: requireString(args, "direction"),
|
|
3175
3214
|
initOrdAmt: requireString(args, "initOrdAmt"),
|
|
3176
3215
|
safetyOrdAmt: readString(args, "safetyOrdAmt"),
|
|
3177
|
-
maxSafetyOrds
|
|
3216
|
+
maxSafetyOrds,
|
|
3178
3217
|
pxSteps: readString(args, "pxSteps"),
|
|
3179
3218
|
pxStepsMult: readString(args, "pxStepsMult"),
|
|
3180
3219
|
volMult: readString(args, "volMult"),
|
|
3181
3220
|
tpPct: requireString(args, "tpPct"),
|
|
3182
3221
|
slPct: readString(args, "slPct"),
|
|
3183
3222
|
slMode: readString(args, "slMode"),
|
|
3184
|
-
allowReinvest:
|
|
3185
|
-
triggerParams: [triggerParam]
|
|
3223
|
+
allowReinvest: args["allowReinvest"] !== void 0 ? args["allowReinvest"] === true || args["allowReinvest"] === "true" : void 0,
|
|
3224
|
+
triggerParams: [triggerParam],
|
|
3225
|
+
tag: context.config.sourceTag,
|
|
3226
|
+
algoClOrdId: readString(args, "algoClOrdId"),
|
|
3227
|
+
reserveFunds: readString(args, "reserveFunds"),
|
|
3228
|
+
tradeQuoteCcy: readString(args, "tradeQuoteCcy")
|
|
3186
3229
|
}),
|
|
3187
3230
|
privateRateLimit("dca_create_order", 20)
|
|
3188
3231
|
);
|
|
@@ -3192,21 +3235,31 @@ function registerDcaTools() {
|
|
|
3192
3235
|
{
|
|
3193
3236
|
name: "dca_stop_order",
|
|
3194
3237
|
module: "bot.dca",
|
|
3195
|
-
description: "Stop a running
|
|
3238
|
+
description: "Stop a running DCA bot. [CAUTION] spot_dca needs stopType: 1=sell, 2=keep.",
|
|
3196
3239
|
isWrite: true,
|
|
3197
3240
|
inputSchema: {
|
|
3198
3241
|
type: "object",
|
|
3199
3242
|
properties: {
|
|
3200
|
-
algoId: { type: "string", description: "
|
|
3243
|
+
algoId: { type: "string", description: "Algo order ID" },
|
|
3244
|
+
algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"] },
|
|
3245
|
+
stopType: { type: "string", enum: ["1", "2"], description: "Required for spot_dca: 1=sell all, 2=keep tokens" }
|
|
3201
3246
|
},
|
|
3202
|
-
required: ["algoId"]
|
|
3247
|
+
required: ["algoId", "algoOrdType"]
|
|
3203
3248
|
},
|
|
3204
3249
|
handler: async (rawArgs, context) => {
|
|
3205
3250
|
const args = asRecord(rawArgs);
|
|
3206
3251
|
const algoId = requireString(args, "algoId");
|
|
3252
|
+
const algoOrdType = requireString(args, "algoOrdType");
|
|
3253
|
+
const stopType = readString(args, "stopType");
|
|
3254
|
+
if (algoOrdType === "spot_dca" && !stopType) {
|
|
3255
|
+
throw new OkxApiError(
|
|
3256
|
+
"stopType is required for spot_dca. Use '1' (sell all tokens) or '2' (keep tokens)",
|
|
3257
|
+
{ code: "VALIDATION", endpoint: `${BASE}/stop` }
|
|
3258
|
+
);
|
|
3259
|
+
}
|
|
3207
3260
|
const response = await context.client.privatePost(
|
|
3208
3261
|
`${BASE}/stop`,
|
|
3209
|
-
{ algoId, algoOrdType
|
|
3262
|
+
compactObject({ algoId, algoOrdType, stopType }),
|
|
3210
3263
|
privateRateLimit("dca_stop_order", 20)
|
|
3211
3264
|
);
|
|
3212
3265
|
return normalizeWrite2(response);
|
|
@@ -3215,21 +3268,18 @@ function registerDcaTools() {
|
|
|
3215
3268
|
{
|
|
3216
3269
|
name: "dca_get_orders",
|
|
3217
3270
|
module: "bot.dca",
|
|
3218
|
-
description: "List DCA bots.
|
|
3271
|
+
description: "List DCA bots. Default: active (running). Use status=history for stopped.",
|
|
3219
3272
|
isWrite: false,
|
|
3220
3273
|
inputSchema: {
|
|
3221
3274
|
type: "object",
|
|
3222
3275
|
properties: {
|
|
3223
|
-
status: {
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
},
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
after: { type: "string", description: "Cursor for older records" },
|
|
3231
|
-
before: { type: "string", description: "Cursor for newer records" },
|
|
3232
|
-
limit: { type: "number", description: "Default 100" }
|
|
3276
|
+
status: { type: "string", enum: ["active", "history"] },
|
|
3277
|
+
algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"], description: "Default: contract_dca" },
|
|
3278
|
+
algoId: { type: "string", description: "Algo order ID" },
|
|
3279
|
+
instId: { type: "string" },
|
|
3280
|
+
after: { type: "string", description: "Pagination cursor" },
|
|
3281
|
+
before: { type: "string", description: "Pagination cursor" },
|
|
3282
|
+
limit: { type: "number" }
|
|
3233
3283
|
},
|
|
3234
3284
|
required: []
|
|
3235
3285
|
},
|
|
@@ -3237,10 +3287,11 @@ function registerDcaTools() {
|
|
|
3237
3287
|
const args = asRecord(rawArgs);
|
|
3238
3288
|
const status = readString(args, "status") ?? "active";
|
|
3239
3289
|
const path42 = status === "history" ? `${BASE}/history-list` : `${BASE}/ongoing-list`;
|
|
3290
|
+
const algoOrdType = readString(args, "algoOrdType") ?? "contract_dca";
|
|
3240
3291
|
const response = await context.client.privateGet(
|
|
3241
3292
|
path42,
|
|
3242
3293
|
compactObject({
|
|
3243
|
-
algoOrdType
|
|
3294
|
+
algoOrdType,
|
|
3244
3295
|
algoId: readString(args, "algoId"),
|
|
3245
3296
|
instId: readString(args, "instId"),
|
|
3246
3297
|
after: readString(args, "after"),
|
|
@@ -3255,21 +3306,23 @@ function registerDcaTools() {
|
|
|
3255
3306
|
{
|
|
3256
3307
|
name: "dca_get_order_details",
|
|
3257
3308
|
module: "bot.dca",
|
|
3258
|
-
description: "Get DCA bot
|
|
3309
|
+
description: "Get DCA bot position details (avgPx, upl, liqPx, etc).",
|
|
3259
3310
|
isWrite: false,
|
|
3260
3311
|
inputSchema: {
|
|
3261
3312
|
type: "object",
|
|
3262
3313
|
properties: {
|
|
3263
|
-
algoId: { type: "string", description: "
|
|
3314
|
+
algoId: { type: "string", description: "Algo order ID" },
|
|
3315
|
+
algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"] }
|
|
3264
3316
|
},
|
|
3265
|
-
required: ["algoId"]
|
|
3317
|
+
required: ["algoId", "algoOrdType"]
|
|
3266
3318
|
},
|
|
3267
3319
|
handler: async (rawArgs, context) => {
|
|
3268
3320
|
const args = asRecord(rawArgs);
|
|
3269
3321
|
const algoId = requireString(args, "algoId");
|
|
3322
|
+
const algoOrdType = requireString(args, "algoOrdType");
|
|
3270
3323
|
const response = await context.client.privateGet(
|
|
3271
3324
|
`${BASE}/position-details`,
|
|
3272
|
-
{ algoId, algoOrdType
|
|
3325
|
+
{ algoId, algoOrdType },
|
|
3273
3326
|
privateRateLimit("dca_get_order_details", 20)
|
|
3274
3327
|
);
|
|
3275
3328
|
return normalizeResponse(response);
|
|
@@ -3278,29 +3331,31 @@ function registerDcaTools() {
|
|
|
3278
3331
|
{
|
|
3279
3332
|
name: "dca_get_sub_orders",
|
|
3280
3333
|
module: "bot.dca",
|
|
3281
|
-
description: "
|
|
3334
|
+
description: "Get DCA cycles or orders in a cycle. Omit cycleId=cycle list; with cycleId=orders.",
|
|
3282
3335
|
isWrite: false,
|
|
3283
3336
|
inputSchema: {
|
|
3284
3337
|
type: "object",
|
|
3285
3338
|
properties: {
|
|
3286
|
-
algoId: { type: "string", description: "
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3339
|
+
algoId: { type: "string", description: "Algo order ID" },
|
|
3340
|
+
algoOrdType: { type: "string", enum: ["spot_dca", "contract_dca"] },
|
|
3341
|
+
cycleId: { type: "string", description: "Omit for cycles; provide for orders" },
|
|
3342
|
+
after: { type: "string", description: "Pagination cursor" },
|
|
3343
|
+
before: { type: "string", description: "Pagination cursor" },
|
|
3344
|
+
limit: { type: "number" }
|
|
3291
3345
|
},
|
|
3292
|
-
required: ["algoId"]
|
|
3346
|
+
required: ["algoId", "algoOrdType"]
|
|
3293
3347
|
},
|
|
3294
3348
|
handler: async (rawArgs, context) => {
|
|
3295
3349
|
const args = asRecord(rawArgs);
|
|
3296
3350
|
const algoId = requireString(args, "algoId");
|
|
3351
|
+
const algoOrdType = requireString(args, "algoOrdType");
|
|
3297
3352
|
const cycleId = readString(args, "cycleId");
|
|
3298
3353
|
if (cycleId) {
|
|
3299
3354
|
const response2 = await context.client.privateGet(
|
|
3300
3355
|
`${BASE}/orders`,
|
|
3301
3356
|
compactObject({
|
|
3302
3357
|
algoId,
|
|
3303
|
-
algoOrdType
|
|
3358
|
+
algoOrdType,
|
|
3304
3359
|
cycleId,
|
|
3305
3360
|
limit: readNumber(args, "limit")
|
|
3306
3361
|
}),
|
|
@@ -3312,7 +3367,7 @@ function registerDcaTools() {
|
|
|
3312
3367
|
`${BASE}/cycle-list`,
|
|
3313
3368
|
compactObject({
|
|
3314
3369
|
algoId,
|
|
3315
|
-
algoOrdType
|
|
3370
|
+
algoOrdType,
|
|
3316
3371
|
after: readString(args, "after"),
|
|
3317
3372
|
before: readString(args, "before"),
|
|
3318
3373
|
limit: readNumber(args, "limit")
|
|
@@ -7196,6 +7251,12 @@ function fail(label, detail, hints) {
|
|
|
7196
7251
|
outputLine(` \u2192 ${hint}`);
|
|
7197
7252
|
}
|
|
7198
7253
|
}
|
|
7254
|
+
function warn(label, detail, hints = []) {
|
|
7255
|
+
outputLine(` \u26A0 ${label.padEnd(14)} ${detail}`);
|
|
7256
|
+
for (const hint of hints) {
|
|
7257
|
+
outputLine(` \u2192 ${hint}`);
|
|
7258
|
+
}
|
|
7259
|
+
}
|
|
7199
7260
|
function section(title) {
|
|
7200
7261
|
outputLine("");
|
|
7201
7262
|
outputLine(` ${title}`);
|
|
@@ -7306,59 +7367,154 @@ function checkMcpEntryPoint(report) {
|
|
|
7306
7367
|
return { entryPath: null, passed: false };
|
|
7307
7368
|
}
|
|
7308
7369
|
}
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
return true;
|
|
7316
|
-
}
|
|
7317
|
-
if (!fs4.existsSync(configPath)) {
|
|
7318
|
-
fail("config file", `not found: ${configPath}`, [
|
|
7319
|
-
"Claude Desktop may not be installed",
|
|
7320
|
-
"Run: okx setup --client claude-desktop to configure"
|
|
7321
|
-
]);
|
|
7322
|
-
report.add("claude_cfg", `MISSING ${sanitize(configPath)}`);
|
|
7323
|
-
return false;
|
|
7324
|
-
}
|
|
7325
|
-
ok("config file", configPath);
|
|
7326
|
-
report.add("claude_cfg", sanitize(configPath));
|
|
7370
|
+
var MCP_SERVER_NAME = "okx-trade-mcp";
|
|
7371
|
+
var CLIENT_LIMITS = {
|
|
7372
|
+
cursor: { perServer: 40, total: 80 }
|
|
7373
|
+
};
|
|
7374
|
+
function checkJsonMcpConfig(configPath) {
|
|
7375
|
+
if (!fs4.existsSync(configPath)) return "missing";
|
|
7327
7376
|
try {
|
|
7328
7377
|
const raw = fs4.readFileSync(configPath, "utf8");
|
|
7329
7378
|
const parsed = JSON.parse(raw);
|
|
7330
7379
|
const mcpServers = parsed["mcpServers"];
|
|
7331
|
-
if (!mcpServers)
|
|
7332
|
-
fail("mcp entry", "no mcpServers section found", [
|
|
7333
|
-
"Run: okx setup --client claude-desktop"
|
|
7334
|
-
]);
|
|
7335
|
-
report.add("claude_mcp", "NO_SECTION");
|
|
7336
|
-
return false;
|
|
7337
|
-
}
|
|
7380
|
+
if (!mcpServers) return "not-configured";
|
|
7338
7381
|
const entries = Object.entries(mcpServers);
|
|
7339
|
-
const
|
|
7382
|
+
const found = entries.find(([name, v]) => {
|
|
7383
|
+
if (name.includes(MCP_SERVER_NAME)) return true;
|
|
7340
7384
|
const val = v;
|
|
7341
7385
|
const cmd = String(val["command"] ?? "");
|
|
7342
7386
|
const args = val["args"] ?? [];
|
|
7343
|
-
return cmd.includes(
|
|
7387
|
+
return cmd.includes(MCP_SERVER_NAME) || args.some((a) => a.includes(MCP_SERVER_NAME));
|
|
7344
7388
|
});
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7389
|
+
return found ? "found" : "not-configured";
|
|
7390
|
+
} catch (_e) {
|
|
7391
|
+
return "parse-error";
|
|
7392
|
+
}
|
|
7393
|
+
}
|
|
7394
|
+
function checkClaudeCodeConfig() {
|
|
7395
|
+
const home = os2.homedir();
|
|
7396
|
+
const candidates = [
|
|
7397
|
+
path2.join(home, ".claude", "settings.json"),
|
|
7398
|
+
path2.join(home, ".claude.json")
|
|
7399
|
+
];
|
|
7400
|
+
let anyFound = false;
|
|
7401
|
+
let anyParseError = false;
|
|
7402
|
+
for (const cfgPath of candidates) {
|
|
7403
|
+
if (!fs4.existsSync(cfgPath)) continue;
|
|
7404
|
+
anyFound = true;
|
|
7405
|
+
const result = checkJsonMcpConfig(cfgPath);
|
|
7406
|
+
if (result === "found") return "found";
|
|
7407
|
+
if (result === "parse-error") anyParseError = true;
|
|
7408
|
+
}
|
|
7409
|
+
if (!anyFound) return "missing";
|
|
7410
|
+
if (anyParseError) return "parse-error";
|
|
7411
|
+
return "not-configured";
|
|
7412
|
+
}
|
|
7413
|
+
function checkMcpClients(report) {
|
|
7414
|
+
section("MCP Client Config");
|
|
7415
|
+
const jsonClients = ["claude-desktop", "cursor", "windsurf"];
|
|
7416
|
+
const configuredClients = [];
|
|
7417
|
+
let anyFailed = false;
|
|
7418
|
+
for (const clientId of jsonClients) {
|
|
7419
|
+
const configPath = getConfigPath(clientId);
|
|
7420
|
+
if (!configPath) continue;
|
|
7421
|
+
const name = CLIENT_NAMES[clientId];
|
|
7422
|
+
const status = checkJsonMcpConfig(configPath);
|
|
7423
|
+
if (status === "missing") {
|
|
7424
|
+
continue;
|
|
7425
|
+
}
|
|
7426
|
+
if (status === "found") {
|
|
7427
|
+
ok(name, `configured (${sanitize(configPath)})`);
|
|
7428
|
+
report.add(`client_${clientId}`, `OK ${sanitize(configPath)}`);
|
|
7429
|
+
configuredClients.push(clientId);
|
|
7430
|
+
} else if (status === "not-configured") {
|
|
7431
|
+
fail(name, "okx-trade-mcp not found in mcpServers", [
|
|
7432
|
+
`Run: okx setup --client ${clientId}`
|
|
7433
|
+
]);
|
|
7434
|
+
report.add(`client_${clientId}`, "NOT_CONFIGURED");
|
|
7435
|
+
anyFailed = true;
|
|
7349
7436
|
} else {
|
|
7350
|
-
fail(
|
|
7351
|
-
|
|
7437
|
+
fail(name, `JSON parse error in ${sanitize(configPath)}`, [
|
|
7438
|
+
`Check ${sanitize(configPath)} for JSON syntax errors`,
|
|
7439
|
+
`Then run: okx setup --client ${clientId}`
|
|
7352
7440
|
]);
|
|
7353
|
-
report.add(
|
|
7354
|
-
|
|
7441
|
+
report.add(`client_${clientId}`, "PARSE_ERROR");
|
|
7442
|
+
anyFailed = true;
|
|
7443
|
+
}
|
|
7444
|
+
}
|
|
7445
|
+
const claudeCodeStatus = checkClaudeCodeConfig();
|
|
7446
|
+
if (claudeCodeStatus !== "missing") {
|
|
7447
|
+
const name = CLIENT_NAMES["claude-code"];
|
|
7448
|
+
if (claudeCodeStatus === "found") {
|
|
7449
|
+
ok(name, "configured");
|
|
7450
|
+
report.add("client_claude-code", "OK");
|
|
7451
|
+
configuredClients.push("claude-code");
|
|
7452
|
+
} else if (claudeCodeStatus === "not-configured") {
|
|
7453
|
+
warn(name, "installed but okx-trade-mcp not configured", [
|
|
7454
|
+
"Run: okx setup --client claude-code"
|
|
7455
|
+
]);
|
|
7456
|
+
report.add("client_claude-code", "NOT_CONFIGURED");
|
|
7457
|
+
} else {
|
|
7458
|
+
fail(name, "settings file has JSON parse error", [
|
|
7459
|
+
"Run: okx setup --client claude-code"
|
|
7460
|
+
]);
|
|
7461
|
+
report.add("client_claude-code", "PARSE_ERROR");
|
|
7462
|
+
anyFailed = true;
|
|
7355
7463
|
}
|
|
7356
|
-
}
|
|
7357
|
-
|
|
7358
|
-
|
|
7464
|
+
}
|
|
7465
|
+
if (configuredClients.length === 0 && !anyFailed) {
|
|
7466
|
+
fail("no client", "no MCP client configuration found", [
|
|
7467
|
+
"Run: okx setup --client <client>",
|
|
7468
|
+
"Supported clients: claude-desktop, cursor, windsurf, claude-code"
|
|
7359
7469
|
]);
|
|
7360
|
-
report.add("
|
|
7361
|
-
return false;
|
|
7470
|
+
report.add("client_cfg", "NONE_FOUND");
|
|
7471
|
+
return { passed: false, configuredClients };
|
|
7472
|
+
}
|
|
7473
|
+
const passed = configuredClients.length > 0 && !anyFailed;
|
|
7474
|
+
report.add("client_cfg", passed ? `OK (${configuredClients.join(",")})` : "FAIL");
|
|
7475
|
+
return { passed, configuredClients };
|
|
7476
|
+
}
|
|
7477
|
+
function checkToolCount(report, configuredClients, getSpecs = allToolSpecs) {
|
|
7478
|
+
section("Tool Count");
|
|
7479
|
+
const specs = getSpecs();
|
|
7480
|
+
const totalCount = specs.length;
|
|
7481
|
+
const defaultModuleSet = new Set(DEFAULT_MODULES);
|
|
7482
|
+
const defaultCount = specs.filter((s) => defaultModuleSet.has(s.module)).length;
|
|
7483
|
+
const defaultModulesArg = DEFAULT_MODULES.join(",");
|
|
7484
|
+
const applicableLimits = configuredClients.map((id) => ({ id, limits: CLIENT_LIMITS[id] })).filter((x) => x.limits !== void 0);
|
|
7485
|
+
if (applicableLimits.length === 0) {
|
|
7486
|
+
ok("total tools", `${totalCount} tools loaded`);
|
|
7487
|
+
report.add("tool_count", `${totalCount}`);
|
|
7488
|
+
return;
|
|
7489
|
+
}
|
|
7490
|
+
let anyExceeded = false;
|
|
7491
|
+
for (const { id, limits } of applicableLimits) {
|
|
7492
|
+
const name = CLIENT_NAMES[id];
|
|
7493
|
+
if (totalCount > limits.total) {
|
|
7494
|
+
warn(
|
|
7495
|
+
"tool count",
|
|
7496
|
+
`${totalCount} tools loaded \u2014 exceeds ${name} limit (${limits.total} total / ${limits.perServer} per server)`,
|
|
7497
|
+
[
|
|
7498
|
+
`Use --modules to reduce: okx-trade-mcp --modules ${defaultModulesArg} (${defaultCount} tools)`
|
|
7499
|
+
]
|
|
7500
|
+
);
|
|
7501
|
+
report.add("tool_count", `${totalCount} EXCEEDS_${id.toUpperCase()}_LIMIT`);
|
|
7502
|
+
anyExceeded = true;
|
|
7503
|
+
} else if (totalCount > limits.perServer) {
|
|
7504
|
+
warn(
|
|
7505
|
+
"tool count",
|
|
7506
|
+
`${totalCount} tools loaded \u2014 exceeds ${name} per-server limit (${limits.perServer})`,
|
|
7507
|
+
[
|
|
7508
|
+
`Use --modules to reduce: okx-trade-mcp --modules ${defaultModulesArg} (${defaultCount} tools)`
|
|
7509
|
+
]
|
|
7510
|
+
);
|
|
7511
|
+
report.add("tool_count", `${totalCount} EXCEEDS_${id.toUpperCase()}_PER_SERVER_LIMIT`);
|
|
7512
|
+
anyExceeded = true;
|
|
7513
|
+
}
|
|
7514
|
+
}
|
|
7515
|
+
if (!anyExceeded) {
|
|
7516
|
+
ok("total tools", `${totalCount} tools loaded (within limits for all configured clients)`);
|
|
7517
|
+
report.add("tool_count", `${totalCount} OK`);
|
|
7362
7518
|
}
|
|
7363
7519
|
}
|
|
7364
7520
|
function readLogTail(logPath) {
|
|
@@ -7551,9 +7707,10 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
7551
7707
|
checkMcpPackageVersion(report);
|
|
7552
7708
|
const nodePassed = checkNodeCompat(report);
|
|
7553
7709
|
const { entryPath, passed: entryPassed } = checkMcpEntryPoint(report);
|
|
7554
|
-
const cfgPassed =
|
|
7710
|
+
const { passed: cfgPassed, configuredClients } = checkMcpClients(report);
|
|
7555
7711
|
checkMcpLogs(report);
|
|
7556
7712
|
const moduleLoadPassed = checkModuleLoading(entryPath, report);
|
|
7713
|
+
checkToolCount(report, configuredClients);
|
|
7557
7714
|
let handshakePassed = false;
|
|
7558
7715
|
if (entryPath && entryPassed && moduleLoadPassed) {
|
|
7559
7716
|
handshakePassed = await checkStdioHandshake(entryPath, report);
|
|
@@ -7578,7 +7735,7 @@ async function cmdDiagnoseMcp(options = {}) {
|
|
|
7578
7735
|
|
|
7579
7736
|
// src/commands/diagnose.ts
|
|
7580
7737
|
var CLI_VERSION = readCliVersion();
|
|
7581
|
-
var GIT_HASH = true ? "
|
|
7738
|
+
var GIT_HASH = true ? "c270a0b" : "dev";
|
|
7582
7739
|
function maskKey2(key) {
|
|
7583
7740
|
if (!key) return "(not set)";
|
|
7584
7741
|
if (key.length <= 8) return "****";
|
|
@@ -8421,27 +8578,27 @@ var HELP_TREE = {
|
|
|
8421
8578
|
}
|
|
8422
8579
|
},
|
|
8423
8580
|
dca: {
|
|
8424
|
-
description: "
|
|
8581
|
+
description: "DCA (Martingale) bot \u2014 spot or contract recurring buys",
|
|
8425
8582
|
commands: {
|
|
8426
8583
|
orders: {
|
|
8427
|
-
usage: "okx bot dca orders [--algoId <id>] [--instId <id>] [--history]",
|
|
8428
|
-
description: "List
|
|
8584
|
+
usage: "okx bot dca orders [--algoOrdType <spot_dca|contract_dca>] [--algoId <id>] [--instId <id>] [--history]",
|
|
8585
|
+
description: "List DCA bots (spot and/or contract)"
|
|
8429
8586
|
},
|
|
8430
8587
|
details: {
|
|
8431
|
-
usage: "okx bot dca details --algoId <id>",
|
|
8432
|
-
description: "Get
|
|
8588
|
+
usage: "okx bot dca details --algoOrdType <spot_dca|contract_dca> --algoId <id>",
|
|
8589
|
+
description: "Get DCA bot details (spot or contract)"
|
|
8433
8590
|
},
|
|
8434
8591
|
"sub-orders": {
|
|
8435
|
-
usage: "okx bot dca sub-orders --algoId <id> [--cycleId <id>]",
|
|
8436
|
-
description: "
|
|
8592
|
+
usage: "okx bot dca sub-orders --algoOrdType <spot_dca|contract_dca> --algoId <id> [--cycleId <id>]",
|
|
8593
|
+
description: "Get DCA cycles/orders (spot or contract)"
|
|
8437
8594
|
},
|
|
8438
8595
|
create: {
|
|
8439
|
-
usage: "okx bot dca create --
|
|
8440
|
-
description: "Create a
|
|
8596
|
+
usage: "okx bot dca create --algoOrdType <spot_dca|contract_dca> --instId <id> --direction <long|short>\n --initOrdAmt <n> --maxSafetyOrds <n> --tpPct <n>\n [--lever <n>] [--safetyOrdAmt <n>] [--pxSteps <n>] [--pxStepsMult <n>] [--volMult <n>]\n [--slPct <n>] [--slMode <limit|market>] [--allowReinvest <true|false>]\n [--triggerStrategy <instant|price|rsi>] [--triggerPx <price>]\n [--algoClOrdId <id>] [--reserveFunds <true|false>] [--tradeQuoteCcy <ccy>]\n Note: --lever required for contract_dca; safetyOrdAmt, pxSteps, pxStepsMult, volMult required when maxSafetyOrds > 0",
|
|
8597
|
+
description: "Create a DCA (Martingale) bot (spot or contract)"
|
|
8441
8598
|
},
|
|
8442
8599
|
stop: {
|
|
8443
|
-
usage: "okx bot dca stop --algoId <id>",
|
|
8444
|
-
description: "Stop a
|
|
8600
|
+
usage: "okx bot dca stop --algoOrdType <spot_dca|contract_dca> --algoId <id> [--stopType <1|2>]\n Note: --stopType required for spot_dca (1=sell all, 2=keep tokens)",
|
|
8601
|
+
description: "Stop a DCA bot (spot or contract)"
|
|
8445
8602
|
}
|
|
8446
8603
|
}
|
|
8447
8604
|
}
|
|
@@ -8676,7 +8833,7 @@ var CLI_OPTIONS = {
|
|
|
8676
8833
|
autoCxl: { type: "boolean", default: false },
|
|
8677
8834
|
clOrdId: { type: "string" },
|
|
8678
8835
|
newPx: { type: "string" },
|
|
8679
|
-
// dca bot (contract
|
|
8836
|
+
// dca bot (spot & contract)
|
|
8680
8837
|
initOrdAmt: { type: "string" },
|
|
8681
8838
|
safetyOrdAmt: { type: "string" },
|
|
8682
8839
|
maxSafetyOrds: { type: "string" },
|
|
@@ -8690,6 +8847,8 @@ var CLI_OPTIONS = {
|
|
|
8690
8847
|
triggerStrategy: { type: "string" },
|
|
8691
8848
|
triggerPx: { type: "string" },
|
|
8692
8849
|
cycleId: { type: "string" },
|
|
8850
|
+
reserveFunds: { type: "string" },
|
|
8851
|
+
tradeQuoteCcy: { type: "string" },
|
|
8693
8852
|
// i18n
|
|
8694
8853
|
lang: { type: "string" },
|
|
8695
8854
|
// option
|
|
@@ -8909,10 +9068,15 @@ async function cmdMarketTicker(run, instId, json) {
|
|
|
8909
9068
|
printKv({
|
|
8910
9069
|
instId: t["instId"],
|
|
8911
9070
|
last: t["last"],
|
|
8912
|
-
"24h
|
|
9071
|
+
"24h open": t["open24h"],
|
|
8913
9072
|
"24h high": t["high24h"],
|
|
8914
9073
|
"24h low": t["low24h"],
|
|
8915
9074
|
"24h vol": t["vol24h"],
|
|
9075
|
+
"24h change %": (() => {
|
|
9076
|
+
const last = Number(t["last"]);
|
|
9077
|
+
const open24h = Number(t["open24h"]);
|
|
9078
|
+
return open24h !== 0 ? ((last - open24h) / open24h * 100).toFixed(2) + "%" : "N/A";
|
|
9079
|
+
})(),
|
|
8916
9080
|
time: new Date(Number(t["ts"])).toLocaleString()
|
|
8917
9081
|
});
|
|
8918
9082
|
}
|
|
@@ -10949,6 +11113,7 @@ async function cmdGridStop(run, opts) {
|
|
|
10949
11113
|
async function cmdDcaCreate(run, opts) {
|
|
10950
11114
|
const result = await run("dca_create_order", {
|
|
10951
11115
|
instId: opts.instId,
|
|
11116
|
+
algoOrdType: opts.algoOrdType,
|
|
10952
11117
|
lever: opts.lever,
|
|
10953
11118
|
direction: opts.direction,
|
|
10954
11119
|
initOrdAmt: opts.initOrdAmt,
|
|
@@ -10962,25 +11127,29 @@ async function cmdDcaCreate(run, opts) {
|
|
|
10962
11127
|
slMode: opts.slMode,
|
|
10963
11128
|
allowReinvest: opts.allowReinvest,
|
|
10964
11129
|
triggerStrategy: opts.triggerStrategy,
|
|
10965
|
-
triggerPx: opts.triggerPx
|
|
11130
|
+
triggerPx: opts.triggerPx,
|
|
11131
|
+
algoClOrdId: opts.algoClOrdId,
|
|
11132
|
+
reserveFunds: opts.reserveFunds,
|
|
11133
|
+
tradeQuoteCcy: opts.tradeQuoteCcy
|
|
10966
11134
|
});
|
|
10967
11135
|
const data = getData7(result);
|
|
10968
11136
|
if (opts.json) return printJson(data);
|
|
10969
|
-
const r = data?.[0];
|
|
10970
11137
|
emitWriteResult5(data?.[0], "DCA bot created", "algoId");
|
|
10971
11138
|
}
|
|
10972
11139
|
async function cmdDcaStop(run, opts) {
|
|
10973
11140
|
const result = await run("dca_stop_order", {
|
|
10974
|
-
algoId: opts.algoId
|
|
11141
|
+
algoId: opts.algoId,
|
|
11142
|
+
algoOrdType: opts.algoOrdType,
|
|
11143
|
+
stopType: opts.stopType
|
|
10975
11144
|
});
|
|
10976
11145
|
const data = getData7(result);
|
|
10977
11146
|
if (opts.json) return printJson(data);
|
|
10978
|
-
const r = data?.[0];
|
|
10979
11147
|
emitWriteResult5(data?.[0], "DCA bot stopped", "algoId");
|
|
10980
11148
|
}
|
|
10981
11149
|
async function cmdDcaOrders(run, opts) {
|
|
10982
11150
|
const result = await run("dca_get_orders", {
|
|
10983
11151
|
status: opts.history ? "history" : "active",
|
|
11152
|
+
algoOrdType: opts.algoOrdType,
|
|
10984
11153
|
algoId: opts.algoId,
|
|
10985
11154
|
instId: opts.instId
|
|
10986
11155
|
});
|
|
@@ -10994,6 +11163,7 @@ async function cmdDcaOrders(run, opts) {
|
|
|
10994
11163
|
orders.map((o) => ({
|
|
10995
11164
|
algoId: o["algoId"],
|
|
10996
11165
|
instId: o["instId"],
|
|
11166
|
+
type: o["algoOrdType"],
|
|
10997
11167
|
state: o["state"],
|
|
10998
11168
|
pnl: o["pnl"],
|
|
10999
11169
|
pnlRatio: o["pnlRatio"],
|
|
@@ -11003,7 +11173,8 @@ async function cmdDcaOrders(run, opts) {
|
|
|
11003
11173
|
}
|
|
11004
11174
|
async function cmdDcaDetails(run, opts) {
|
|
11005
11175
|
const result = await run("dca_get_order_details", {
|
|
11006
|
-
algoId: opts.algoId
|
|
11176
|
+
algoId: opts.algoId,
|
|
11177
|
+
algoOrdType: opts.algoOrdType
|
|
11007
11178
|
});
|
|
11008
11179
|
const detail = (getData7(result) ?? [])[0];
|
|
11009
11180
|
if (!detail) {
|
|
@@ -11013,6 +11184,7 @@ async function cmdDcaDetails(run, opts) {
|
|
|
11013
11184
|
if (opts.json) return printJson(detail);
|
|
11014
11185
|
printKv({
|
|
11015
11186
|
algoId: detail["algoId"],
|
|
11187
|
+
algoOrdType: detail["algoOrdType"],
|
|
11016
11188
|
instId: detail["instId"],
|
|
11017
11189
|
sz: detail["sz"],
|
|
11018
11190
|
avgPx: detail["avgPx"],
|
|
@@ -11030,26 +11202,42 @@ async function cmdDcaDetails(run, opts) {
|
|
|
11030
11202
|
async function cmdDcaSubOrders(run, opts) {
|
|
11031
11203
|
const result = await run("dca_get_sub_orders", {
|
|
11032
11204
|
algoId: opts.algoId,
|
|
11205
|
+
algoOrdType: opts.algoOrdType,
|
|
11033
11206
|
cycleId: opts.cycleId
|
|
11034
11207
|
});
|
|
11035
|
-
const
|
|
11036
|
-
if (opts.json) return printJson(
|
|
11037
|
-
if (!
|
|
11208
|
+
const rows = getData7(result) ?? [];
|
|
11209
|
+
if (opts.json) return printJson(rows);
|
|
11210
|
+
if (!rows.length) {
|
|
11038
11211
|
outputLine("No sub-orders");
|
|
11039
11212
|
return;
|
|
11040
11213
|
}
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11214
|
+
if (opts.cycleId) {
|
|
11215
|
+
printTable(
|
|
11216
|
+
rows.map((o) => ({
|
|
11217
|
+
ordId: o["ordId"],
|
|
11218
|
+
side: o["side"],
|
|
11219
|
+
ordType: o["ordType"],
|
|
11220
|
+
px: o["px"],
|
|
11221
|
+
filledSz: o["filledSz"],
|
|
11222
|
+
avgFillPx: o["avgFillPx"],
|
|
11223
|
+
state: o["state"],
|
|
11224
|
+
fee: o["fee"]
|
|
11225
|
+
}))
|
|
11226
|
+
);
|
|
11227
|
+
} else {
|
|
11228
|
+
printTable(
|
|
11229
|
+
rows.map((o) => ({
|
|
11230
|
+
cycleId: o["cycleId"],
|
|
11231
|
+
status: o["cycleStatus"],
|
|
11232
|
+
current: o["currentCycle"] ? "yes" : "",
|
|
11233
|
+
avgPx: o["avgPx"],
|
|
11234
|
+
tpPx: o["tpPx"],
|
|
11235
|
+
realizedPnl: o["realizedPnl"],
|
|
11236
|
+
fee: o["fee"],
|
|
11237
|
+
startTime: o["startTime"] ? new Date(Number(o["startTime"])).toLocaleString() : ""
|
|
11238
|
+
}))
|
|
11239
|
+
);
|
|
11240
|
+
}
|
|
11053
11241
|
}
|
|
11054
11242
|
|
|
11055
11243
|
// src/commands/onchain-earn.ts
|
|
@@ -11349,7 +11537,7 @@ async function cmdDcdQuoteAndBuy(run, opts) {
|
|
|
11349
11537
|
// src/index.ts
|
|
11350
11538
|
var _require3 = createRequire3(import.meta.url);
|
|
11351
11539
|
var CLI_VERSION2 = _require3("../package.json").version;
|
|
11352
|
-
var GIT_HASH2 = true ? "
|
|
11540
|
+
var GIT_HASH2 = true ? "c270a0b" : "dev";
|
|
11353
11541
|
function handleConfigCommand(action, rest, json, lang, force) {
|
|
11354
11542
|
if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
|
|
11355
11543
|
if (action === "show") return cmdConfigShow(json);
|
|
@@ -11956,15 +12144,17 @@ function handleBotGridCommand(run, v, rest, json) {
|
|
|
11956
12144
|
});
|
|
11957
12145
|
}
|
|
11958
12146
|
function handleBotDcaCommand(run, subAction, v, json) {
|
|
12147
|
+
const algoOrdType = v.algoOrdType ?? "contract_dca";
|
|
11959
12148
|
if (subAction === "orders")
|
|
11960
|
-
return cmdDcaOrders(run, { algoId: v.algoId, instId: v.instId, history: v.history ?? false, json });
|
|
12149
|
+
return cmdDcaOrders(run, { algoOrdType, algoId: v.algoId, instId: v.instId, history: v.history ?? false, json });
|
|
11961
12150
|
if (subAction === "details")
|
|
11962
|
-
return cmdDcaDetails(run, { algoId: v.algoId, json });
|
|
12151
|
+
return cmdDcaDetails(run, { algoId: v.algoId, algoOrdType, json });
|
|
11963
12152
|
if (subAction === "sub-orders")
|
|
11964
|
-
return cmdDcaSubOrders(run, { algoId: v.algoId, cycleId: v.cycleId, json });
|
|
12153
|
+
return cmdDcaSubOrders(run, { algoId: v.algoId, algoOrdType, cycleId: v.cycleId, json });
|
|
11965
12154
|
if (subAction === "create")
|
|
11966
12155
|
return cmdDcaCreate(run, {
|
|
11967
12156
|
instId: v.instId,
|
|
12157
|
+
algoOrdType,
|
|
11968
12158
|
lever: v.lever,
|
|
11969
12159
|
direction: v.direction,
|
|
11970
12160
|
initOrdAmt: v.initOrdAmt,
|
|
@@ -11979,10 +12169,13 @@ function handleBotDcaCommand(run, subAction, v, json) {
|
|
|
11979
12169
|
allowReinvest: v.allowReinvest,
|
|
11980
12170
|
triggerStrategy: v.triggerStrategy,
|
|
11981
12171
|
triggerPx: v.triggerPx,
|
|
12172
|
+
algoClOrdId: v.algoClOrdId,
|
|
12173
|
+
reserveFunds: v.reserveFunds,
|
|
12174
|
+
tradeQuoteCcy: v.tradeQuoteCcy,
|
|
11982
12175
|
json
|
|
11983
12176
|
});
|
|
11984
12177
|
if (subAction === "stop")
|
|
11985
|
-
return cmdDcaStop(run, { algoId: v.algoId, json });
|
|
12178
|
+
return cmdDcaStop(run, { algoId: v.algoId, algoOrdType, stopType: v.stopType, json });
|
|
11986
12179
|
}
|
|
11987
12180
|
function handleBotCommand(run, action, rest, v, json) {
|
|
11988
12181
|
if (action === "grid") return handleBotGridCommand(run, v, rest, json);
|