@okx_ai/okx-trade-cli 1.2.4-beta.4 → 1.2.4-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2200,6 +2200,11 @@ function registerAlgoTradeTools() {
2200
2200
  enum: ["pending", "history"],
2201
2201
  description: "pending=active (default); history=completed"
2202
2202
  },
2203
+ instType: {
2204
+ type: "string",
2205
+ enum: ["SWAP", "FUTURES"],
2206
+ description: "SWAP (default) or FUTURES"
2207
+ },
2203
2208
  ordType: {
2204
2209
  type: "string",
2205
2210
  enum: ["conditional", "oco", "move_order_stop"],
@@ -2239,8 +2244,9 @@ function registerAlgoTradeTools() {
2239
2244
  const path4 = isHistory ? "/api/v5/trade/orders-algo-history" : "/api/v5/trade/orders-algo-pending";
2240
2245
  const ordType = readString(args, "ordType");
2241
2246
  const state = isHistory ? readString(args, "state") ?? "effective" : void 0;
2247
+ const instType = readString(args, "instType") ?? "SWAP";
2242
2248
  const baseParams = compactObject({
2243
- instType: "SWAP",
2249
+ instType,
2244
2250
  instId: readString(args, "instId"),
2245
2251
  algoId: readString(args, "algoId"),
2246
2252
  after: readString(args, "after"),
@@ -2271,216 +2277,567 @@ function registerAlgoTradeTools() {
2271
2277
  }
2272
2278
  ];
2273
2279
  }
2274
- var DEFAULT_LOG_DIR = path.join(os.homedir(), ".okx", "logs");
2275
- function getLogPaths(logDir, days = 7) {
2276
- const paths = [];
2277
- const now = /* @__PURE__ */ new Date();
2278
- for (let i = 0; i < days; i++) {
2279
- const d = new Date(now);
2280
- d.setUTCDate(now.getUTCDate() - i);
2281
- const yyyy = d.getUTCFullYear();
2282
- const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
2283
- const dd = String(d.getUTCDate()).padStart(2, "0");
2284
- paths.push(path.join(logDir, `trade-${yyyy}-${mm}-${dd}.log`));
2285
- }
2286
- return paths;
2287
- }
2288
- function readEntries(logDir) {
2289
- const entries = [];
2290
- for (const filePath of getLogPaths(logDir)) {
2291
- let content;
2292
- try {
2293
- content = fs.readFileSync(filePath, "utf8");
2294
- } catch {
2295
- continue;
2296
- }
2297
- for (const line of content.split("\n")) {
2298
- const trimmed = line.trim();
2299
- if (!trimmed) continue;
2300
- try {
2301
- entries.push(JSON.parse(trimmed));
2302
- } catch {
2303
- }
2304
- }
2305
- }
2306
- return entries;
2307
- }
2308
- function registerAuditTools() {
2280
+ function registerFuturesAlgoTools() {
2309
2281
  return [
2310
2282
  {
2311
- name: "trade_get_history",
2312
- module: "account",
2313
- description: "Query local audit log of tool calls made through this MCP server. Returns recent operations with timestamps, duration, params, and results. Use to review what trades or queries were executed in this session or past sessions.",
2314
- isWrite: false,
2283
+ name: "futures_place_algo_order",
2284
+ module: "futures",
2285
+ description: "Place a FUTURES delivery algo order: TP/SL (conditional/oco) or trailing stop (move_order_stop). [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: provide callbackRatio (e.g. '0.01'=1%) OR callbackSpread, and optionally activePx. Set tpOrdPx='-1' or slOrdPx='-1' for market execution.",
2286
+ isWrite: true,
2315
2287
  inputSchema: {
2316
2288
  type: "object",
2317
2289
  properties: {
2318
- limit: {
2319
- type: "number",
2320
- description: "Max results (default 20)"
2290
+ instId: {
2291
+ type: "string",
2292
+ description: "e.g. BTC-USDT-240329"
2321
2293
  },
2322
- tool: {
2294
+ tdMode: {
2323
2295
  type: "string",
2324
- description: "e.g. swap_place_order"
2296
+ enum: ["cross", "isolated"],
2297
+ description: "cross|isolated margin"
2325
2298
  },
2326
- level: {
2299
+ side: {
2327
2300
  type: "string",
2328
- enum: ["INFO", "WARN", "ERROR", "DEBUG"]
2301
+ enum: ["buy", "sell"],
2302
+ description: "sell=close long, buy=close short"
2329
2303
  },
2330
- since: {
2304
+ posSide: {
2331
2305
  type: "string",
2332
- description: "ISO 8601 timestamp lower bound"
2333
- }
2334
- }
2335
- },
2336
- handler: async (rawArgs) => {
2337
- const args = asRecord(rawArgs);
2338
- const limit = Math.min(readNumber(args, "limit") ?? 20, 100);
2339
- const toolFilter = readString(args, "tool");
2340
- const levelFilter = readString(args, "level")?.toUpperCase();
2341
- const since = readString(args, "since");
2342
- const sinceTime = since ? new Date(since).getTime() : void 0;
2343
- let entries = readEntries(DEFAULT_LOG_DIR);
2344
- if (toolFilter) {
2345
- entries = entries.filter((e) => e.tool === toolFilter);
2346
- }
2347
- if (levelFilter) {
2348
- entries = entries.filter((e) => e.level === levelFilter);
2349
- }
2350
- if (sinceTime !== void 0) {
2351
- entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceTime);
2352
- }
2353
- entries.sort(
2354
- (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
2355
- );
2356
- entries = entries.slice(0, limit);
2357
- return { entries, total: entries.length };
2358
- }
2359
- }
2360
- ];
2361
- }
2362
- function normalizeWrite(response) {
2363
- const data = response.data;
2364
- if (Array.isArray(data) && data.length > 0) {
2365
- const failed = data.filter(
2366
- (item) => item !== null && typeof item === "object" && "sCode" in item && item["sCode"] !== "0"
2367
- );
2368
- if (failed.length > 0) {
2369
- const messages2 = failed.map(
2370
- (item) => `[${item["sCode"]}] ${item["sMsg"] ?? "Operation failed"}`
2371
- );
2372
- throw new OkxApiError(messages2.join("; "), {
2373
- code: String(failed[0]["sCode"] ?? ""),
2374
- endpoint: response.endpoint
2375
- });
2376
- }
2377
- }
2378
- return {
2379
- endpoint: response.endpoint,
2380
- requestTime: response.requestTime,
2381
- data
2382
- };
2383
- }
2384
- function registerGridTools() {
2385
- return [
2386
- {
2387
- name: "grid_get_orders",
2388
- module: "bot.grid",
2389
- description: "Query grid trading bot list. status='active' for running bots; status='history' for completed/stopped. Covers Spot Grid, Contract Grid, and Moon Grid.",
2390
- isWrite: false,
2391
- inputSchema: {
2392
- type: "object",
2393
- properties: {
2394
- algoOrdType: {
2306
+ enum: ["long", "short", "net"],
2307
+ description: "net=one-way (default); long/short=hedge mode"
2308
+ },
2309
+ ordType: {
2395
2310
  type: "string",
2396
- enum: ["grid", "contract_grid", "moon_grid"],
2397
- description: "Grid bot type. grid=Spot, contract_grid=Contract, moon_grid=Moon. Must match the bot's actual type when filtering by algoId."
2311
+ enum: ["conditional", "oco", "move_order_stop"],
2312
+ description: "conditional=single TP/SL or both; oco=TP+SL pair; move_order_stop=trailing stop"
2398
2313
  },
2399
- status: {
2314
+ sz: {
2400
2315
  type: "string",
2401
- enum: ["active", "history"],
2402
- description: "active=running (default); history=stopped"
2316
+ description: "Number of contracts (NOT USDT amount)."
2403
2317
  },
2404
- instId: {
2318
+ tpTriggerPx: {
2405
2319
  type: "string",
2406
- description: "e.g. BTC-USDT"
2320
+ description: "TP trigger price (conditional/oco only)"
2407
2321
  },
2408
- algoId: {
2322
+ tpOrdPx: {
2409
2323
  type: "string",
2410
- description: "Grid bot algo order ID (returned by grid_create_order or grid_get_orders). This is NOT a normal trade order ID."
2324
+ description: "TP order price; -1=market (conditional/oco only)"
2411
2325
  },
2412
- after: {
2326
+ tpTriggerPxType: {
2413
2327
  type: "string",
2414
- description: "Pagination: before this algo ID"
2328
+ enum: ["last", "index", "mark"],
2329
+ description: "last(default)|index|mark (conditional/oco only)"
2415
2330
  },
2416
- before: {
2331
+ slTriggerPx: {
2417
2332
  type: "string",
2418
- description: "Pagination: after this algo ID"
2333
+ description: "SL trigger price (conditional/oco only)"
2419
2334
  },
2420
- limit: {
2421
- type: "number",
2422
- description: "Max results (default 100)"
2335
+ slOrdPx: {
2336
+ type: "string",
2337
+ description: "SL order price; -1=market (conditional/oco only)"
2338
+ },
2339
+ slTriggerPxType: {
2340
+ type: "string",
2341
+ enum: ["last", "index", "mark"],
2342
+ description: "last(default)|index|mark (conditional/oco only)"
2343
+ },
2344
+ callbackRatio: {
2345
+ type: "string",
2346
+ description: "Callback ratio (e.g. '0.01'=1%); provide either ratio or spread (move_order_stop only)"
2347
+ },
2348
+ callbackSpread: {
2349
+ type: "string",
2350
+ description: "Callback spread in price units (move_order_stop only)"
2351
+ },
2352
+ activePx: {
2353
+ type: "string",
2354
+ description: "Activation price; tracking starts after market reaches this level (move_order_stop only)"
2355
+ },
2356
+ reduceOnly: {
2357
+ type: "boolean",
2358
+ description: "Ensure order only reduces position"
2359
+ },
2360
+ clOrdId: {
2361
+ type: "string",
2362
+ description: "Client order ID (max 32 chars)"
2423
2363
  }
2424
2364
  },
2425
- required: ["algoOrdType"]
2365
+ required: ["instId", "tdMode", "side", "ordType", "sz"]
2426
2366
  },
2427
2367
  handler: async (rawArgs, context) => {
2428
2368
  const args = asRecord(rawArgs);
2429
- const algoOrdType = requireString(args, "algoOrdType");
2430
- const status = readString(args, "status") ?? "active";
2431
- const path4 = status === "history" ? "/api/v5/tradingBot/grid/orders-algo-history" : "/api/v5/tradingBot/grid/orders-algo-pending";
2432
- const response = await context.client.privateGet(
2433
- path4,
2369
+ const reduceOnly = args.reduceOnly;
2370
+ const response = await context.client.privatePost(
2371
+ "/api/v5/trade/order-algo",
2434
2372
  compactObject({
2435
- algoOrdType,
2436
- instId: readString(args, "instId"),
2437
- algoId: readString(args, "algoId"),
2438
- after: readString(args, "after"),
2439
- before: readString(args, "before"),
2440
- limit: readNumber(args, "limit")
2373
+ instId: requireString(args, "instId"),
2374
+ tdMode: requireString(args, "tdMode"),
2375
+ side: requireString(args, "side"),
2376
+ posSide: readString(args, "posSide"),
2377
+ ordType: requireString(args, "ordType"),
2378
+ sz: requireString(args, "sz"),
2379
+ tpTriggerPx: readString(args, "tpTriggerPx"),
2380
+ tpOrdPx: readString(args, "tpOrdPx"),
2381
+ tpTriggerPxType: readString(args, "tpTriggerPxType"),
2382
+ slTriggerPx: readString(args, "slTriggerPx"),
2383
+ slOrdPx: readString(args, "slOrdPx"),
2384
+ slTriggerPxType: readString(args, "slTriggerPxType"),
2385
+ callBackRatio: readString(args, "callbackRatio"),
2386
+ callBackSpread: readString(args, "callbackSpread"),
2387
+ activePx: readString(args, "activePx"),
2388
+ reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
2389
+ clOrdId: readString(args, "clOrdId"),
2390
+ tag: context.config.sourceTag
2441
2391
  }),
2442
- privateRateLimit("grid_get_orders", 20)
2392
+ privateRateLimit("futures_place_algo_order", 20)
2443
2393
  );
2444
2394
  return normalizeResponse(response);
2445
2395
  }
2446
2396
  },
2447
2397
  {
2448
- name: "grid_get_order_details",
2449
- module: "bot.grid",
2450
- description: "Query details of a single grid trading bot by its algo ID. Returns configuration, current status, PnL, and position info.",
2451
- isWrite: false,
2398
+ name: "futures_place_move_stop_order",
2399
+ module: "futures",
2400
+ description: "[DEPRECATED] Use futures_place_algo_order with ordType='move_order_stop' instead. Place a FUTURES delivery trailing stop order. [CAUTION] Executes real trades.",
2401
+ isWrite: true,
2452
2402
  inputSchema: {
2453
2403
  type: "object",
2454
2404
  properties: {
2455
- algoOrdType: {
2405
+ instId: {
2456
2406
  type: "string",
2457
- enum: ["grid", "contract_grid", "moon_grid"],
2458
- description: "Must match the bot's actual type (use the algoOrdType value returned by grid_get_orders). grid=Spot, contract_grid=Contract, moon_grid=Moon."
2407
+ description: "e.g. BTC-USDT-240329"
2459
2408
  },
2460
- algoId: {
2409
+ tdMode: {
2461
2410
  type: "string",
2462
- description: "Grid bot algo order ID (returned by grid_create_order or grid_get_orders). This is NOT a normal trade order ID."
2463
- }
2464
- },
2465
- required: ["algoOrdType", "algoId"]
2466
- },
2467
- handler: async (rawArgs, context) => {
2468
- const args = asRecord(rawArgs);
2469
- const response = await context.client.privateGet(
2470
- "/api/v5/tradingBot/grid/orders-algo-details",
2471
- {
2472
- algoOrdType: requireString(args, "algoOrdType"),
2473
- algoId: requireString(args, "algoId")
2411
+ enum: ["cross", "isolated"],
2412
+ description: "cross|isolated margin"
2474
2413
  },
2475
- privateRateLimit("grid_get_order_details", 20)
2476
- );
2477
- return normalizeResponse(response);
2478
- }
2479
- },
2480
- {
2481
- name: "grid_get_sub_orders",
2482
- module: "bot.grid",
2483
- description: "Query individual sub-orders (grid trades) generated by a grid bot. type='filled' for executed trades; type='live' for pending orders.",
2414
+ side: {
2415
+ type: "string",
2416
+ enum: ["buy", "sell"],
2417
+ description: "sell=close long, buy=close short"
2418
+ },
2419
+ posSide: {
2420
+ type: "string",
2421
+ enum: ["long", "short", "net"],
2422
+ description: "net=one-way (default); long/short=hedge mode"
2423
+ },
2424
+ sz: {
2425
+ type: "string",
2426
+ description: "Number of contracts (NOT USDT amount)."
2427
+ },
2428
+ callbackRatio: {
2429
+ type: "string",
2430
+ description: "Callback ratio (e.g. '0.01'=1%); provide either ratio or spread"
2431
+ },
2432
+ callbackSpread: {
2433
+ type: "string",
2434
+ description: "Callback spread in price units; provide either ratio or spread"
2435
+ },
2436
+ activePx: {
2437
+ type: "string",
2438
+ description: "Activation price"
2439
+ },
2440
+ reduceOnly: {
2441
+ type: "boolean",
2442
+ description: "Ensure order only reduces position"
2443
+ },
2444
+ clOrdId: {
2445
+ type: "string",
2446
+ description: "Client order ID (max 32 chars)"
2447
+ }
2448
+ },
2449
+ required: ["instId", "tdMode", "side", "sz"]
2450
+ },
2451
+ handler: async (rawArgs, context) => {
2452
+ const args = asRecord(rawArgs);
2453
+ const reduceOnly = args.reduceOnly;
2454
+ const response = await context.client.privatePost(
2455
+ "/api/v5/trade/order-algo",
2456
+ compactObject({
2457
+ instId: requireString(args, "instId"),
2458
+ tdMode: requireString(args, "tdMode"),
2459
+ side: requireString(args, "side"),
2460
+ posSide: readString(args, "posSide"),
2461
+ ordType: "move_order_stop",
2462
+ sz: requireString(args, "sz"),
2463
+ callBackRatio: readString(args, "callbackRatio"),
2464
+ callBackSpread: readString(args, "callbackSpread"),
2465
+ activePx: readString(args, "activePx"),
2466
+ reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
2467
+ clOrdId: readString(args, "clOrdId")
2468
+ }),
2469
+ privateRateLimit("futures_place_move_stop_order", 20)
2470
+ );
2471
+ return normalizeResponse(response);
2472
+ }
2473
+ },
2474
+ {
2475
+ name: "futures_amend_algo_order",
2476
+ module: "futures",
2477
+ description: "Amend a pending FUTURES delivery algo order (modify TP/SL prices or size).",
2478
+ isWrite: true,
2479
+ inputSchema: {
2480
+ type: "object",
2481
+ properties: {
2482
+ instId: { type: "string", description: "e.g. BTC-USDT-240329" },
2483
+ algoId: { type: "string", description: "Algo order ID" },
2484
+ newSz: { type: "string", description: "New number of contracts" },
2485
+ newTpTriggerPx: { type: "string", description: "New TP trigger price" },
2486
+ newTpOrdPx: { type: "string", description: "New TP order price; -1=market" },
2487
+ newSlTriggerPx: { type: "string", description: "New SL trigger price" },
2488
+ newSlOrdPx: { type: "string", description: "New SL order price; -1=market" }
2489
+ },
2490
+ required: ["instId", "algoId"]
2491
+ },
2492
+ handler: async (rawArgs, context) => {
2493
+ const args = asRecord(rawArgs);
2494
+ const response = await context.client.privatePost(
2495
+ "/api/v5/trade/amend-algos",
2496
+ compactObject({
2497
+ instId: requireString(args, "instId"),
2498
+ algoId: requireString(args, "algoId"),
2499
+ newSz: readString(args, "newSz"),
2500
+ newTpTriggerPx: readString(args, "newTpTriggerPx"),
2501
+ newTpOrdPx: readString(args, "newTpOrdPx"),
2502
+ newSlTriggerPx: readString(args, "newSlTriggerPx"),
2503
+ newSlOrdPx: readString(args, "newSlOrdPx")
2504
+ }),
2505
+ privateRateLimit("futures_amend_algo_order", 20)
2506
+ );
2507
+ return normalizeResponse(response);
2508
+ }
2509
+ },
2510
+ {
2511
+ name: "futures_cancel_algo_orders",
2512
+ module: "futures",
2513
+ description: "Cancel one or more pending FUTURES delivery algo orders (TP/SL). Accepts a list of {algoId, instId} objects.",
2514
+ isWrite: true,
2515
+ inputSchema: {
2516
+ type: "object",
2517
+ properties: {
2518
+ orders: {
2519
+ type: "array",
2520
+ description: "List of algo orders to cancel. Each item: {algoId, instId}.",
2521
+ items: {
2522
+ type: "object",
2523
+ properties: {
2524
+ algoId: { type: "string", description: "Algo order ID" },
2525
+ instId: { type: "string", description: "e.g. BTC-USDT-240329" }
2526
+ },
2527
+ required: ["algoId", "instId"]
2528
+ }
2529
+ }
2530
+ },
2531
+ required: ["orders"]
2532
+ },
2533
+ handler: async (rawArgs, context) => {
2534
+ const args = asRecord(rawArgs);
2535
+ const orders = args.orders;
2536
+ if (!Array.isArray(orders) || orders.length === 0) {
2537
+ throw new Error("orders must be a non-empty array.");
2538
+ }
2539
+ const response = await context.client.privatePost(
2540
+ "/api/v5/trade/cancel-algos",
2541
+ orders,
2542
+ privateRateLimit("futures_cancel_algo_orders", 20)
2543
+ );
2544
+ return normalizeResponse(response);
2545
+ }
2546
+ },
2547
+ {
2548
+ name: "futures_get_algo_orders",
2549
+ module: "futures",
2550
+ description: "Query pending or completed FUTURES delivery algo orders (TP/SL, OCO, trailing stop).",
2551
+ isWrite: false,
2552
+ inputSchema: {
2553
+ type: "object",
2554
+ properties: {
2555
+ status: {
2556
+ type: "string",
2557
+ enum: ["pending", "history"],
2558
+ description: "pending=active (default); history=completed"
2559
+ },
2560
+ ordType: {
2561
+ type: "string",
2562
+ enum: ["conditional", "oco", "move_order_stop"],
2563
+ description: "Filter by type; omit for all"
2564
+ },
2565
+ instId: {
2566
+ type: "string",
2567
+ description: "Instrument ID filter"
2568
+ },
2569
+ algoId: {
2570
+ type: "string",
2571
+ description: "Filter by algo order ID"
2572
+ },
2573
+ after: {
2574
+ type: "string",
2575
+ description: "Pagination: before this algo ID"
2576
+ },
2577
+ before: {
2578
+ type: "string",
2579
+ description: "Pagination: after this algo ID"
2580
+ },
2581
+ limit: {
2582
+ type: "number",
2583
+ description: "Max results (default 100)"
2584
+ },
2585
+ state: {
2586
+ type: "string",
2587
+ enum: ["effective", "canceled", "order_failed"],
2588
+ description: "Required when status=history. effective=triggered, canceled, order_failed. Defaults to effective."
2589
+ }
2590
+ }
2591
+ },
2592
+ handler: async (rawArgs, context) => {
2593
+ const args = asRecord(rawArgs);
2594
+ const status = readString(args, "status") ?? "pending";
2595
+ const isHistory = status === "history";
2596
+ const path4 = isHistory ? "/api/v5/trade/orders-algo-history" : "/api/v5/trade/orders-algo-pending";
2597
+ const ordType = readString(args, "ordType");
2598
+ const state = isHistory ? readString(args, "state") ?? "effective" : void 0;
2599
+ const baseParams = compactObject({
2600
+ instType: "FUTURES",
2601
+ instId: readString(args, "instId"),
2602
+ algoId: readString(args, "algoId"),
2603
+ after: readString(args, "after"),
2604
+ before: readString(args, "before"),
2605
+ limit: readNumber(args, "limit"),
2606
+ state
2607
+ });
2608
+ if (ordType) {
2609
+ const response = await context.client.privateGet(
2610
+ path4,
2611
+ { ...baseParams, ordType },
2612
+ privateRateLimit("futures_get_algo_orders", 20)
2613
+ );
2614
+ return normalizeResponse(response);
2615
+ }
2616
+ const [r1, r2, r3] = await Promise.all([
2617
+ context.client.privateGet(path4, { ...baseParams, ordType: "conditional" }, privateRateLimit("futures_get_algo_orders", 20)),
2618
+ context.client.privateGet(path4, { ...baseParams, ordType: "oco" }, privateRateLimit("futures_get_algo_orders", 20)),
2619
+ context.client.privateGet(path4, { ...baseParams, ordType: "move_order_stop" }, privateRateLimit("futures_get_algo_orders", 20))
2620
+ ]);
2621
+ const merged = [
2622
+ ...r1.data ?? [],
2623
+ ...r2.data ?? [],
2624
+ ...r3.data ?? []
2625
+ ];
2626
+ return { endpoint: r1.endpoint, requestTime: r1.requestTime, data: merged };
2627
+ }
2628
+ }
2629
+ ];
2630
+ }
2631
+ var DEFAULT_LOG_DIR = path.join(os.homedir(), ".okx", "logs");
2632
+ function getLogPaths(logDir, days = 7) {
2633
+ const paths = [];
2634
+ const now = /* @__PURE__ */ new Date();
2635
+ for (let i = 0; i < days; i++) {
2636
+ const d = new Date(now);
2637
+ d.setUTCDate(now.getUTCDate() - i);
2638
+ const yyyy = d.getUTCFullYear();
2639
+ const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
2640
+ const dd = String(d.getUTCDate()).padStart(2, "0");
2641
+ paths.push(path.join(logDir, `trade-${yyyy}-${mm}-${dd}.log`));
2642
+ }
2643
+ return paths;
2644
+ }
2645
+ function readEntries(logDir) {
2646
+ const entries = [];
2647
+ for (const filePath of getLogPaths(logDir)) {
2648
+ let content;
2649
+ try {
2650
+ content = fs.readFileSync(filePath, "utf8");
2651
+ } catch {
2652
+ continue;
2653
+ }
2654
+ for (const line of content.split("\n")) {
2655
+ const trimmed = line.trim();
2656
+ if (!trimmed) continue;
2657
+ try {
2658
+ entries.push(JSON.parse(trimmed));
2659
+ } catch {
2660
+ }
2661
+ }
2662
+ }
2663
+ return entries;
2664
+ }
2665
+ function registerAuditTools() {
2666
+ return [
2667
+ {
2668
+ name: "trade_get_history",
2669
+ module: "account",
2670
+ description: "Query local audit log of tool calls made through this MCP server. Returns recent operations with timestamps, duration, params, and results. Use to review what trades or queries were executed in this session or past sessions.",
2671
+ isWrite: false,
2672
+ inputSchema: {
2673
+ type: "object",
2674
+ properties: {
2675
+ limit: {
2676
+ type: "number",
2677
+ description: "Max results (default 20)"
2678
+ },
2679
+ tool: {
2680
+ type: "string",
2681
+ description: "e.g. swap_place_order"
2682
+ },
2683
+ level: {
2684
+ type: "string",
2685
+ enum: ["INFO", "WARN", "ERROR", "DEBUG"]
2686
+ },
2687
+ since: {
2688
+ type: "string",
2689
+ description: "ISO 8601 timestamp lower bound"
2690
+ }
2691
+ }
2692
+ },
2693
+ handler: async (rawArgs) => {
2694
+ const args = asRecord(rawArgs);
2695
+ const limit = Math.min(readNumber(args, "limit") ?? 20, 100);
2696
+ const toolFilter = readString(args, "tool");
2697
+ const levelFilter = readString(args, "level")?.toUpperCase();
2698
+ const since = readString(args, "since");
2699
+ const sinceTime = since ? new Date(since).getTime() : void 0;
2700
+ let entries = readEntries(DEFAULT_LOG_DIR);
2701
+ if (toolFilter) {
2702
+ entries = entries.filter((e) => e.tool === toolFilter);
2703
+ }
2704
+ if (levelFilter) {
2705
+ entries = entries.filter((e) => e.level === levelFilter);
2706
+ }
2707
+ if (sinceTime !== void 0) {
2708
+ entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceTime);
2709
+ }
2710
+ entries.sort(
2711
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
2712
+ );
2713
+ entries = entries.slice(0, limit);
2714
+ return { entries, total: entries.length };
2715
+ }
2716
+ }
2717
+ ];
2718
+ }
2719
+ function normalizeWrite(response) {
2720
+ const data = response.data;
2721
+ if (Array.isArray(data) && data.length > 0) {
2722
+ const failed = data.filter(
2723
+ (item) => item !== null && typeof item === "object" && "sCode" in item && item["sCode"] !== "0"
2724
+ );
2725
+ if (failed.length > 0) {
2726
+ const messages2 = failed.map(
2727
+ (item) => `[${item["sCode"]}] ${item["sMsg"] ?? "Operation failed"}`
2728
+ );
2729
+ throw new OkxApiError(messages2.join("; "), {
2730
+ code: String(failed[0]["sCode"] ?? ""),
2731
+ endpoint: response.endpoint
2732
+ });
2733
+ }
2734
+ }
2735
+ return {
2736
+ endpoint: response.endpoint,
2737
+ requestTime: response.requestTime,
2738
+ data
2739
+ };
2740
+ }
2741
+ function registerGridTools() {
2742
+ return [
2743
+ {
2744
+ name: "grid_get_orders",
2745
+ module: "bot.grid",
2746
+ description: "Query grid trading bot list. status='active' for running bots; status='history' for completed/stopped. Covers Spot Grid, Contract Grid, and Moon Grid.",
2747
+ isWrite: false,
2748
+ inputSchema: {
2749
+ type: "object",
2750
+ properties: {
2751
+ algoOrdType: {
2752
+ type: "string",
2753
+ enum: ["grid", "contract_grid", "moon_grid"],
2754
+ description: "Grid bot type. grid=Spot, contract_grid=Contract, moon_grid=Moon. Must match the bot's actual type when filtering by algoId."
2755
+ },
2756
+ status: {
2757
+ type: "string",
2758
+ enum: ["active", "history"],
2759
+ description: "active=running (default); history=stopped"
2760
+ },
2761
+ instId: {
2762
+ type: "string",
2763
+ description: "e.g. BTC-USDT"
2764
+ },
2765
+ algoId: {
2766
+ type: "string",
2767
+ description: "Grid bot algo order ID (returned by grid_create_order or grid_get_orders). This is NOT a normal trade order ID."
2768
+ },
2769
+ after: {
2770
+ type: "string",
2771
+ description: "Pagination: before this algo ID"
2772
+ },
2773
+ before: {
2774
+ type: "string",
2775
+ description: "Pagination: after this algo ID"
2776
+ },
2777
+ limit: {
2778
+ type: "number",
2779
+ description: "Max results (default 100)"
2780
+ }
2781
+ },
2782
+ required: ["algoOrdType"]
2783
+ },
2784
+ handler: async (rawArgs, context) => {
2785
+ const args = asRecord(rawArgs);
2786
+ const algoOrdType = requireString(args, "algoOrdType");
2787
+ const status = readString(args, "status") ?? "active";
2788
+ const path4 = status === "history" ? "/api/v5/tradingBot/grid/orders-algo-history" : "/api/v5/tradingBot/grid/orders-algo-pending";
2789
+ const response = await context.client.privateGet(
2790
+ path4,
2791
+ compactObject({
2792
+ algoOrdType,
2793
+ instId: readString(args, "instId"),
2794
+ algoId: readString(args, "algoId"),
2795
+ after: readString(args, "after"),
2796
+ before: readString(args, "before"),
2797
+ limit: readNumber(args, "limit")
2798
+ }),
2799
+ privateRateLimit("grid_get_orders", 20)
2800
+ );
2801
+ return normalizeResponse(response);
2802
+ }
2803
+ },
2804
+ {
2805
+ name: "grid_get_order_details",
2806
+ module: "bot.grid",
2807
+ description: "Query details of a single grid trading bot by its algo ID. Returns configuration, current status, PnL, and position info.",
2808
+ isWrite: false,
2809
+ inputSchema: {
2810
+ type: "object",
2811
+ properties: {
2812
+ algoOrdType: {
2813
+ type: "string",
2814
+ enum: ["grid", "contract_grid", "moon_grid"],
2815
+ description: "Must match the bot's actual type (use the algoOrdType value returned by grid_get_orders). grid=Spot, contract_grid=Contract, moon_grid=Moon."
2816
+ },
2817
+ algoId: {
2818
+ type: "string",
2819
+ description: "Grid bot algo order ID (returned by grid_create_order or grid_get_orders). This is NOT a normal trade order ID."
2820
+ }
2821
+ },
2822
+ required: ["algoOrdType", "algoId"]
2823
+ },
2824
+ handler: async (rawArgs, context) => {
2825
+ const args = asRecord(rawArgs);
2826
+ const response = await context.client.privateGet(
2827
+ "/api/v5/tradingBot/grid/orders-algo-details",
2828
+ {
2829
+ algoOrdType: requireString(args, "algoOrdType"),
2830
+ algoId: requireString(args, "algoId")
2831
+ },
2832
+ privateRateLimit("grid_get_order_details", 20)
2833
+ );
2834
+ return normalizeResponse(response);
2835
+ }
2836
+ },
2837
+ {
2838
+ name: "grid_get_sub_orders",
2839
+ module: "bot.grid",
2840
+ description: "Query individual sub-orders (grid trades) generated by a grid bot. type='filled' for executed trades; type='live' for pending orders.",
2484
2841
  isWrite: false,
2485
2842
  inputSchema: {
2486
2843
  type: "object",
@@ -3801,9 +4158,266 @@ function registerFuturesTools() {
3801
4158
  }
3802
4159
  },
3803
4160
  {
3804
- name: "futures_cancel_order",
4161
+ name: "futures_cancel_order",
4162
+ module: "futures",
4163
+ description: "Cancel an unfilled FUTURES delivery order.",
4164
+ isWrite: true,
4165
+ inputSchema: {
4166
+ type: "object",
4167
+ properties: {
4168
+ instId: {
4169
+ type: "string",
4170
+ description: "e.g. BTC-USDT-240329"
4171
+ },
4172
+ ordId: {
4173
+ type: "string"
4174
+ },
4175
+ clOrdId: {
4176
+ type: "string",
4177
+ description: "Client order ID"
4178
+ }
4179
+ },
4180
+ required: ["instId"]
4181
+ },
4182
+ handler: async (rawArgs, context) => {
4183
+ const args = asRecord(rawArgs);
4184
+ const response = await context.client.privatePost(
4185
+ "/api/v5/trade/cancel-order",
4186
+ compactObject({
4187
+ instId: requireString(args, "instId"),
4188
+ ordId: readString(args, "ordId"),
4189
+ clOrdId: readString(args, "clOrdId")
4190
+ }),
4191
+ privateRateLimit("futures_cancel_order", 60)
4192
+ );
4193
+ return normalizeResponse(response);
4194
+ }
4195
+ },
4196
+ {
4197
+ name: "futures_get_order",
4198
+ module: "futures",
4199
+ description: "Get details of a single FUTURES delivery order by ordId or clOrdId.",
4200
+ isWrite: false,
4201
+ inputSchema: {
4202
+ type: "object",
4203
+ properties: {
4204
+ instId: {
4205
+ type: "string",
4206
+ description: "e.g. BTC-USDT-240329"
4207
+ },
4208
+ ordId: {
4209
+ type: "string",
4210
+ description: "Provide ordId or clOrdId"
4211
+ },
4212
+ clOrdId: {
4213
+ type: "string",
4214
+ description: "Provide ordId or clOrdId"
4215
+ }
4216
+ },
4217
+ required: ["instId"]
4218
+ },
4219
+ handler: async (rawArgs, context) => {
4220
+ const args = asRecord(rawArgs);
4221
+ const response = await context.client.privateGet(
4222
+ "/api/v5/trade/order",
4223
+ compactObject({
4224
+ instId: requireString(args, "instId"),
4225
+ ordId: readString(args, "ordId"),
4226
+ clOrdId: readString(args, "clOrdId")
4227
+ }),
4228
+ privateRateLimit("futures_get_order", 60)
4229
+ );
4230
+ return normalizeResponse(response);
4231
+ }
4232
+ },
4233
+ {
4234
+ name: "futures_get_orders",
4235
+ module: "futures",
4236
+ description: "Query FUTURES open orders, history (last 7 days), or archive (up to 3 months).",
4237
+ isWrite: false,
4238
+ inputSchema: {
4239
+ type: "object",
4240
+ properties: {
4241
+ status: {
4242
+ type: "string",
4243
+ enum: ["open", "history", "archive"],
4244
+ description: "open=active, history=7d, archive=3mo"
4245
+ },
4246
+ instType: {
4247
+ type: "string",
4248
+ enum: [...FUTURES_INST_TYPES],
4249
+ description: "FUTURES (default) or SWAP"
4250
+ },
4251
+ instId: {
4252
+ type: "string",
4253
+ description: "e.g. BTC-USDT-240329"
4254
+ },
4255
+ ordType: {
4256
+ type: "string",
4257
+ description: "Order type filter"
4258
+ },
4259
+ state: {
4260
+ type: "string",
4261
+ description: "canceled|filled"
4262
+ },
4263
+ after: {
4264
+ type: "string",
4265
+ description: "Pagination: before this order ID"
4266
+ },
4267
+ before: {
4268
+ type: "string",
4269
+ description: "Pagination: after this order ID"
4270
+ },
4271
+ begin: {
4272
+ type: "string",
4273
+ description: "Start time (ms)"
4274
+ },
4275
+ end: {
4276
+ type: "string",
4277
+ description: "End time (ms)"
4278
+ },
4279
+ limit: {
4280
+ type: "number",
4281
+ description: "Max results (default 100)"
4282
+ }
4283
+ }
4284
+ },
4285
+ handler: async (rawArgs, context) => {
4286
+ const args = asRecord(rawArgs);
4287
+ const status = readString(args, "status") ?? "open";
4288
+ const instType = readString(args, "instType") ?? "FUTURES";
4289
+ assertEnum(instType, "instType", FUTURES_INST_TYPES);
4290
+ const path4 = status === "archive" ? "/api/v5/trade/orders-history-archive" : status === "history" ? "/api/v5/trade/orders-history" : "/api/v5/trade/orders-pending";
4291
+ const response = await context.client.privateGet(
4292
+ path4,
4293
+ compactObject({
4294
+ instType,
4295
+ instId: readString(args, "instId"),
4296
+ ordType: readString(args, "ordType"),
4297
+ state: readString(args, "state"),
4298
+ after: readString(args, "after"),
4299
+ before: readString(args, "before"),
4300
+ begin: readString(args, "begin"),
4301
+ end: readString(args, "end"),
4302
+ limit: readNumber(args, "limit")
4303
+ }),
4304
+ privateRateLimit("futures_get_orders", 20)
4305
+ );
4306
+ return normalizeResponse(response);
4307
+ }
4308
+ },
4309
+ {
4310
+ name: "futures_get_positions",
4311
+ module: "futures",
4312
+ description: "Get current FUTURES delivery contract positions.",
4313
+ isWrite: false,
4314
+ inputSchema: {
4315
+ type: "object",
4316
+ properties: {
4317
+ instType: {
4318
+ type: "string",
4319
+ enum: [...FUTURES_INST_TYPES],
4320
+ description: "FUTURES (default) or SWAP"
4321
+ },
4322
+ instId: {
4323
+ type: "string",
4324
+ description: "e.g. BTC-USDT-240329"
4325
+ },
4326
+ posId: {
4327
+ type: "string"
4328
+ }
4329
+ }
4330
+ },
4331
+ handler: async (rawArgs, context) => {
4332
+ const args = asRecord(rawArgs);
4333
+ const instType = readString(args, "instType") ?? "FUTURES";
4334
+ assertEnum(instType, "instType", FUTURES_INST_TYPES);
4335
+ const response = await context.client.privateGet(
4336
+ "/api/v5/account/positions",
4337
+ compactObject({
4338
+ instType,
4339
+ instId: readString(args, "instId"),
4340
+ posId: readString(args, "posId")
4341
+ }),
4342
+ privateRateLimit("futures_get_positions", 10)
4343
+ );
4344
+ return normalizeResponse(response);
4345
+ }
4346
+ },
4347
+ {
4348
+ name: "futures_get_fills",
4349
+ module: "futures",
4350
+ description: "Get FUTURES fill details. archive=false: last 3 days; archive=true: up to 3 months.",
4351
+ isWrite: false,
4352
+ inputSchema: {
4353
+ type: "object",
4354
+ properties: {
4355
+ archive: {
4356
+ type: "boolean",
4357
+ description: "true=up to 3 months; false=last 3 days (default)"
4358
+ },
4359
+ instType: {
4360
+ type: "string",
4361
+ enum: [...FUTURES_INST_TYPES],
4362
+ description: "FUTURES (default) or SWAP"
4363
+ },
4364
+ instId: {
4365
+ type: "string",
4366
+ description: "Instrument ID filter"
4367
+ },
4368
+ ordId: {
4369
+ type: "string",
4370
+ description: "Order ID filter"
4371
+ },
4372
+ after: {
4373
+ type: "string",
4374
+ description: "Pagination: before this bill ID"
4375
+ },
4376
+ before: {
4377
+ type: "string",
4378
+ description: "Pagination: after this bill ID"
4379
+ },
4380
+ begin: {
4381
+ type: "string",
4382
+ description: "Start time (ms)"
4383
+ },
4384
+ end: {
4385
+ type: "string",
4386
+ description: "End time (ms)"
4387
+ },
4388
+ limit: {
4389
+ type: "number",
4390
+ description: "Max results (default 100 or 20 for archive)"
4391
+ }
4392
+ }
4393
+ },
4394
+ handler: async (rawArgs, context) => {
4395
+ const args = asRecord(rawArgs);
4396
+ const archive = readBoolean(args, "archive") ?? false;
4397
+ const instType = readString(args, "instType") ?? "FUTURES";
4398
+ assertEnum(instType, "instType", FUTURES_INST_TYPES);
4399
+ const path4 = archive ? "/api/v5/trade/fills-history" : "/api/v5/trade/fills";
4400
+ const response = await context.client.privateGet(
4401
+ path4,
4402
+ compactObject({
4403
+ instType,
4404
+ instId: readString(args, "instId"),
4405
+ ordId: readString(args, "ordId"),
4406
+ after: readString(args, "after"),
4407
+ before: readString(args, "before"),
4408
+ begin: readString(args, "begin"),
4409
+ end: readString(args, "end"),
4410
+ limit: readNumber(args, "limit") ?? (archive ? 20 : void 0)
4411
+ }),
4412
+ privateRateLimit("futures_get_fills", 20)
4413
+ );
4414
+ return normalizeResponse(response);
4415
+ }
4416
+ },
4417
+ {
4418
+ name: "futures_amend_order",
3805
4419
  module: "futures",
3806
- description: "Cancel an unfilled FUTURES delivery order.",
4420
+ description: "Amend an unfilled FUTURES delivery order (modify price and/or size).",
3807
4421
  isWrite: true,
3808
4422
  inputSchema: {
3809
4423
  type: "object",
@@ -3813,11 +4427,20 @@ function registerFuturesTools() {
3813
4427
  description: "e.g. BTC-USDT-240329"
3814
4428
  },
3815
4429
  ordId: {
3816
- type: "string"
4430
+ type: "string",
4431
+ description: "Provide ordId or clOrdId"
3817
4432
  },
3818
4433
  clOrdId: {
3819
4434
  type: "string",
3820
- description: "Client order ID"
4435
+ description: "Provide ordId or clOrdId"
4436
+ },
4437
+ newSz: {
4438
+ type: "string",
4439
+ description: "New number of contracts"
4440
+ },
4441
+ newPx: {
4442
+ type: "string",
4443
+ description: "New price"
3821
4444
  }
3822
4445
  },
3823
4446
  required: ["instId"]
@@ -3825,22 +4448,24 @@ function registerFuturesTools() {
3825
4448
  handler: async (rawArgs, context) => {
3826
4449
  const args = asRecord(rawArgs);
3827
4450
  const response = await context.client.privatePost(
3828
- "/api/v5/trade/cancel-order",
4451
+ "/api/v5/trade/amend-order",
3829
4452
  compactObject({
3830
4453
  instId: requireString(args, "instId"),
3831
4454
  ordId: readString(args, "ordId"),
3832
- clOrdId: readString(args, "clOrdId")
4455
+ clOrdId: readString(args, "clOrdId"),
4456
+ newSz: readString(args, "newSz"),
4457
+ newPx: readString(args, "newPx")
3833
4458
  }),
3834
- privateRateLimit("futures_cancel_order", 60)
4459
+ privateRateLimit("futures_amend_order", 60)
3835
4460
  );
3836
4461
  return normalizeResponse(response);
3837
4462
  }
3838
4463
  },
3839
4464
  {
3840
- name: "futures_get_order",
4465
+ name: "futures_close_position",
3841
4466
  module: "futures",
3842
- description: "Get details of a single FUTURES delivery order by ordId or clOrdId.",
3843
- isWrite: false,
4467
+ description: "[CAUTION] Close an entire FUTURES delivery position at market. Private. Rate limit: 20 req/s.",
4468
+ isWrite: true,
3844
4469
  inputSchema: {
3845
4470
  type: "object",
3846
4471
  properties: {
@@ -3848,211 +4473,225 @@ function registerFuturesTools() {
3848
4473
  type: "string",
3849
4474
  description: "e.g. BTC-USDT-240329"
3850
4475
  },
3851
- ordId: {
4476
+ mgnMode: {
3852
4477
  type: "string",
3853
- description: "Provide ordId or clOrdId"
4478
+ enum: ["cross", "isolated"]
4479
+ },
4480
+ posSide: {
4481
+ type: "string",
4482
+ enum: ["long", "short", "net"],
4483
+ description: "long/short=hedge mode; omit for one-way (net)"
4484
+ },
4485
+ autoCxl: {
4486
+ type: "boolean",
4487
+ description: "Cancel pending orders for this instrument on close"
3854
4488
  },
3855
4489
  clOrdId: {
3856
4490
  type: "string",
3857
- description: "Provide ordId or clOrdId"
4491
+ description: "Client order ID for close order"
3858
4492
  }
3859
4493
  },
3860
- required: ["instId"]
4494
+ required: ["instId", "mgnMode"]
3861
4495
  },
3862
4496
  handler: async (rawArgs, context) => {
3863
4497
  const args = asRecord(rawArgs);
3864
- const response = await context.client.privateGet(
3865
- "/api/v5/trade/order",
4498
+ const autoCxl = args.autoCxl;
4499
+ const response = await context.client.privatePost(
4500
+ "/api/v5/trade/close-position",
3866
4501
  compactObject({
3867
4502
  instId: requireString(args, "instId"),
3868
- ordId: readString(args, "ordId"),
3869
- clOrdId: readString(args, "clOrdId")
4503
+ mgnMode: requireString(args, "mgnMode"),
4504
+ posSide: readString(args, "posSide"),
4505
+ autoCxl: typeof autoCxl === "boolean" ? String(autoCxl) : void 0,
4506
+ clOrdId: readString(args, "clOrdId"),
4507
+ tag: context.config.sourceTag
3870
4508
  }),
3871
- privateRateLimit("futures_get_order", 60)
4509
+ privateRateLimit("futures_close_position", 20)
3872
4510
  );
3873
4511
  return normalizeResponse(response);
3874
4512
  }
3875
4513
  },
3876
4514
  {
3877
- name: "futures_get_orders",
4515
+ name: "futures_set_leverage",
3878
4516
  module: "futures",
3879
- description: "Query FUTURES open orders, history (last 7 days), or archive (up to 3 months).",
3880
- isWrite: false,
4517
+ description: "Set leverage for a FUTURES delivery instrument or position. [CAUTION] Changes risk parameters.",
4518
+ isWrite: true,
3881
4519
  inputSchema: {
3882
4520
  type: "object",
3883
4521
  properties: {
3884
- status: {
3885
- type: "string",
3886
- enum: ["open", "history", "archive"],
3887
- description: "open=active, history=7d, archive=3mo"
3888
- },
3889
- instType: {
3890
- type: "string",
3891
- enum: [...FUTURES_INST_TYPES],
3892
- description: "FUTURES (default) or SWAP"
3893
- },
3894
4522
  instId: {
3895
4523
  type: "string",
3896
4524
  description: "e.g. BTC-USDT-240329"
3897
4525
  },
3898
- ordType: {
3899
- type: "string",
3900
- description: "Order type filter"
3901
- },
3902
- state: {
3903
- type: "string",
3904
- description: "canceled|filled"
3905
- },
3906
- after: {
3907
- type: "string",
3908
- description: "Pagination: before this order ID"
3909
- },
3910
- before: {
4526
+ lever: {
3911
4527
  type: "string",
3912
- description: "Pagination: after this order ID"
4528
+ description: "Leverage, e.g. '10'"
3913
4529
  },
3914
- begin: {
4530
+ mgnMode: {
3915
4531
  type: "string",
3916
- description: "Start time (ms)"
4532
+ enum: ["cross", "isolated"]
3917
4533
  },
3918
- end: {
4534
+ posSide: {
3919
4535
  type: "string",
3920
- description: "End time (ms)"
3921
- },
3922
- limit: {
3923
- type: "number",
3924
- description: "Max results (default 100)"
4536
+ enum: ["long", "short", "net"],
4537
+ description: "Required for isolated margin in hedge mode"
3925
4538
  }
3926
- }
4539
+ },
4540
+ required: ["instId", "lever", "mgnMode"]
3927
4541
  },
3928
4542
  handler: async (rawArgs, context) => {
3929
4543
  const args = asRecord(rawArgs);
3930
- const status = readString(args, "status") ?? "open";
3931
- const instType = readString(args, "instType") ?? "FUTURES";
3932
- assertEnum(instType, "instType", FUTURES_INST_TYPES);
3933
- const path4 = status === "archive" ? "/api/v5/trade/orders-history-archive" : status === "history" ? "/api/v5/trade/orders-history" : "/api/v5/trade/orders-pending";
3934
- const response = await context.client.privateGet(
3935
- path4,
4544
+ const response = await context.client.privatePost(
4545
+ "/api/v5/account/set-leverage",
3936
4546
  compactObject({
3937
- instType,
3938
- instId: readString(args, "instId"),
3939
- ordType: readString(args, "ordType"),
3940
- state: readString(args, "state"),
3941
- after: readString(args, "after"),
3942
- before: readString(args, "before"),
3943
- begin: readString(args, "begin"),
3944
- end: readString(args, "end"),
3945
- limit: readNumber(args, "limit")
4547
+ instId: requireString(args, "instId"),
4548
+ lever: requireString(args, "lever"),
4549
+ mgnMode: requireString(args, "mgnMode"),
4550
+ posSide: readString(args, "posSide")
3946
4551
  }),
3947
- privateRateLimit("futures_get_orders", 20)
4552
+ privateRateLimit("futures_set_leverage", 20)
3948
4553
  );
3949
4554
  return normalizeResponse(response);
3950
4555
  }
3951
4556
  },
3952
4557
  {
3953
- name: "futures_get_positions",
4558
+ name: "futures_get_leverage",
3954
4559
  module: "futures",
3955
- description: "Get current FUTURES delivery contract positions.",
4560
+ description: "Get current leverage for a FUTURES delivery instrument.",
3956
4561
  isWrite: false,
3957
4562
  inputSchema: {
3958
4563
  type: "object",
3959
4564
  properties: {
3960
- instType: {
3961
- type: "string",
3962
- enum: [...FUTURES_INST_TYPES],
3963
- description: "FUTURES (default) or SWAP"
3964
- },
3965
4565
  instId: {
3966
4566
  type: "string",
3967
4567
  description: "e.g. BTC-USDT-240329"
3968
4568
  },
3969
- posId: {
3970
- type: "string"
4569
+ mgnMode: {
4570
+ type: "string",
4571
+ enum: ["cross", "isolated"]
3971
4572
  }
3972
- }
4573
+ },
4574
+ required: ["instId", "mgnMode"]
3973
4575
  },
3974
4576
  handler: async (rawArgs, context) => {
3975
4577
  const args = asRecord(rawArgs);
3976
- const instType = readString(args, "instType") ?? "FUTURES";
3977
- assertEnum(instType, "instType", FUTURES_INST_TYPES);
3978
4578
  const response = await context.client.privateGet(
3979
- "/api/v5/account/positions",
4579
+ "/api/v5/account/leverage-info",
3980
4580
  compactObject({
3981
- instType,
3982
- instId: readString(args, "instId"),
3983
- posId: readString(args, "posId")
4581
+ instId: requireString(args, "instId"),
4582
+ mgnMode: requireString(args, "mgnMode")
3984
4583
  }),
3985
- privateRateLimit("futures_get_positions", 10)
4584
+ privateRateLimit("futures_get_leverage", 20)
3986
4585
  );
3987
4586
  return normalizeResponse(response);
3988
4587
  }
3989
4588
  },
3990
4589
  {
3991
- name: "futures_get_fills",
4590
+ name: "futures_batch_orders",
3992
4591
  module: "futures",
3993
- description: "Get FUTURES fill details. archive=false: last 3 days; archive=true: up to 3 months.",
3994
- isWrite: false,
4592
+ description: "[CAUTION] Batch place up to 20 FUTURES delivery orders in one request. Private. Rate limit: 60 req/s.",
4593
+ isWrite: true,
3995
4594
  inputSchema: {
3996
4595
  type: "object",
3997
4596
  properties: {
3998
- archive: {
3999
- type: "boolean",
4000
- description: "true=up to 3 months; false=last 3 days (default)"
4001
- },
4002
- instType: {
4003
- type: "string",
4004
- enum: [...FUTURES_INST_TYPES],
4005
- description: "FUTURES (default) or SWAP"
4006
- },
4007
- instId: {
4008
- type: "string",
4009
- description: "Instrument ID filter"
4010
- },
4011
- ordId: {
4012
- type: "string",
4013
- description: "Order ID filter"
4014
- },
4015
- after: {
4016
- type: "string",
4017
- description: "Pagination: before this bill ID"
4018
- },
4019
- before: {
4020
- type: "string",
4021
- description: "Pagination: after this bill ID"
4022
- },
4023
- begin: {
4024
- type: "string",
4025
- description: "Start time (ms)"
4026
- },
4027
- end: {
4028
- type: "string",
4029
- description: "End time (ms)"
4030
- },
4031
- limit: {
4032
- type: "number",
4033
- description: "Max results (default 100 or 20 for archive)"
4597
+ orders: {
4598
+ type: "array",
4599
+ description: "Array (max 20): {instId,tdMode,side,ordType,sz,px?,posSide?,reduceOnly?,clOrdId?,tpTriggerPx?,tpOrdPx?,slTriggerPx?,slOrdPx?}",
4600
+ items: {
4601
+ type: "object"
4602
+ }
4603
+ }
4604
+ },
4605
+ required: ["orders"]
4606
+ },
4607
+ handler: async (rawArgs, context) => {
4608
+ const args = asRecord(rawArgs);
4609
+ const orders = args.orders;
4610
+ if (!Array.isArray(orders) || orders.length === 0) {
4611
+ throw new Error("orders must be a non-empty array.");
4612
+ }
4613
+ const body = orders.map((order) => {
4614
+ const o = asRecord(order);
4615
+ const attachAlgoOrds = buildAttachAlgoOrds(o);
4616
+ const reduceOnly = o.reduceOnly;
4617
+ return compactObject({
4618
+ instId: requireString(o, "instId"),
4619
+ tdMode: requireString(o, "tdMode"),
4620
+ side: requireString(o, "side"),
4621
+ ordType: requireString(o, "ordType"),
4622
+ sz: requireString(o, "sz"),
4623
+ px: readString(o, "px"),
4624
+ posSide: readString(o, "posSide"),
4625
+ reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
4626
+ clOrdId: readString(o, "clOrdId"),
4627
+ tag: context.config.sourceTag,
4628
+ attachAlgoOrds
4629
+ });
4630
+ });
4631
+ const response = await context.client.privatePost(
4632
+ "/api/v5/trade/batch-orders",
4633
+ body,
4634
+ privateRateLimit("futures_batch_orders", 60)
4635
+ );
4636
+ return normalizeResponse(response);
4637
+ }
4638
+ },
4639
+ {
4640
+ name: "futures_batch_amend",
4641
+ module: "futures",
4642
+ description: "[CAUTION] Batch amend up to 20 unfilled FUTURES delivery orders in one request.",
4643
+ isWrite: true,
4644
+ inputSchema: {
4645
+ type: "object",
4646
+ properties: {
4647
+ orders: {
4648
+ type: "array",
4649
+ description: "Array (max 20): {instId, ordId?, clOrdId?, newSz?, newPx?}",
4650
+ items: { type: "object" }
4651
+ }
4652
+ },
4653
+ required: ["orders"]
4654
+ },
4655
+ handler: async (rawArgs, context) => {
4656
+ const args = asRecord(rawArgs);
4657
+ const orders = args.orders;
4658
+ if (!Array.isArray(orders) || orders.length === 0) {
4659
+ throw new Error("orders must be a non-empty array.");
4660
+ }
4661
+ const response = await context.client.privatePost(
4662
+ "/api/v5/trade/amend-batch-orders",
4663
+ orders,
4664
+ privateRateLimit("futures_batch_amend", 60)
4665
+ );
4666
+ return normalizeResponse(response);
4667
+ }
4668
+ },
4669
+ {
4670
+ name: "futures_batch_cancel",
4671
+ module: "futures",
4672
+ description: "[CAUTION] Batch cancel up to 20 FUTURES delivery orders in one request.",
4673
+ isWrite: true,
4674
+ inputSchema: {
4675
+ type: "object",
4676
+ properties: {
4677
+ orders: {
4678
+ type: "array",
4679
+ description: "Array (max 20): {instId, ordId?, clOrdId?}",
4680
+ items: { type: "object" }
4034
4681
  }
4035
- }
4682
+ },
4683
+ required: ["orders"]
4036
4684
  },
4037
4685
  handler: async (rawArgs, context) => {
4038
4686
  const args = asRecord(rawArgs);
4039
- const archive = readBoolean(args, "archive") ?? false;
4040
- const instType = readString(args, "instType") ?? "FUTURES";
4041
- assertEnum(instType, "instType", FUTURES_INST_TYPES);
4042
- const path4 = archive ? "/api/v5/trade/fills-history" : "/api/v5/trade/fills";
4043
- const response = await context.client.privateGet(
4044
- path4,
4045
- compactObject({
4046
- instType,
4047
- instId: readString(args, "instId"),
4048
- ordId: readString(args, "ordId"),
4049
- after: readString(args, "after"),
4050
- before: readString(args, "before"),
4051
- begin: readString(args, "begin"),
4052
- end: readString(args, "end"),
4053
- limit: readNumber(args, "limit") ?? (archive ? 20 : void 0)
4054
- }),
4055
- privateRateLimit("futures_get_fills", 20)
4687
+ const orders = args.orders;
4688
+ if (!Array.isArray(orders) || orders.length === 0) {
4689
+ throw new Error("orders must be a non-empty array.");
4690
+ }
4691
+ const response = await context.client.privatePost(
4692
+ "/api/v5/trade/cancel-batch-orders",
4693
+ orders,
4694
+ privateRateLimit("futures_batch_cancel", 60)
4056
4695
  );
4057
4696
  return normalizeResponse(response);
4058
4697
  }
@@ -4465,103 +5104,360 @@ function registerMarketTools() {
4465
5104
  }
4466
5105
  },
4467
5106
  {
4468
- name: "market_get_price_limit",
4469
- module: "market",
4470
- description: "Get the current price limit (upper and lower bands) for a SWAP or FUTURES instrument. Orders outside these limits will be rejected.",
4471
- isWrite: false,
5107
+ name: "market_get_price_limit",
5108
+ module: "market",
5109
+ description: "Get the current price limit (upper and lower bands) for a SWAP or FUTURES instrument. Orders outside these limits will be rejected.",
5110
+ isWrite: false,
5111
+ inputSchema: {
5112
+ type: "object",
5113
+ properties: {
5114
+ instId: {
5115
+ type: "string",
5116
+ description: "SWAP or FUTURES ID, e.g. BTC-USDT-SWAP"
5117
+ }
5118
+ },
5119
+ required: ["instId"]
5120
+ },
5121
+ handler: async (rawArgs, context) => {
5122
+ const args = asRecord(rawArgs);
5123
+ const response = await context.client.publicGet(
5124
+ "/api/v5/public/price-limit",
5125
+ { instId: requireString(args, "instId") },
5126
+ publicRateLimit("market_get_price_limit", 20)
5127
+ );
5128
+ return normalizeResponse(response);
5129
+ }
5130
+ },
5131
+ {
5132
+ name: "market_get_open_interest",
5133
+ module: "market",
5134
+ description: "Get open interest for SWAP, FUTURES, or OPTION instruments. Useful for gauging market sentiment and positioning.",
5135
+ isWrite: false,
5136
+ inputSchema: {
5137
+ type: "object",
5138
+ properties: {
5139
+ instType: {
5140
+ type: "string",
5141
+ enum: ["SWAP", "FUTURES", "OPTION"]
5142
+ },
5143
+ instId: {
5144
+ type: "string",
5145
+ description: "e.g. BTC-USDT-SWAP"
5146
+ },
5147
+ uly: {
5148
+ type: "string",
5149
+ description: "e.g. BTC-USD"
5150
+ },
5151
+ instFamily: {
5152
+ type: "string"
5153
+ }
5154
+ },
5155
+ required: ["instType"]
5156
+ },
5157
+ handler: async (rawArgs, context) => {
5158
+ const args = asRecord(rawArgs);
5159
+ const response = await context.client.publicGet(
5160
+ "/api/v5/public/open-interest",
5161
+ compactObject({
5162
+ instType: requireString(args, "instType"),
5163
+ instId: readString(args, "instId"),
5164
+ uly: readString(args, "uly"),
5165
+ instFamily: readString(args, "instFamily")
5166
+ }),
5167
+ publicRateLimit("market_get_open_interest", 20)
5168
+ );
5169
+ return normalizeResponse(response);
5170
+ }
5171
+ },
5172
+ {
5173
+ name: "market_get_stock_tokens",
5174
+ module: "market",
5175
+ description: "Get all stock token instruments (instCategory=3). Stock tokens track real-world stock prices on OKX (e.g. AAPL-USDT-SWAP). Filters client-side by instCategory=3.",
5176
+ isWrite: false,
5177
+ inputSchema: {
5178
+ type: "object",
5179
+ properties: {
5180
+ instType: {
5181
+ type: "string",
5182
+ enum: ["SPOT", "SWAP"],
5183
+ description: "Instrument type. Default: SWAP"
5184
+ },
5185
+ instId: {
5186
+ type: "string",
5187
+ description: "Optional: filter by specific instrument ID, e.g. AAPL-USDT-SWAP"
5188
+ }
5189
+ },
5190
+ required: []
5191
+ },
5192
+ handler: async (rawArgs, context) => {
5193
+ const args = asRecord(rawArgs);
5194
+ const instType = readString(args, "instType") ?? "SWAP";
5195
+ const instId = readString(args, "instId");
5196
+ const response = await context.client.publicGet(
5197
+ "/api/v5/public/instruments",
5198
+ compactObject({ instType, instId }),
5199
+ publicRateLimit("market_get_stock_tokens", 20)
5200
+ );
5201
+ const data = response.data;
5202
+ const filtered = Array.isArray(data) ? data.filter((item) => item.instCategory === "3") : data;
5203
+ return normalizeResponse({ ...response, data: filtered });
5204
+ }
5205
+ }
5206
+ ];
5207
+ }
5208
+ function registerOptionAlgoTools() {
5209
+ return [
5210
+ {
5211
+ name: "option_place_algo_order",
5212
+ module: "option",
5213
+ description: "Place an OPTION algo order: TP/SL (conditional/oco). [CAUTION] Executes real trades. conditional: single TP, single SL, or both on one order. oco: TP+SL simultaneously \u2014 first trigger cancels the other. Set tpOrdPx='-1' or slOrdPx='-1' for market execution.",
5214
+ isWrite: true,
5215
+ inputSchema: {
5216
+ type: "object",
5217
+ properties: {
5218
+ instId: {
5219
+ type: "string",
5220
+ description: "e.g. BTC-USD-241227-50000-C"
5221
+ },
5222
+ tdMode: {
5223
+ type: "string",
5224
+ enum: ["cash", "cross", "isolated"],
5225
+ description: "cash=buyer full premium; cross/isolated=seller margin"
5226
+ },
5227
+ side: {
5228
+ type: "string",
5229
+ enum: ["buy", "sell"],
5230
+ description: "sell=close long, buy=close short"
5231
+ },
5232
+ ordType: {
5233
+ type: "string",
5234
+ enum: ["conditional", "oco"],
5235
+ description: "conditional=single TP/SL or both; oco=TP+SL pair (first trigger cancels other)"
5236
+ },
5237
+ sz: {
5238
+ type: "string",
5239
+ description: "Number of contracts (NOT USDT amount). Use market_get_instruments to get ctVal for conversion."
5240
+ },
5241
+ tpTriggerPx: {
5242
+ type: "string",
5243
+ description: "TP trigger price (conditional/oco only)"
5244
+ },
5245
+ tpOrdPx: {
5246
+ type: "string",
5247
+ description: "TP order price; -1=market (conditional/oco only)"
5248
+ },
5249
+ tpTriggerPxType: {
5250
+ type: "string",
5251
+ enum: ["last", "index", "mark"],
5252
+ description: "last(default)|index|mark (conditional/oco only)"
5253
+ },
5254
+ slTriggerPx: {
5255
+ type: "string",
5256
+ description: "SL trigger price (conditional/oco only)"
5257
+ },
5258
+ slOrdPx: {
5259
+ type: "string",
5260
+ description: "SL order price; -1=market (recommended) (conditional/oco only)"
5261
+ },
5262
+ slTriggerPxType: {
5263
+ type: "string",
5264
+ enum: ["last", "index", "mark"],
5265
+ description: "last(default)|index|mark (conditional/oco only)"
5266
+ },
5267
+ reduceOnly: {
5268
+ type: "boolean",
5269
+ description: "Ensure order only reduces position"
5270
+ },
5271
+ clOrdId: {
5272
+ type: "string",
5273
+ description: "Client order ID (max 32 chars)"
5274
+ }
5275
+ },
5276
+ required: ["instId", "tdMode", "side", "ordType", "sz"]
5277
+ },
5278
+ handler: async (rawArgs, context) => {
5279
+ const args = asRecord(rawArgs);
5280
+ const reduceOnly = readBoolean(args, "reduceOnly");
5281
+ const response = await context.client.privatePost(
5282
+ "/api/v5/trade/order-algo",
5283
+ compactObject({
5284
+ instId: requireString(args, "instId"),
5285
+ tdMode: requireString(args, "tdMode"),
5286
+ side: requireString(args, "side"),
5287
+ ordType: requireString(args, "ordType"),
5288
+ sz: requireString(args, "sz"),
5289
+ tpTriggerPx: readString(args, "tpTriggerPx"),
5290
+ tpOrdPx: readString(args, "tpOrdPx"),
5291
+ tpTriggerPxType: readString(args, "tpTriggerPxType"),
5292
+ slTriggerPx: readString(args, "slTriggerPx"),
5293
+ slOrdPx: readString(args, "slOrdPx"),
5294
+ slTriggerPxType: readString(args, "slTriggerPxType"),
5295
+ reduceOnly: reduceOnly !== void 0 ? String(reduceOnly) : void 0,
5296
+ clOrdId: readString(args, "clOrdId"),
5297
+ tag: context.config.sourceTag
5298
+ }),
5299
+ privateRateLimit("option_place_algo_order", 20)
5300
+ );
5301
+ return normalizeResponse(response);
5302
+ }
5303
+ },
5304
+ {
5305
+ name: "option_amend_algo_order",
5306
+ module: "option",
5307
+ description: "Amend a pending OPTION algo order (modify TP/SL prices or size).",
5308
+ isWrite: true,
5309
+ inputSchema: {
5310
+ type: "object",
5311
+ properties: {
5312
+ instId: { type: "string", description: "e.g. BTC-USD-241227-50000-C" },
5313
+ algoId: { type: "string", description: "Algo order ID" },
5314
+ newSz: { type: "string", description: "New number of contracts" },
5315
+ newTpTriggerPx: { type: "string", description: "New TP trigger price" },
5316
+ newTpOrdPx: { type: "string", description: "New TP order price; -1=market" },
5317
+ newSlTriggerPx: { type: "string", description: "New SL trigger price" },
5318
+ newSlOrdPx: { type: "string", description: "New SL order price; -1=market" }
5319
+ },
5320
+ required: ["instId", "algoId"]
5321
+ },
5322
+ handler: async (rawArgs, context) => {
5323
+ const args = asRecord(rawArgs);
5324
+ const response = await context.client.privatePost(
5325
+ "/api/v5/trade/amend-algos",
5326
+ compactObject({
5327
+ instId: requireString(args, "instId"),
5328
+ algoId: requireString(args, "algoId"),
5329
+ newSz: readString(args, "newSz"),
5330
+ newTpTriggerPx: readString(args, "newTpTriggerPx"),
5331
+ newTpOrdPx: readString(args, "newTpOrdPx"),
5332
+ newSlTriggerPx: readString(args, "newSlTriggerPx"),
5333
+ newSlOrdPx: readString(args, "newSlOrdPx")
5334
+ }),
5335
+ privateRateLimit("option_amend_algo_order", 20)
5336
+ );
5337
+ return normalizeResponse(response);
5338
+ }
5339
+ },
5340
+ {
5341
+ name: "option_cancel_algo_orders",
5342
+ module: "option",
5343
+ description: "Cancel one or more pending OPTION algo orders (TP/SL). Accepts a list of {algoId, instId} objects.",
5344
+ isWrite: true,
4472
5345
  inputSchema: {
4473
5346
  type: "object",
4474
5347
  properties: {
4475
- instId: {
4476
- type: "string",
4477
- description: "SWAP or FUTURES ID, e.g. BTC-USDT-SWAP"
5348
+ orders: {
5349
+ type: "array",
5350
+ description: "List of algo orders to cancel. Each item: {algoId, instId}.",
5351
+ items: {
5352
+ type: "object",
5353
+ properties: {
5354
+ algoId: {
5355
+ type: "string",
5356
+ description: "Algo order ID"
5357
+ },
5358
+ instId: {
5359
+ type: "string",
5360
+ description: "e.g. BTC-USD-241227-50000-C"
5361
+ }
5362
+ },
5363
+ required: ["algoId", "instId"]
5364
+ }
4478
5365
  }
4479
5366
  },
4480
- required: ["instId"]
5367
+ required: ["orders"]
4481
5368
  },
4482
5369
  handler: async (rawArgs, context) => {
4483
5370
  const args = asRecord(rawArgs);
4484
- const response = await context.client.publicGet(
4485
- "/api/v5/public/price-limit",
4486
- { instId: requireString(args, "instId") },
4487
- publicRateLimit("market_get_price_limit", 20)
5371
+ const orders = args.orders;
5372
+ if (!Array.isArray(orders) || orders.length === 0) {
5373
+ throw new Error("orders must be a non-empty array.");
5374
+ }
5375
+ const response = await context.client.privatePost(
5376
+ "/api/v5/trade/cancel-algos",
5377
+ orders,
5378
+ privateRateLimit("option_cancel_algo_orders", 20)
4488
5379
  );
4489
5380
  return normalizeResponse(response);
4490
5381
  }
4491
5382
  },
4492
5383
  {
4493
- name: "market_get_open_interest",
4494
- module: "market",
4495
- description: "Get open interest for SWAP, FUTURES, or OPTION instruments. Useful for gauging market sentiment and positioning.",
5384
+ name: "option_get_algo_orders",
5385
+ module: "option",
5386
+ description: "Query pending or completed OPTION algo orders (TP/SL, OCO).",
4496
5387
  isWrite: false,
4497
5388
  inputSchema: {
4498
5389
  type: "object",
4499
5390
  properties: {
4500
- instType: {
5391
+ status: {
4501
5392
  type: "string",
4502
- enum: ["SWAP", "FUTURES", "OPTION"]
5393
+ enum: ["pending", "history"],
5394
+ description: "pending=active (default); history=completed"
5395
+ },
5396
+ ordType: {
5397
+ type: "string",
5398
+ enum: ["conditional", "oco"],
5399
+ description: "Filter by type; omit for all"
4503
5400
  },
4504
5401
  instId: {
4505
5402
  type: "string",
4506
- description: "e.g. BTC-USDT-SWAP"
5403
+ description: "Instrument ID filter"
4507
5404
  },
4508
- uly: {
5405
+ algoId: {
4509
5406
  type: "string",
4510
- description: "e.g. BTC-USD"
5407
+ description: "Filter by algo order ID"
4511
5408
  },
4512
- instFamily: {
4513
- type: "string"
4514
- }
4515
- },
4516
- required: ["instType"]
4517
- },
4518
- handler: async (rawArgs, context) => {
4519
- const args = asRecord(rawArgs);
4520
- const response = await context.client.publicGet(
4521
- "/api/v5/public/open-interest",
4522
- compactObject({
4523
- instType: requireString(args, "instType"),
4524
- instId: readString(args, "instId"),
4525
- uly: readString(args, "uly"),
4526
- instFamily: readString(args, "instFamily")
4527
- }),
4528
- publicRateLimit("market_get_open_interest", 20)
4529
- );
4530
- return normalizeResponse(response);
4531
- }
4532
- },
4533
- {
4534
- name: "market_get_stock_tokens",
4535
- module: "market",
4536
- description: "Get all stock token instruments (instCategory=3). Stock tokens track real-world stock prices on OKX (e.g. AAPL-USDT-SWAP). Filters client-side by instCategory=3.",
4537
- isWrite: false,
4538
- inputSchema: {
4539
- type: "object",
4540
- properties: {
4541
- instType: {
5409
+ after: {
4542
5410
  type: "string",
4543
- enum: ["SPOT", "SWAP"],
4544
- description: "Instrument type. Default: SWAP"
5411
+ description: "Pagination: before this algo ID"
4545
5412
  },
4546
- instId: {
5413
+ before: {
4547
5414
  type: "string",
4548
- description: "Optional: filter by specific instrument ID, e.g. AAPL-USDT-SWAP"
5415
+ description: "Pagination: after this algo ID"
5416
+ },
5417
+ limit: {
5418
+ type: "number",
5419
+ description: "Max results (default 100)"
5420
+ },
5421
+ state: {
5422
+ type: "string",
5423
+ enum: ["effective", "canceled", "order_failed"],
5424
+ description: "Required when status=history. effective=triggered, canceled, order_failed. Defaults to effective."
4549
5425
  }
4550
- },
4551
- required: []
5426
+ }
4552
5427
  },
4553
5428
  handler: async (rawArgs, context) => {
4554
5429
  const args = asRecord(rawArgs);
4555
- const instType = readString(args, "instType") ?? "SWAP";
4556
- const instId = readString(args, "instId");
4557
- const response = await context.client.publicGet(
4558
- "/api/v5/public/instruments",
4559
- compactObject({ instType, instId }),
4560
- publicRateLimit("market_get_stock_tokens", 20)
4561
- );
4562
- const data = response.data;
4563
- const filtered = Array.isArray(data) ? data.filter((item) => item.instCategory === "3") : data;
4564
- return normalizeResponse({ ...response, data: filtered });
5430
+ const status = readString(args, "status") ?? "pending";
5431
+ const isHistory = status === "history";
5432
+ const path4 = isHistory ? "/api/v5/trade/orders-algo-history" : "/api/v5/trade/orders-algo-pending";
5433
+ const ordType = readString(args, "ordType");
5434
+ const state = isHistory ? readString(args, "state") ?? "effective" : void 0;
5435
+ const baseParams = compactObject({
5436
+ instType: "OPTION",
5437
+ instId: readString(args, "instId"),
5438
+ algoId: readString(args, "algoId"),
5439
+ after: readString(args, "after"),
5440
+ before: readString(args, "before"),
5441
+ limit: readNumber(args, "limit"),
5442
+ state
5443
+ });
5444
+ if (ordType) {
5445
+ const response = await context.client.privateGet(
5446
+ path4,
5447
+ { ...baseParams, ordType },
5448
+ privateRateLimit("option_get_algo_orders", 20)
5449
+ );
5450
+ return normalizeResponse(response);
5451
+ }
5452
+ const [r1, r2] = await Promise.all([
5453
+ context.client.privateGet(path4, { ...baseParams, ordType: "conditional" }, privateRateLimit("option_get_algo_orders", 20)),
5454
+ context.client.privateGet(path4, { ...baseParams, ordType: "oco" }, privateRateLimit("option_get_algo_orders", 20))
5455
+ ]);
5456
+ const merged = [
5457
+ ...r1.data ?? [],
5458
+ ...r2.data ?? []
5459
+ ];
5460
+ return { endpoint: r1.endpoint, requestTime: r1.requestTime, data: merged };
4565
5461
  }
4566
5462
  }
4567
5463
  ];
@@ -4609,6 +5505,22 @@ function registerOptionTools() {
4609
5505
  clOrdId: {
4610
5506
  type: "string",
4611
5507
  description: "Client order ID (max 32 chars)"
5508
+ },
5509
+ tpTriggerPx: {
5510
+ type: "string",
5511
+ description: "TP trigger price; attaches a take-profit algo order"
5512
+ },
5513
+ tpOrdPx: {
5514
+ type: "string",
5515
+ description: "TP order price; -1=market"
5516
+ },
5517
+ slTriggerPx: {
5518
+ type: "string",
5519
+ description: "SL trigger price; attaches a stop-loss algo order"
5520
+ },
5521
+ slOrdPx: {
5522
+ type: "string",
5523
+ description: "SL order price; -1=market (recommended)"
4612
5524
  }
4613
5525
  },
4614
5526
  required: ["instId", "tdMode", "side", "ordType", "sz"]
@@ -4616,6 +5528,7 @@ function registerOptionTools() {
4616
5528
  handler: async (rawArgs, context) => {
4617
5529
  const args = asRecord(rawArgs);
4618
5530
  const reduceOnly = args.reduceOnly;
5531
+ const attachAlgoOrds = buildAttachAlgoOrds(args);
4619
5532
  const response = await context.client.privatePost(
4620
5533
  "/api/v5/trade/order",
4621
5534
  compactObject({
@@ -4627,7 +5540,8 @@ function registerOptionTools() {
4627
5540
  px: readString(args, "px"),
4628
5541
  reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
4629
5542
  clOrdId: readString(args, "clOrdId"),
4630
- tag: context.config.sourceTag
5543
+ tag: context.config.sourceTag,
5544
+ attachAlgoOrds
4631
5545
  }),
4632
5546
  privateRateLimit("option_place_order", 60)
4633
5547
  );
@@ -6265,7 +7179,9 @@ function allToolSpecs() {
6265
7179
  ...registerSpotTradeTools(),
6266
7180
  ...registerSwapTradeTools(),
6267
7181
  ...registerFuturesTools(),
7182
+ ...registerFuturesAlgoTools(),
6268
7183
  ...registerOptionTools(),
7184
+ ...registerOptionAlgoTools(),
6269
7185
  ...registerAlgoTradeTools(),
6270
7186
  ...registerAccountTools(),
6271
7187
  ...registerBotTools(),
@@ -6637,7 +7553,7 @@ function readCliVersion() {
6637
7553
  return "0.0.0";
6638
7554
  }
6639
7555
  var CLI_VERSION = readCliVersion();
6640
- var GIT_HASH = true ? "a880395" : "dev";
7556
+ var GIT_HASH = true ? "836b2ae" : "dev";
6641
7557
  var Report = class {
6642
7558
  lines = [];
6643
7559
  add(key, value) {
@@ -8853,83 +9769,255 @@ async function cmdFuturesPositions(run, instId, json) {
8853
9769
  }))
8854
9770
  );
8855
9771
  }
8856
- async function cmdFuturesFills(run, opts) {
8857
- const result = await run("futures_get_fills", { instId: opts.instId, ordId: opts.ordId, archive: opts.archive });
8858
- const fills = getData5(result);
8859
- if (opts.json) return printJson(fills);
9772
+ async function cmdFuturesFills(run, opts) {
9773
+ const result = await run("futures_get_fills", { instId: opts.instId, ordId: opts.ordId, archive: opts.archive });
9774
+ const fills = getData5(result);
9775
+ if (opts.json) return printJson(fills);
9776
+ printTable(
9777
+ (fills ?? []).map((f) => ({
9778
+ instId: f["instId"],
9779
+ side: f["side"],
9780
+ fillPx: f["fillPx"],
9781
+ fillSz: f["fillSz"],
9782
+ fee: f["fee"],
9783
+ ts: new Date(Number(f["ts"])).toLocaleString()
9784
+ }))
9785
+ );
9786
+ }
9787
+ async function cmdFuturesPlace(run, opts) {
9788
+ const result = await run("futures_place_order", {
9789
+ instId: opts.instId,
9790
+ tdMode: opts.tdMode,
9791
+ side: opts.side,
9792
+ ordType: opts.ordType,
9793
+ sz: opts.sz,
9794
+ posSide: opts.posSide,
9795
+ px: opts.px,
9796
+ reduceOnly: opts.reduceOnly,
9797
+ tpTriggerPx: opts.tpTriggerPx,
9798
+ tpOrdPx: opts.tpOrdPx,
9799
+ slTriggerPx: opts.slTriggerPx,
9800
+ slOrdPx: opts.slOrdPx
9801
+ });
9802
+ const data = getData5(result);
9803
+ if (opts.json) return printJson(data);
9804
+ const order = data?.[0];
9805
+ process.stdout.write(`Order placed: ${order?.["ordId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9806
+ `);
9807
+ }
9808
+ async function cmdFuturesCancel(run, instId, ordId, json) {
9809
+ const result = await run("futures_cancel_order", { instId, ordId });
9810
+ const data = getData5(result);
9811
+ if (json) return printJson(data);
9812
+ const r = data?.[0];
9813
+ process.stdout.write(`Cancelled: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9814
+ `);
9815
+ }
9816
+ async function cmdFuturesGet(run, opts) {
9817
+ const result = await run("futures_get_order", { instId: opts.instId, ordId: opts.ordId });
9818
+ const data = getData5(result);
9819
+ if (opts.json) return printJson(data);
9820
+ const o = data?.[0];
9821
+ if (!o) {
9822
+ process.stdout.write("No data\n");
9823
+ return;
9824
+ }
9825
+ printKv({
9826
+ ordId: o["ordId"],
9827
+ instId: o["instId"],
9828
+ side: o["side"],
9829
+ posSide: o["posSide"],
9830
+ ordType: o["ordType"],
9831
+ px: o["px"],
9832
+ sz: o["sz"],
9833
+ fillSz: o["fillSz"],
9834
+ avgPx: o["avgPx"],
9835
+ state: o["state"],
9836
+ cTime: new Date(Number(o["cTime"])).toLocaleString()
9837
+ });
9838
+ }
9839
+ async function cmdFuturesAmend(run, opts) {
9840
+ const result = await run("futures_amend_order", {
9841
+ instId: opts.instId,
9842
+ ordId: opts.ordId,
9843
+ clOrdId: opts.clOrdId,
9844
+ newSz: opts.newSz,
9845
+ newPx: opts.newPx
9846
+ });
9847
+ const data = getData5(result);
9848
+ if (opts.json) return printJson(data);
9849
+ const r = data?.[0];
9850
+ process.stdout.write(`Order amended: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9851
+ `);
9852
+ }
9853
+ async function cmdFuturesClose(run, opts) {
9854
+ const result = await run("futures_close_position", {
9855
+ instId: opts.instId,
9856
+ mgnMode: opts.mgnMode,
9857
+ posSide: opts.posSide,
9858
+ autoCxl: opts.autoCxl
9859
+ });
9860
+ const data = getData5(result);
9861
+ if (opts.json) return printJson(data);
9862
+ const r = data?.[0];
9863
+ process.stdout.write(`Position closed: ${r?.["instId"]} ${r?.["posSide"] ?? ""}
9864
+ `);
9865
+ }
9866
+ async function cmdFuturesSetLeverage(run, opts) {
9867
+ const result = await run("futures_set_leverage", {
9868
+ instId: opts.instId,
9869
+ lever: opts.lever,
9870
+ mgnMode: opts.mgnMode,
9871
+ posSide: opts.posSide
9872
+ });
9873
+ const data = getData5(result);
9874
+ if (opts.json) return printJson(data);
9875
+ const r = data?.[0];
9876
+ process.stdout.write(`Leverage set: ${r?.["lever"]}x ${r?.["instId"]}
9877
+ `);
9878
+ }
9879
+ async function cmdFuturesGetLeverage(run, opts) {
9880
+ const result = await run("futures_get_leverage", { instId: opts.instId, mgnMode: opts.mgnMode });
9881
+ const data = getData5(result);
9882
+ if (opts.json) return printJson(data);
8860
9883
  printTable(
8861
- (fills ?? []).map((f) => ({
8862
- instId: f["instId"],
8863
- side: f["side"],
8864
- fillPx: f["fillPx"],
8865
- fillSz: f["fillSz"],
8866
- fee: f["fee"],
8867
- ts: new Date(Number(f["ts"])).toLocaleString()
9884
+ (data ?? []).map((r) => ({
9885
+ instId: r["instId"],
9886
+ mgnMode: r["mgnMode"],
9887
+ posSide: r["posSide"],
9888
+ lever: r["lever"]
8868
9889
  }))
8869
9890
  );
8870
9891
  }
8871
- async function cmdFuturesPlace(run, opts) {
8872
- const result = await run("futures_place_order", {
9892
+ async function cmdFuturesBatch(run, opts) {
9893
+ let parsed;
9894
+ try {
9895
+ parsed = JSON.parse(opts.orders);
9896
+ } catch {
9897
+ process.stderr.write("Error: --orders must be a valid JSON array\n");
9898
+ process.exitCode = 1;
9899
+ return;
9900
+ }
9901
+ if (!Array.isArray(parsed) || parsed.length === 0) {
9902
+ process.stderr.write("Error: --orders must be a non-empty JSON array\n");
9903
+ process.exitCode = 1;
9904
+ return;
9905
+ }
9906
+ const toolMap = {
9907
+ place: "futures_batch_orders",
9908
+ amend: "futures_batch_amend",
9909
+ cancel: "futures_batch_cancel"
9910
+ };
9911
+ const tool = toolMap[opts.action];
9912
+ if (!tool) {
9913
+ process.stderr.write(`Error: --action must be one of: place, amend, cancel
9914
+ `);
9915
+ process.exitCode = 1;
9916
+ return;
9917
+ }
9918
+ const result = await run(tool, tool === "futures_batch_orders" ? { orders: parsed } : { orders: parsed });
9919
+ const data = getData5(result);
9920
+ if (opts.json) return printJson(data);
9921
+ for (const r of data ?? []) {
9922
+ process.stdout.write(`${r["ordId"] ?? r["clOrdId"] ?? "?"}: ${r["sCode"] === "0" ? "OK" : r["sMsg"]}
9923
+ `);
9924
+ }
9925
+ }
9926
+ async function cmdFuturesAlgoPlace(run, opts) {
9927
+ const result = await run("futures_place_algo_order", {
8873
9928
  instId: opts.instId,
8874
9929
  tdMode: opts.tdMode,
8875
9930
  side: opts.side,
8876
9931
  ordType: opts.ordType,
8877
9932
  sz: opts.sz,
8878
9933
  posSide: opts.posSide,
8879
- px: opts.px,
8880
- reduceOnly: opts.reduceOnly,
8881
9934
  tpTriggerPx: opts.tpTriggerPx,
8882
9935
  tpOrdPx: opts.tpOrdPx,
8883
9936
  slTriggerPx: opts.slTriggerPx,
8884
- slOrdPx: opts.slOrdPx
9937
+ slOrdPx: opts.slOrdPx,
9938
+ reduceOnly: opts.reduceOnly
8885
9939
  });
8886
9940
  const data = getData5(result);
8887
9941
  if (opts.json) return printJson(data);
8888
9942
  const order = data?.[0];
8889
- process.stdout.write(`Order placed: ${order?.["ordId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
8890
- `);
9943
+ process.stdout.write(
9944
+ `Algo order placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9945
+ `
9946
+ );
8891
9947
  }
8892
- async function cmdFuturesCancel(run, instId, ordId, json) {
8893
- const result = await run("futures_cancel_order", { instId, ordId });
9948
+ async function cmdFuturesAlgoTrailPlace(run, opts) {
9949
+ const result = await run("futures_place_move_stop_order", {
9950
+ instId: opts.instId,
9951
+ tdMode: opts.tdMode,
9952
+ side: opts.side,
9953
+ sz: opts.sz,
9954
+ callbackRatio: opts.callbackRatio,
9955
+ callbackSpread: opts.callbackSpread,
9956
+ activePx: opts.activePx,
9957
+ posSide: opts.posSide,
9958
+ reduceOnly: opts.reduceOnly
9959
+ });
8894
9960
  const data = getData5(result);
8895
- if (json) return printJson(data);
8896
- const r = data?.[0];
8897
- process.stdout.write(`Cancelled: ${r?.["ordId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
8898
- `);
9961
+ if (opts.json) return printJson(data);
9962
+ const order = data?.[0];
9963
+ process.stdout.write(
9964
+ `Trailing stop placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
9965
+ `
9966
+ );
8899
9967
  }
8900
- async function cmdFuturesGet(run, opts) {
8901
- const result = await run("futures_get_order", { instId: opts.instId, ordId: opts.ordId });
9968
+ async function cmdFuturesAlgoAmend(run, opts) {
9969
+ const result = await run("futures_amend_algo_order", {
9970
+ instId: opts.instId,
9971
+ algoId: opts.algoId,
9972
+ newSz: opts.newSz,
9973
+ newTpTriggerPx: opts.newTpTriggerPx,
9974
+ newTpOrdPx: opts.newTpOrdPx,
9975
+ newSlTriggerPx: opts.newSlTriggerPx,
9976
+ newSlOrdPx: opts.newSlOrdPx
9977
+ });
8902
9978
  const data = getData5(result);
8903
9979
  if (opts.json) return printJson(data);
8904
- const o = data?.[0];
8905
- if (!o) {
8906
- process.stdout.write("No data\n");
9980
+ const r = data?.[0];
9981
+ process.stdout.write(
9982
+ `Algo order amended: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9983
+ `
9984
+ );
9985
+ }
9986
+ async function cmdFuturesAlgoCancel(run, instId, algoId, json) {
9987
+ const result = await run("futures_cancel_algo_orders", { orders: [{ instId, algoId }] });
9988
+ const data = getData5(result);
9989
+ if (json) return printJson(data);
9990
+ const r = data?.[0];
9991
+ process.stdout.write(
9992
+ `Algo order cancelled: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
9993
+ `
9994
+ );
9995
+ }
9996
+ async function cmdFuturesAlgoOrders(run, opts) {
9997
+ const result = await run("futures_get_algo_orders", {
9998
+ instId: opts.instId,
9999
+ status: opts.status,
10000
+ ordType: opts.ordType
10001
+ });
10002
+ const orders = getData5(result);
10003
+ if (opts.json) return printJson(orders);
10004
+ if (!(orders ?? []).length) {
10005
+ process.stdout.write("No algo orders\n");
8907
10006
  return;
8908
10007
  }
8909
- printKv({
8910
- ordId: o["ordId"],
8911
- instId: o["instId"],
8912
- side: o["side"],
8913
- posSide: o["posSide"],
8914
- ordType: o["ordType"],
8915
- px: o["px"],
8916
- sz: o["sz"],
8917
- fillSz: o["fillSz"],
8918
- avgPx: o["avgPx"],
8919
- state: o["state"],
8920
- cTime: new Date(Number(o["cTime"])).toLocaleString()
8921
- });
10008
+ printTable(
10009
+ orders.map((o) => ({
10010
+ algoId: o["algoId"],
10011
+ instId: o["instId"],
10012
+ type: o["ordType"],
10013
+ side: o["side"],
10014
+ sz: o["sz"],
10015
+ tpTrigger: o["tpTriggerPx"],
10016
+ slTrigger: o["slTriggerPx"],
10017
+ state: o["state"]
10018
+ }))
10019
+ );
8922
10020
  }
8923
- var cmdFuturesAmend = cmdSwapAmend;
8924
- var cmdFuturesAlgoPlace = cmdSwapAlgoPlace;
8925
- var cmdFuturesAlgoAmend = cmdSwapAlgoAmend;
8926
- var cmdFuturesAlgoCancel = cmdSwapAlgoCancel;
8927
- var cmdFuturesAlgoOrders = cmdSwapAlgoOrders;
8928
- var cmdFuturesBatch = cmdSwapBatch;
8929
- var cmdFuturesClose = cmdSwapClose;
8930
- var cmdFuturesGetLeverage = cmdSwapGetLeverage;
8931
- var cmdFuturesSetLeverage = cmdSwapSetLeverage;
8932
- var cmdFuturesAlgoTrailPlace = cmdSwapAlgoTrailPlace;
8933
10021
 
8934
10022
  // src/commands/option.ts
8935
10023
  function getData6(result) {
@@ -9072,7 +10160,11 @@ async function cmdOptionPlace(run, opts) {
9072
10160
  sz: opts.sz,
9073
10161
  px: opts.px,
9074
10162
  reduceOnly: opts.reduceOnly,
9075
- clOrdId: opts.clOrdId
10163
+ clOrdId: opts.clOrdId,
10164
+ tpTriggerPx: opts.tpTriggerPx,
10165
+ tpOrdPx: opts.tpOrdPx,
10166
+ slTriggerPx: opts.slTriggerPx,
10167
+ slOrdPx: opts.slOrdPx
9076
10168
  });
9077
10169
  const data = getData6(result);
9078
10170
  if (opts.json) return printJson(data);
@@ -9128,6 +10220,81 @@ async function cmdOptionBatchCancel(run, opts) {
9128
10220
  `);
9129
10221
  }
9130
10222
  }
10223
+ async function cmdOptionAlgoPlace(run, opts) {
10224
+ const result = await run("option_place_algo_order", {
10225
+ instId: opts.instId,
10226
+ tdMode: opts.tdMode,
10227
+ side: opts.side,
10228
+ ordType: opts.ordType,
10229
+ sz: opts.sz,
10230
+ tpTriggerPx: opts.tpTriggerPx,
10231
+ tpOrdPx: opts.tpOrdPx,
10232
+ slTriggerPx: opts.slTriggerPx,
10233
+ slOrdPx: opts.slOrdPx,
10234
+ reduceOnly: opts.reduceOnly,
10235
+ clOrdId: opts.clOrdId
10236
+ });
10237
+ const data = getData6(result);
10238
+ if (opts.json) return printJson(data);
10239
+ const order = data?.[0];
10240
+ process.stdout.write(
10241
+ `Algo order placed: ${order?.["algoId"]} (${order?.["sCode"] === "0" ? "OK" : order?.["sMsg"]})
10242
+ `
10243
+ );
10244
+ }
10245
+ async function cmdOptionAlgoAmend(run, opts) {
10246
+ const result = await run("option_amend_algo_order", {
10247
+ instId: opts.instId,
10248
+ algoId: opts.algoId,
10249
+ newSz: opts.newSz,
10250
+ newTpTriggerPx: opts.newTpTriggerPx,
10251
+ newTpOrdPx: opts.newTpOrdPx,
10252
+ newSlTriggerPx: opts.newSlTriggerPx,
10253
+ newSlOrdPx: opts.newSlOrdPx
10254
+ });
10255
+ const data = getData6(result);
10256
+ if (opts.json) return printJson(data);
10257
+ const r = data?.[0];
10258
+ process.stdout.write(
10259
+ `Algo order amended: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
10260
+ `
10261
+ );
10262
+ }
10263
+ async function cmdOptionAlgoCancel(run, opts) {
10264
+ const result = await run("option_cancel_algo_orders", { orders: [{ instId: opts.instId, algoId: opts.algoId }] });
10265
+ const data = getData6(result);
10266
+ if (opts.json) return printJson(data);
10267
+ const r = data?.[0];
10268
+ process.stdout.write(
10269
+ `Algo order cancelled: ${r?.["algoId"]} (${r?.["sCode"] === "0" ? "OK" : r?.["sMsg"]})
10270
+ `
10271
+ );
10272
+ }
10273
+ async function cmdOptionAlgoOrders(run, opts) {
10274
+ const result = await run("option_get_algo_orders", {
10275
+ instId: opts.instId,
10276
+ status: opts.status,
10277
+ ordType: opts.ordType
10278
+ });
10279
+ const orders = getData6(result);
10280
+ if (opts.json) return printJson(orders);
10281
+ if (!(orders ?? []).length) {
10282
+ process.stdout.write("No algo orders\n");
10283
+ return;
10284
+ }
10285
+ printTable(
10286
+ orders.map((o) => ({
10287
+ algoId: o["algoId"],
10288
+ instId: o["instId"],
10289
+ type: o["ordType"],
10290
+ side: o["side"],
10291
+ sz: o["sz"],
10292
+ tpTrigger: o["tpTriggerPx"],
10293
+ slTrigger: o["slTriggerPx"],
10294
+ state: o["state"]
10295
+ }))
10296
+ );
10297
+ }
9131
10298
 
9132
10299
  // src/config/toml.ts
9133
10300
  function writeCliConfig(config) {
@@ -10190,7 +11357,7 @@ async function cmdDcdQuoteAndBuy(run, opts) {
10190
11357
  // src/index.ts
10191
11358
  var _require2 = createRequire2(import.meta.url);
10192
11359
  var CLI_VERSION2 = _require2("../package.json").version;
10193
- var GIT_HASH2 = true ? "a880395" : "dev";
11360
+ var GIT_HASH2 = true ? "836b2ae" : "dev";
10194
11361
  function handleConfigCommand(action, rest, json, lang, force) {
10195
11362
  if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
10196
11363
  if (action === "show") return cmdConfigShow(json);
@@ -10505,7 +11672,44 @@ function handleSwapCommand(run, action, rest, v, json) {
10505
11672
  if (action === "batch")
10506
11673
  return cmdSwapBatch(run, { action: v.action, orders: v.orders, json });
10507
11674
  }
10508
- function handleOptionCommand(run, action, _rest, v, json) {
11675
+ function handleOptionAlgoCommand(run, subAction, v, json) {
11676
+ if (subAction === "place")
11677
+ return cmdOptionAlgoPlace(run, {
11678
+ instId: v.instId,
11679
+ tdMode: v.tdMode,
11680
+ side: v.side,
11681
+ ordType: v.ordType ?? "conditional",
11682
+ sz: v.sz,
11683
+ tpTriggerPx: v.tpTriggerPx,
11684
+ tpOrdPx: v.tpOrdPx,
11685
+ slTriggerPx: v.slTriggerPx,
11686
+ slOrdPx: v.slOrdPx,
11687
+ reduceOnly: v.reduceOnly,
11688
+ clOrdId: v.clOrdId,
11689
+ json
11690
+ });
11691
+ if (subAction === "amend")
11692
+ return cmdOptionAlgoAmend(run, {
11693
+ instId: v.instId,
11694
+ algoId: v.algoId,
11695
+ newSz: v.newSz,
11696
+ newTpTriggerPx: v.newTpTriggerPx,
11697
+ newTpOrdPx: v.newTpOrdPx,
11698
+ newSlTriggerPx: v.newSlTriggerPx,
11699
+ newSlOrdPx: v.newSlOrdPx,
11700
+ json
11701
+ });
11702
+ if (subAction === "cancel")
11703
+ return cmdOptionAlgoCancel(run, { instId: v.instId, algoId: v.algoId, json });
11704
+ if (subAction === "orders")
11705
+ return cmdOptionAlgoOrders(run, {
11706
+ instId: v.instId,
11707
+ status: v.history ? "history" : "pending",
11708
+ ordType: v.ordType,
11709
+ json
11710
+ });
11711
+ }
11712
+ function handleOptionCommand(run, action, rest, v, json) {
10509
11713
  if (action === "orders") {
10510
11714
  let status = "live";
10511
11715
  if (v.archive) status = "archive";
@@ -10532,6 +11736,10 @@ function handleOptionCommand(run, action, _rest, v, json) {
10532
11736
  px: v.px,
10533
11737
  reduceOnly: v.reduceOnly,
10534
11738
  clOrdId: v.clOrdId,
11739
+ tpTriggerPx: v.tpTriggerPx,
11740
+ tpOrdPx: v.tpOrdPx,
11741
+ slTriggerPx: v.slTriggerPx,
11742
+ slOrdPx: v.slOrdPx,
10535
11743
  json
10536
11744
  });
10537
11745
  if (action === "cancel")
@@ -10547,6 +11755,8 @@ function handleOptionCommand(run, action, _rest, v, json) {
10547
11755
  });
10548
11756
  if (action === "batch-cancel")
10549
11757
  return cmdOptionBatchCancel(run, { orders: v.orders, json });
11758
+ if (action === "algo")
11759
+ return handleOptionAlgoCommand(run, rest[0], v, json);
10550
11760
  }
10551
11761
  function handleFuturesAlgoCommand(run, subAction, v, json) {
10552
11762
  if (subAction === "trail")