@okx_ai/okx-trade-cli 1.2.3 → 1.2.4-beta.1

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
@@ -1284,7 +1284,8 @@ var BOT_SUB_MODULE_IDS = [
1284
1284
  var BOT_DEFAULT_SUB_MODULES = ["bot.grid"];
1285
1285
  var EARN_SUB_MODULE_IDS = [
1286
1286
  "earn.savings",
1287
- "earn.onchain"
1287
+ "earn.onchain",
1288
+ "earn.dcd"
1288
1289
  ];
1289
1290
  var MODULES = [
1290
1291
  "market",
@@ -2391,7 +2392,7 @@ function registerGridTools() {
2391
2392
  algoOrdType: {
2392
2393
  type: "string",
2393
2394
  enum: ["grid", "contract_grid", "moon_grid"],
2394
- description: "grid=Spot, contract_grid=Contract, moon_grid=Moon"
2395
+ description: "Grid bot type. grid=Spot, contract_grid=Contract, moon_grid=Moon. Must match the bot's actual type when filtering by algoId."
2395
2396
  },
2396
2397
  status: {
2397
2398
  type: "string",
@@ -2403,7 +2404,8 @@ function registerGridTools() {
2403
2404
  description: "e.g. BTC-USDT"
2404
2405
  },
2405
2406
  algoId: {
2406
- type: "string"
2407
+ type: "string",
2408
+ description: "Grid bot algo order ID (returned by grid_create_order or grid_get_orders). This is NOT a normal trade order ID."
2407
2409
  },
2408
2410
  after: {
2409
2411
  type: "string",
@@ -2451,10 +2453,11 @@ function registerGridTools() {
2451
2453
  algoOrdType: {
2452
2454
  type: "string",
2453
2455
  enum: ["grid", "contract_grid", "moon_grid"],
2454
- description: "grid=Spot, contract_grid=Contract, moon_grid=Moon"
2456
+ 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."
2455
2457
  },
2456
2458
  algoId: {
2457
- type: "string"
2459
+ type: "string",
2460
+ description: "Grid bot algo order ID (returned by grid_create_order or grid_get_orders). This is NOT a normal trade order ID."
2458
2461
  }
2459
2462
  },
2460
2463
  required: ["algoOrdType", "algoId"]
@@ -2483,10 +2486,11 @@ function registerGridTools() {
2483
2486
  algoOrdType: {
2484
2487
  type: "string",
2485
2488
  enum: ["grid", "contract_grid", "moon_grid"],
2486
- description: "grid=Spot, contract_grid=Contract, moon_grid=Moon"
2489
+ 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."
2487
2490
  },
2488
2491
  algoId: {
2489
- type: "string"
2492
+ type: "string",
2493
+ description: "Grid bot algo order ID (returned by grid_create_order or grid_get_orders). This is NOT a normal trade order ID."
2490
2494
  },
2491
2495
  type: {
2492
2496
  type: "string",
@@ -2494,7 +2498,8 @@ function registerGridTools() {
2494
2498
  description: "filled=executed trades (default); live=pending orders"
2495
2499
  },
2496
2500
  groupId: {
2497
- type: "string"
2501
+ type: "string",
2502
+ description: "Group ID \u2014 a buy-sell pair shares the same groupId. Use to filter a specific grid level."
2498
2503
  },
2499
2504
  after: {
2500
2505
  type: "string",
@@ -2629,12 +2634,13 @@ function registerGridTools() {
2629
2634
  type: "object",
2630
2635
  properties: {
2631
2636
  algoId: {
2632
- type: "string"
2637
+ type: "string",
2638
+ description: "Grid bot algo order ID (returned by grid_create_order or grid_get_orders). This is NOT a normal trade order ID."
2633
2639
  },
2634
2640
  algoOrdType: {
2635
2641
  type: "string",
2636
2642
  enum: ["grid", "contract_grid", "moon_grid"],
2637
- description: "grid=Spot, contract_grid=Contract, moon_grid=Moon"
2643
+ 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."
2638
2644
  },
2639
2645
  instId: {
2640
2646
  type: "string",
@@ -2766,7 +2772,10 @@ function registerDcaTools() {
2766
2772
  inputSchema: {
2767
2773
  type: "object",
2768
2774
  properties: {
2769
- algoId: { type: "string", description: "Algo order ID of the DCA bot to stop" }
2775
+ algoId: {
2776
+ type: "string",
2777
+ description: "DCA bot algo order ID (returned by dca_create_order or dca_get_orders). This is NOT a normal trade order ID."
2778
+ }
2770
2779
  },
2771
2780
  required: ["algoId"]
2772
2781
  },
@@ -2794,7 +2803,10 @@ function registerDcaTools() {
2794
2803
  enum: ["active", "history"],
2795
2804
  description: "active=running (default); history=stopped"
2796
2805
  },
2797
- algoId: { type: "string" },
2806
+ algoId: {
2807
+ type: "string",
2808
+ description: "DCA bot algo order ID (returned by dca_create_order or dca_get_orders). This is NOT a normal trade order ID."
2809
+ },
2798
2810
  instId: { type: "string", description: "Filter by instrument, e.g. BTC-USDT-SWAP (optional)" },
2799
2811
  after: { type: "string", description: "Pagination: before this algo ID" },
2800
2812
  before: { type: "string", description: "Pagination: after this algo ID" },
@@ -2829,7 +2841,10 @@ function registerDcaTools() {
2829
2841
  inputSchema: {
2830
2842
  type: "object",
2831
2843
  properties: {
2832
- algoId: { type: "string" }
2844
+ algoId: {
2845
+ type: "string",
2846
+ description: "DCA bot algo order ID (returned by dca_create_order or dca_get_orders). This is NOT a normal trade order ID."
2847
+ }
2833
2848
  },
2834
2849
  required: ["algoId"]
2835
2850
  },
@@ -2852,7 +2867,10 @@ function registerDcaTools() {
2852
2867
  inputSchema: {
2853
2868
  type: "object",
2854
2869
  properties: {
2855
- algoId: { type: "string", description: "Algo order ID of the DCA bot" },
2870
+ algoId: {
2871
+ type: "string",
2872
+ description: "DCA bot algo order ID (returned by dca_create_order or dca_get_orders). This is NOT a normal trade order ID."
2873
+ },
2856
2874
  cycleId: { type: "string", description: "Omit to list all cycles; provide to get orders within a cycle" },
2857
2875
  after: { type: "string", description: "Pagination cursor \u2014 applies to cycle-list mode only (when cycleId is omitted)" },
2858
2876
  before: { type: "string", description: "Pagination cursor \u2014 applies to cycle-list mode only (when cycleId is omitted)" },
@@ -3139,639 +3157,921 @@ function registerEarnTools() {
3139
3157
  }
3140
3158
  ];
3141
3159
  }
3142
- var FUTURES_INST_TYPES = ["FUTURES", "SWAP"];
3143
- function normalize5(response) {
3144
- return {
3145
- endpoint: response.endpoint,
3146
- requestTime: response.requestTime,
3147
- data: response.data
3148
- };
3149
- }
3150
- function registerFuturesTools() {
3160
+ function registerOnchainEarnTools() {
3151
3161
  return [
3162
+ // -------------------------------------------------------------------------
3163
+ // Get Offers
3164
+ // -------------------------------------------------------------------------
3152
3165
  {
3153
- name: "futures_place_order",
3154
- module: "futures",
3155
- description: "Place a FUTURES delivery contract order (e.g. instId: BTC-USDT-240329). Optionally attach TP/SL via tpTriggerPx/slTriggerPx. [CAUTION] Executes real trades. Private endpoint. Rate limit: 60 req/s.",
3156
- isWrite: true,
3166
+ name: "onchain_earn_get_offers",
3167
+ module: "earn.onchain",
3168
+ description: "Get available on-chain earn (staking/DeFi) offers. Returns investment products with APY, terms, and limits. Private endpoint. Rate limit: 3 req/s.",
3169
+ isWrite: false,
3157
3170
  inputSchema: {
3158
3171
  type: "object",
3159
3172
  properties: {
3160
- instId: {
3161
- type: "string",
3162
- description: "e.g. BTC-USDT-240329"
3163
- },
3164
- tdMode: {
3165
- type: "string",
3166
- enum: ["cross", "isolated"],
3167
- description: "cross|isolated margin"
3168
- },
3169
- side: {
3170
- type: "string",
3171
- enum: ["buy", "sell"],
3172
- description: "one-way: buy=open long, sell=open short (use reduceOnly=true to close); hedge: combined with posSide"
3173
- },
3174
- posSide: {
3175
- type: "string",
3176
- enum: ["long", "short", "net"],
3177
- description: "net=one-way mode (default); long/short=hedge mode only"
3178
- },
3179
- ordType: {
3180
- type: "string",
3181
- enum: ["market", "limit", "post_only", "fok", "ioc"],
3182
- description: "market(no px)|limit(px req)|post_only(maker)|fok(all-or-cancel)|ioc(partial fill)"
3183
- },
3184
- sz: {
3185
- type: "string",
3186
- description: "Number of contracts (NOT USDT amount). Use market_get_instruments to get ctVal for conversion."
3187
- },
3188
- px: {
3189
- type: "string",
3190
- description: "Required for limit/post_only/fok/ioc"
3191
- },
3192
- reduceOnly: {
3193
- type: "boolean",
3194
- description: "Close/reduce only, no new position (one-way mode)"
3195
- },
3196
- clOrdId: {
3197
- type: "string",
3198
- description: "Client order ID (max 32 chars)"
3199
- },
3200
- tpTriggerPx: {
3201
- type: "string",
3202
- description: "TP trigger price; places TP at tpOrdPx"
3203
- },
3204
- tpOrdPx: {
3173
+ productId: {
3205
3174
  type: "string",
3206
- description: "TP order price; -1=market"
3175
+ description: "Specific product ID to query. Omit for all offers."
3207
3176
  },
3208
- slTriggerPx: {
3177
+ protocolType: {
3209
3178
  type: "string",
3210
- description: "SL trigger price; places SL at slOrdPx"
3179
+ description: "Protocol type filter: staking, defi. Omit for all types."
3211
3180
  },
3212
- slOrdPx: {
3181
+ ccy: {
3213
3182
  type: "string",
3214
- description: "SL order price; -1=market"
3183
+ description: "Currency filter, e.g. ETH. Omit for all currencies."
3215
3184
  }
3216
- },
3217
- required: ["instId", "tdMode", "side", "ordType", "sz"]
3185
+ }
3218
3186
  },
3219
3187
  handler: async (rawArgs, context) => {
3220
3188
  const args = asRecord(rawArgs);
3221
- const reduceOnly = args.reduceOnly;
3222
- const tpTriggerPx = readString(args, "tpTriggerPx");
3223
- const tpOrdPx = readString(args, "tpOrdPx");
3224
- const slTriggerPx = readString(args, "slTriggerPx");
3225
- const slOrdPx = readString(args, "slOrdPx");
3226
- const algoEntry = compactObject({ tpTriggerPx, tpOrdPx, slTriggerPx, slOrdPx });
3227
- const attachAlgoOrds = Object.keys(algoEntry).length > 0 ? [algoEntry] : void 0;
3228
- const response = await context.client.privatePost(
3229
- "/api/v5/trade/order",
3189
+ const response = await context.client.privateGet(
3190
+ "/api/v5/finance/staking-defi/offers",
3230
3191
  compactObject({
3231
- instId: requireString(args, "instId"),
3232
- tdMode: requireString(args, "tdMode"),
3233
- side: requireString(args, "side"),
3234
- posSide: readString(args, "posSide"),
3235
- ordType: requireString(args, "ordType"),
3236
- sz: requireString(args, "sz"),
3237
- px: readString(args, "px"),
3238
- reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
3239
- clOrdId: readString(args, "clOrdId"),
3240
- tag: context.config.sourceTag,
3241
- attachAlgoOrds
3192
+ productId: readString(args, "productId"),
3193
+ protocolType: readString(args, "protocolType"),
3194
+ ccy: readString(args, "ccy")
3242
3195
  }),
3243
- privateRateLimit("futures_place_order", 60)
3196
+ privateRateLimit("onchain_earn_get_offers", 3)
3244
3197
  );
3245
- return normalize5(response);
3198
+ return normalizeResponse(response);
3246
3199
  }
3247
3200
  },
3201
+ // -------------------------------------------------------------------------
3202
+ // Purchase
3203
+ // -------------------------------------------------------------------------
3248
3204
  {
3249
- name: "futures_cancel_order",
3250
- module: "futures",
3251
- description: "Cancel an unfilled FUTURES delivery order. Private endpoint. Rate limit: 60 req/s.",
3205
+ name: "onchain_earn_purchase",
3206
+ module: "earn.onchain",
3207
+ description: "Purchase on-chain earn (staking/DeFi) product. [CAUTION] Moves real funds into staking/DeFi product. Not supported in demo/simulated trading mode. Private endpoint. Rate limit: 2 req/s.",
3252
3208
  isWrite: true,
3253
3209
  inputSchema: {
3254
3210
  type: "object",
3255
3211
  properties: {
3256
- instId: {
3212
+ productId: {
3257
3213
  type: "string",
3258
- description: "e.g. BTC-USDT-240329"
3214
+ description: "Product ID to purchase"
3259
3215
  },
3260
- ordId: {
3261
- type: "string"
3216
+ investData: {
3217
+ type: "array",
3218
+ description: "Investment data array: [{ccy, amt}]. Each item specifies currency and amount.",
3219
+ items: {
3220
+ type: "object",
3221
+ properties: {
3222
+ ccy: { type: "string", description: "Currency, e.g. ETH" },
3223
+ amt: { type: "string", description: "Amount to invest" }
3224
+ },
3225
+ required: ["ccy", "amt"]
3226
+ }
3262
3227
  },
3263
- clOrdId: {
3228
+ term: {
3264
3229
  type: "string",
3265
- description: "Client order ID"
3230
+ description: "Investment term in days. Required for fixed-term products."
3231
+ },
3232
+ tag: {
3233
+ type: "string",
3234
+ description: "Order tag for tracking (optional)."
3266
3235
  }
3267
3236
  },
3268
- required: ["instId"]
3237
+ required: ["productId", "investData"]
3269
3238
  },
3270
3239
  handler: async (rawArgs, context) => {
3240
+ assertNotDemo(context.config, "onchain_earn_purchase");
3271
3241
  const args = asRecord(rawArgs);
3272
3242
  const response = await context.client.privatePost(
3273
- "/api/v5/trade/cancel-order",
3243
+ "/api/v5/finance/staking-defi/purchase",
3274
3244
  compactObject({
3275
- instId: requireString(args, "instId"),
3276
- ordId: readString(args, "ordId"),
3277
- clOrdId: readString(args, "clOrdId")
3245
+ productId: requireString(args, "productId"),
3246
+ investData: args.investData,
3247
+ term: readString(args, "term"),
3248
+ tag: readString(args, "tag")
3278
3249
  }),
3279
- privateRateLimit("futures_cancel_order", 60)
3250
+ privateRateLimit("onchain_earn_purchase", 2)
3280
3251
  );
3281
- return normalize5(response);
3252
+ return normalizeResponse(response);
3282
3253
  }
3283
3254
  },
3255
+ // -------------------------------------------------------------------------
3256
+ // Redeem
3257
+ // -------------------------------------------------------------------------
3284
3258
  {
3285
- name: "futures_get_order",
3286
- module: "futures",
3287
- description: "Get details of a single FUTURES delivery order by ordId or clOrdId. Private endpoint. Rate limit: 60 req/s.",
3288
- isWrite: false,
3259
+ name: "onchain_earn_redeem",
3260
+ module: "earn.onchain",
3261
+ description: "Redeem on-chain earn (staking/DeFi) investment. [CAUTION] Withdraws funds from staking/DeFi product. Some products may have lock periods. Not supported in demo mode. Private endpoint. Rate limit: 2 req/s.",
3262
+ isWrite: true,
3289
3263
  inputSchema: {
3290
3264
  type: "object",
3291
3265
  properties: {
3292
- instId: {
3293
- type: "string",
3294
- description: "e.g. BTC-USDT-240329"
3295
- },
3296
3266
  ordId: {
3297
3267
  type: "string",
3298
- description: "Provide ordId or clOrdId"
3268
+ description: "Order ID to redeem"
3299
3269
  },
3300
- clOrdId: {
3270
+ protocolType: {
3301
3271
  type: "string",
3302
- description: "Provide ordId or clOrdId"
3272
+ description: "Protocol type: staking, defi"
3273
+ },
3274
+ allowEarlyRedeem: {
3275
+ type: "boolean",
3276
+ description: "Allow early redemption for fixed-term products (may incur penalties). Default false."
3303
3277
  }
3304
3278
  },
3305
- required: ["instId"]
3279
+ required: ["ordId", "protocolType"]
3306
3280
  },
3307
3281
  handler: async (rawArgs, context) => {
3282
+ assertNotDemo(context.config, "onchain_earn_redeem");
3308
3283
  const args = asRecord(rawArgs);
3309
- const response = await context.client.privateGet(
3310
- "/api/v5/trade/order",
3284
+ const response = await context.client.privatePost(
3285
+ "/api/v5/finance/staking-defi/redeem",
3311
3286
  compactObject({
3312
- instId: requireString(args, "instId"),
3313
- ordId: readString(args, "ordId"),
3314
- clOrdId: readString(args, "clOrdId")
3287
+ ordId: requireString(args, "ordId"),
3288
+ protocolType: requireString(args, "protocolType"),
3289
+ allowEarlyRedeem: readBoolean(args, "allowEarlyRedeem")
3315
3290
  }),
3316
- privateRateLimit("futures_get_order", 60)
3291
+ privateRateLimit("onchain_earn_redeem", 2)
3317
3292
  );
3318
- return normalize5(response);
3293
+ return normalizeResponse(response);
3319
3294
  }
3320
3295
  },
3296
+ // -------------------------------------------------------------------------
3297
+ // Cancel
3298
+ // -------------------------------------------------------------------------
3321
3299
  {
3322
- name: "futures_get_orders",
3323
- module: "futures",
3324
- description: "Query FUTURES open orders, history (last 7 days), or archive (up to 3 months). Private. Rate limit: 20 req/s.",
3325
- isWrite: false,
3300
+ name: "onchain_earn_cancel",
3301
+ module: "earn.onchain",
3302
+ description: "Cancel pending on-chain earn purchase. [CAUTION] Cancels a pending investment order. Not supported in demo mode. Private endpoint. Rate limit: 2 req/s.",
3303
+ isWrite: true,
3326
3304
  inputSchema: {
3327
3305
  type: "object",
3328
3306
  properties: {
3329
- status: {
3307
+ ordId: {
3330
3308
  type: "string",
3331
- enum: ["open", "history", "archive"],
3332
- description: "open=active, history=7d, archive=3mo"
3309
+ description: "Order ID to cancel"
3333
3310
  },
3334
- instType: {
3311
+ protocolType: {
3335
3312
  type: "string",
3336
- enum: [...FUTURES_INST_TYPES],
3337
- description: "FUTURES (default) or SWAP"
3313
+ description: "Protocol type: staking, defi"
3314
+ }
3315
+ },
3316
+ required: ["ordId", "protocolType"]
3317
+ },
3318
+ handler: async (rawArgs, context) => {
3319
+ assertNotDemo(context.config, "onchain_earn_cancel");
3320
+ const args = asRecord(rawArgs);
3321
+ const response = await context.client.privatePost(
3322
+ "/api/v5/finance/staking-defi/cancel",
3323
+ {
3324
+ ordId: requireString(args, "ordId"),
3325
+ protocolType: requireString(args, "protocolType")
3338
3326
  },
3339
- instId: {
3340
- type: "string",
3341
- description: "e.g. BTC-USDT-240329"
3342
- },
3343
- ordType: {
3344
- type: "string",
3345
- description: "Order type filter"
3346
- },
3347
- state: {
3348
- type: "string",
3349
- description: "canceled|filled"
3350
- },
3351
- after: {
3352
- type: "string",
3353
- description: "Pagination: before this order ID"
3354
- },
3355
- before: {
3356
- type: "string",
3357
- description: "Pagination: after this order ID"
3358
- },
3359
- begin: {
3360
- type: "string",
3361
- description: "Start time (ms)"
3362
- },
3363
- end: {
3364
- type: "string",
3365
- description: "End time (ms)"
3366
- },
3367
- limit: {
3368
- type: "number",
3369
- description: "Max results (default 100)"
3370
- }
3371
- }
3372
- },
3373
- handler: async (rawArgs, context) => {
3374
- const args = asRecord(rawArgs);
3375
- const status = readString(args, "status") ?? "open";
3376
- const instType = readString(args, "instType") ?? "FUTURES";
3377
- assertEnum(instType, "instType", FUTURES_INST_TYPES);
3378
- const path4 = status === "archive" ? "/api/v5/trade/orders-history-archive" : status === "history" ? "/api/v5/trade/orders-history" : "/api/v5/trade/orders-pending";
3379
- const response = await context.client.privateGet(
3380
- path4,
3381
- compactObject({
3382
- instType,
3383
- instId: readString(args, "instId"),
3384
- ordType: readString(args, "ordType"),
3385
- state: readString(args, "state"),
3386
- after: readString(args, "after"),
3387
- before: readString(args, "before"),
3388
- begin: readString(args, "begin"),
3389
- end: readString(args, "end"),
3390
- limit: readNumber(args, "limit")
3391
- }),
3392
- privateRateLimit("futures_get_orders", 20)
3327
+ privateRateLimit("onchain_earn_cancel", 2)
3393
3328
  );
3394
- return normalize5(response);
3329
+ return normalizeResponse(response);
3395
3330
  }
3396
3331
  },
3332
+ // -------------------------------------------------------------------------
3333
+ // Get Active Orders
3334
+ // -------------------------------------------------------------------------
3397
3335
  {
3398
- name: "futures_get_positions",
3399
- module: "futures",
3400
- description: "Get current FUTURES delivery contract positions. Private endpoint. Rate limit: 10 req/s.",
3336
+ name: "onchain_earn_get_active_orders",
3337
+ module: "earn.onchain",
3338
+ description: "Get active on-chain earn orders. Returns current staking/DeFi investments. Private endpoint. Rate limit: 3 req/s.",
3401
3339
  isWrite: false,
3402
3340
  inputSchema: {
3403
3341
  type: "object",
3404
3342
  properties: {
3405
- instType: {
3343
+ productId: {
3406
3344
  type: "string",
3407
- enum: [...FUTURES_INST_TYPES],
3408
- description: "FUTURES (default) or SWAP"
3345
+ description: "Filter by product ID. Omit for all."
3409
3346
  },
3410
- instId: {
3347
+ protocolType: {
3411
3348
  type: "string",
3412
- description: "e.g. BTC-USDT-240329"
3349
+ description: "Filter by protocol type: staking, defi. Omit for all."
3413
3350
  },
3414
- posId: {
3415
- type: "string"
3351
+ ccy: {
3352
+ type: "string",
3353
+ description: "Filter by currency, e.g. ETH. Omit for all."
3354
+ },
3355
+ state: {
3356
+ type: "string",
3357
+ description: "Filter by state: 8 (pending), 13 (cancelling), 9 (onchain), 1 (earning), 2 (redeeming). Omit for all."
3416
3358
  }
3417
3359
  }
3418
3360
  },
3419
3361
  handler: async (rawArgs, context) => {
3420
3362
  const args = asRecord(rawArgs);
3421
- const instType = readString(args, "instType") ?? "FUTURES";
3422
- assertEnum(instType, "instType", FUTURES_INST_TYPES);
3423
3363
  const response = await context.client.privateGet(
3424
- "/api/v5/account/positions",
3364
+ "/api/v5/finance/staking-defi/orders-active",
3425
3365
  compactObject({
3426
- instType,
3427
- instId: readString(args, "instId"),
3428
- posId: readString(args, "posId")
3366
+ productId: readString(args, "productId"),
3367
+ protocolType: readString(args, "protocolType"),
3368
+ ccy: readString(args, "ccy"),
3369
+ state: readString(args, "state")
3429
3370
  }),
3430
- privateRateLimit("futures_get_positions", 10)
3371
+ privateRateLimit("onchain_earn_get_active_orders", 3)
3431
3372
  );
3432
- return normalize5(response);
3373
+ return normalizeResponse(response);
3433
3374
  }
3434
3375
  },
3376
+ // -------------------------------------------------------------------------
3377
+ // Get Order History
3378
+ // -------------------------------------------------------------------------
3435
3379
  {
3436
- name: "futures_get_fills",
3437
- module: "futures",
3438
- description: "Get FUTURES fill details. archive=false: last 3 days. archive=true: up to 3 months. Private. Rate limit: 20 req/s.",
3380
+ name: "onchain_earn_get_order_history",
3381
+ module: "earn.onchain",
3382
+ description: "Get on-chain earn order history. Returns past staking/DeFi investments including redeemed orders. Private endpoint. Rate limit: 3 req/s.",
3439
3383
  isWrite: false,
3440
3384
  inputSchema: {
3441
3385
  type: "object",
3442
3386
  properties: {
3443
- archive: {
3444
- type: "boolean",
3445
- description: "true=up to 3 months; false=last 3 days (default)"
3446
- },
3447
- instType: {
3387
+ productId: {
3448
3388
  type: "string",
3449
- enum: [...FUTURES_INST_TYPES],
3450
- description: "FUTURES (default) or SWAP"
3389
+ description: "Filter by product ID. Omit for all."
3451
3390
  },
3452
- instId: {
3391
+ protocolType: {
3453
3392
  type: "string",
3454
- description: "Instrument ID filter"
3393
+ description: "Filter by protocol type: staking, defi. Omit for all."
3455
3394
  },
3456
- ordId: {
3395
+ ccy: {
3457
3396
  type: "string",
3458
- description: "Order ID filter"
3397
+ description: "Filter by currency, e.g. ETH. Omit for all."
3459
3398
  },
3460
3399
  after: {
3461
3400
  type: "string",
3462
- description: "Pagination: before this bill ID"
3401
+ description: "Pagination: return results before this order ID"
3463
3402
  },
3464
3403
  before: {
3465
3404
  type: "string",
3466
- description: "Pagination: after this bill ID"
3467
- },
3468
- begin: {
3469
- type: "string",
3470
- description: "Start time (ms)"
3471
- },
3472
- end: {
3473
- type: "string",
3474
- description: "End time (ms)"
3405
+ description: "Pagination: return results after this order ID"
3475
3406
  },
3476
3407
  limit: {
3477
- type: "number",
3478
- description: "Max results (default 100 or 20 for archive)"
3408
+ type: "string",
3409
+ description: "Max results to return (default 100, max 100)"
3479
3410
  }
3480
3411
  }
3481
3412
  },
3482
3413
  handler: async (rawArgs, context) => {
3483
3414
  const args = asRecord(rawArgs);
3484
- const archive = readBoolean(args, "archive") ?? false;
3485
- const instType = readString(args, "instType") ?? "FUTURES";
3486
- assertEnum(instType, "instType", FUTURES_INST_TYPES);
3487
- const path4 = archive ? "/api/v5/trade/fills-history" : "/api/v5/trade/fills";
3488
3415
  const response = await context.client.privateGet(
3489
- path4,
3416
+ "/api/v5/finance/staking-defi/orders-history",
3490
3417
  compactObject({
3491
- instType,
3492
- instId: readString(args, "instId"),
3493
- ordId: readString(args, "ordId"),
3418
+ productId: readString(args, "productId"),
3419
+ protocolType: readString(args, "protocolType"),
3420
+ ccy: readString(args, "ccy"),
3494
3421
  after: readString(args, "after"),
3495
3422
  before: readString(args, "before"),
3496
- begin: readString(args, "begin"),
3497
- end: readString(args, "end"),
3498
- limit: readNumber(args, "limit") ?? (archive ? 20 : void 0)
3423
+ limit: readString(args, "limit")
3499
3424
  }),
3500
- privateRateLimit("futures_get_fills", 20)
3425
+ privateRateLimit("onchain_earn_get_order_history", 3)
3501
3426
  );
3502
- return normalize5(response);
3427
+ return normalizeResponse(response);
3503
3428
  }
3504
3429
  }
3505
3430
  ];
3506
3431
  }
3507
- function registerOnchainEarnTools() {
3432
+ var DCD_CODE_BEHAVIORS = {
3433
+ "50001": { retry: true, suggestion: "DCD service is down. Retry in a few minutes." },
3434
+ "50002": { retry: false, suggestion: "Invalid JSON in request body. This is likely a bug \u2014 check request parameters." },
3435
+ "50014": { retry: false, suggestion: "Missing required parameter. Check that all required fields are provided." },
3436
+ "50016": { retry: false, suggestion: "notionalCcy does not match productId option type. Use baseCcy for CALL, quoteCcy for PUT." },
3437
+ "50026": { retry: true, suggestion: "DCD system error. Retry in a few minutes." },
3438
+ "50030": { retry: false, suggestion: "Account not authorized for DCD (earn-auth check failed). Complete required verification in the OKX app first." },
3439
+ "50038": { retry: false, suggestion: "DCD Open API feature is disabled for this account. Contact OKX support to enable it." },
3440
+ "50051": { retry: false, suggestion: "This currency pair is restricted for your country or account type. Do not retry." },
3441
+ "51000": { retry: false, suggestion: "Invalid parameter value or format. Check ordId, quoteId, or clOrdId." },
3442
+ "51728": { retry: false, suggestion: "Available quota exceeded. Reduce the amount and retry." },
3443
+ "51736": { retry: false, suggestion: "Insufficient balance. Top up your account before retrying." },
3444
+ "52905": { retry: false, suggestion: "Quote has expired or was not found. Request a new quote." },
3445
+ "52909": { retry: false, suggestion: "Duplicate client order ID. Use a different clOrdId." },
3446
+ "52917": { retry: false, suggestion: "Amount is below the minimum trade size. Increase the amount." },
3447
+ "52918": { retry: false, suggestion: "Amount exceeds the maximum trade size. Reduce the amount." },
3448
+ "52921": { retry: false, suggestion: "Quote has already been used by another trade." },
3449
+ "52927": { retry: true, suggestion: "No quote returned by liquidity provider. Retry the quote request." },
3450
+ "52928": { retry: false, suggestion: "Amount is not divisible by the required step size. Adjust the amount." },
3451
+ "58004": { retry: false, suggestion: "Account is frozen or blocked. Contact OKX support. Do not retry." },
3452
+ "58102": { retry: true, suggestion: "DCD rate limit exceeded. Back off and retry after a short delay." }
3453
+ };
3454
+ async function withDcdErrors(fn) {
3455
+ try {
3456
+ return await fn();
3457
+ } catch (error) {
3458
+ if (error instanceof OkxApiError && error.code) {
3459
+ const behavior = DCD_CODE_BEHAVIORS[error.code];
3460
+ if (behavior) {
3461
+ if (behavior.retry) {
3462
+ throw new RateLimitError(error.message, behavior.suggestion, error.endpoint, error.traceId);
3463
+ }
3464
+ throw new OkxApiError(error.message, {
3465
+ code: error.code,
3466
+ suggestion: behavior.suggestion,
3467
+ endpoint: error.endpoint,
3468
+ traceId: error.traceId
3469
+ });
3470
+ }
3471
+ }
3472
+ throw error;
3473
+ }
3474
+ }
3475
+ function registerDcdTools() {
3508
3476
  return [
3509
- // -------------------------------------------------------------------------
3510
- // Get Offers
3511
- // -------------------------------------------------------------------------
3512
3477
  {
3513
- name: "onchain_earn_get_offers",
3514
- module: "earn.onchain",
3515
- description: "Get available on-chain earn (staking/DeFi) offers. Returns investment products with APY, terms, and limits. Private endpoint. Rate limit: 3 req/s.",
3478
+ name: "dcd_get_currency_pairs",
3479
+ module: "earn.dcd",
3480
+ description: "Get available DCD (Dual Currency Deposit) currency pairs. Private endpoint. Rate limit: 5 req/s.",
3481
+ isWrite: false,
3482
+ inputSchema: { type: "object", properties: {} },
3483
+ handler: async (_rawArgs, context) => {
3484
+ return withDcdErrors(async () => {
3485
+ const response = await context.client.privateGet(
3486
+ "/api/v5/finance/sfp/dcd/currency-pair",
3487
+ void 0,
3488
+ privateRateLimit("dcd_get_currency_pairs", 5)
3489
+ );
3490
+ return normalizeResponse(response);
3491
+ });
3492
+ }
3493
+ },
3494
+ {
3495
+ name: "dcd_get_products",
3496
+ module: "earn.dcd",
3497
+ description: "Get active DCD products with yield, trade size, quota, and VIP yield tier information. baseCcy, quoteCcy, and optType are all required. Private endpoint. Rate limit: 5 req/s.",
3516
3498
  isWrite: false,
3517
3499
  inputSchema: {
3518
3500
  type: "object",
3519
3501
  properties: {
3520
- productId: {
3502
+ baseCcy: { type: "string", description: "Base currency, e.g. BTC" },
3503
+ quoteCcy: { type: "string", description: "Quote currency, e.g. USDT" },
3504
+ optType: { type: "string", description: "Option type: C (Call/\u9AD8\u5356) or P (Put/\u4F4E\u4E70)" }
3505
+ },
3506
+ required: ["baseCcy", "quoteCcy", "optType"]
3507
+ },
3508
+ handler: async (rawArgs, context) => {
3509
+ const args = asRecord(rawArgs);
3510
+ return withDcdErrors(async () => {
3511
+ const response = await context.client.privateGet(
3512
+ "/api/v5/finance/sfp/dcd/products",
3513
+ {
3514
+ baseCcy: requireString(args, "baseCcy"),
3515
+ quoteCcy: requireString(args, "quoteCcy"),
3516
+ optType: requireString(args, "optType")
3517
+ },
3518
+ privateRateLimit("dcd_get_products", 5)
3519
+ );
3520
+ return normalizeResponse(response);
3521
+ });
3522
+ }
3523
+ },
3524
+ {
3525
+ name: "dcd_request_quote",
3526
+ module: "earn.dcd",
3527
+ description: "Request a real-time quote for a DCD product. Check validUntil for expiry time \u2014 execute before expiry. Yield reflects the user's actual VIP tier rate. Private endpoint. Rate limit: 5 req/s.",
3528
+ isWrite: false,
3529
+ // POST for payload, no state change
3530
+ inputSchema: {
3531
+ type: "object",
3532
+ properties: {
3533
+ productId: { type: "string", description: "Product ID, e.g. BTC-USDT-260327-77000-C" },
3534
+ notionalSz: { type: "string", description: "Investment amount" },
3535
+ notionalCcy: { type: "string", description: "Investment currency: baseCcy for CALL (C), quoteCcy for PUT (P)" }
3536
+ },
3537
+ required: ["productId", "notionalSz", "notionalCcy"]
3538
+ },
3539
+ handler: async (rawArgs, context) => {
3540
+ const args = asRecord(rawArgs);
3541
+ return withDcdErrors(async () => {
3542
+ const response = await context.client.privatePost(
3543
+ "/api/v5/finance/sfp/dcd/quote",
3544
+ {
3545
+ productId: requireString(args, "productId"),
3546
+ notionalSz: requireString(args, "notionalSz"),
3547
+ notionalCcy: requireString(args, "notionalCcy")
3548
+ },
3549
+ privateRateLimit("dcd_request_quote", 5)
3550
+ );
3551
+ return normalizeResponse(response);
3552
+ });
3553
+ }
3554
+ },
3555
+ {
3556
+ name: "dcd_execute_quote",
3557
+ module: "earn.dcd",
3558
+ description: "Execute a DCD quote to place a trade. [CAUTION] Moves real funds into DCD product. Quote expires \u2014 call immediately after dcd_request_quote. Not supported in demo/simulated trading mode. Private endpoint. Rate limit: 5 req/s.",
3559
+ isWrite: true,
3560
+ inputSchema: {
3561
+ type: "object",
3562
+ properties: {
3563
+ quoteId: { type: "string", description: "Quote ID from dcd_request_quote" },
3564
+ clOrdId: { type: "string", description: "Client order ID for idempotency (optional)" }
3565
+ },
3566
+ required: ["quoteId"]
3567
+ },
3568
+ handler: async (rawArgs, context) => {
3569
+ assertNotDemo(context.config, "dcd_execute_quote");
3570
+ const args = asRecord(rawArgs);
3571
+ return withDcdErrors(async () => {
3572
+ const response = await context.client.privatePost(
3573
+ "/api/v5/finance/sfp/dcd/trade",
3574
+ compactObject({
3575
+ quoteId: requireString(args, "quoteId"),
3576
+ clOrdId: readString(args, "clOrdId")
3577
+ }),
3578
+ privateRateLimit("dcd_execute_quote", 5)
3579
+ );
3580
+ return normalizeResponse(response);
3581
+ });
3582
+ }
3583
+ },
3584
+ {
3585
+ name: "dcd_request_redeem_quote",
3586
+ module: "earn.dcd",
3587
+ description: "Request an early redemption quote for a live DCD order. Check validUntil for expiry. Private endpoint. Rate limit: 5 req/s.",
3588
+ isWrite: false,
3589
+ inputSchema: {
3590
+ type: "object",
3591
+ properties: {
3592
+ ordId: { type: "string", description: "Order ID to redeem early" }
3593
+ },
3594
+ required: ["ordId"]
3595
+ },
3596
+ handler: async (rawArgs, context) => {
3597
+ const args = asRecord(rawArgs);
3598
+ return withDcdErrors(async () => {
3599
+ const response = await context.client.privatePost(
3600
+ "/api/v5/finance/sfp/dcd/redeem-quote",
3601
+ { ordId: requireString(args, "ordId") },
3602
+ privateRateLimit("dcd_request_redeem_quote", 5)
3603
+ );
3604
+ return normalizeResponse(response);
3605
+ });
3606
+ }
3607
+ },
3608
+ {
3609
+ name: "dcd_execute_redeem",
3610
+ module: "earn.dcd",
3611
+ description: "Execute an early redemption using a valid redeem quote. [CAUTION] Initiates early redemption of a DCD position. Not supported in demo/simulated trading mode. Private endpoint. Rate limit: 5 req/s.",
3612
+ isWrite: true,
3613
+ inputSchema: {
3614
+ type: "object",
3615
+ properties: {
3616
+ ordId: { type: "string", description: "Order ID" },
3617
+ quoteId: { type: "string", description: "Redeem quote ID from dcd_request_redeem_quote" }
3618
+ },
3619
+ required: ["ordId", "quoteId"]
3620
+ },
3621
+ handler: async (rawArgs, context) => {
3622
+ assertNotDemo(context.config, "dcd_execute_redeem");
3623
+ const args = asRecord(rawArgs);
3624
+ return withDcdErrors(async () => {
3625
+ const response = await context.client.privatePost(
3626
+ "/api/v5/finance/sfp/dcd/redeem",
3627
+ {
3628
+ ordId: requireString(args, "ordId"),
3629
+ quoteId: requireString(args, "quoteId")
3630
+ },
3631
+ privateRateLimit("dcd_execute_redeem", 5)
3632
+ );
3633
+ return normalizeResponse(response);
3634
+ });
3635
+ }
3636
+ },
3637
+ {
3638
+ name: "dcd_get_order_state",
3639
+ module: "earn.dcd",
3640
+ description: "Query DCD order state by order ID. Private endpoint. Rate limit: 5 req/s.",
3641
+ isWrite: false,
3642
+ inputSchema: {
3643
+ type: "object",
3644
+ properties: {
3645
+ ordId: { type: "string", description: "Order ID" }
3646
+ },
3647
+ required: ["ordId"]
3648
+ },
3649
+ handler: async (rawArgs, context) => {
3650
+ const args = asRecord(rawArgs);
3651
+ return withDcdErrors(async () => {
3652
+ const response = await context.client.privateGet(
3653
+ "/api/v5/finance/sfp/dcd/order-status",
3654
+ { ordId: requireString(args, "ordId") },
3655
+ privateRateLimit("dcd_get_order_state", 5)
3656
+ );
3657
+ return normalizeResponse(response);
3658
+ });
3659
+ }
3660
+ },
3661
+ {
3662
+ name: "dcd_get_orders",
3663
+ module: "earn.dcd",
3664
+ description: "Get DCD order history with optional filters. Returns up to 100 records per request. Private endpoint. Rate limit: 5 req/s.",
3665
+ isWrite: false,
3666
+ inputSchema: {
3667
+ type: "object",
3668
+ properties: {
3669
+ ordId: { type: "string", description: "Filter by specific order ID (ignores other filters when provided)" },
3670
+ productId: { type: "string", description: "Filter by product ID, e.g. BTC-USDT-260327-77000-C" },
3671
+ uly: { type: "string", description: "Filter by underlying index, e.g. BTC-USD" },
3672
+ state: {
3521
3673
  type: "string",
3522
- description: "Specific product ID to query. Omit for all offers."
3674
+ description: "Filter by state: initial | live | pending_settle | settled | pending_redeem | redeemed | rejected"
3523
3675
  },
3524
- protocolType: {
3676
+ beginId: { type: "string", description: "Return records newer than this order ID (pagination)" },
3677
+ endId: { type: "string", description: "Return records older than this order ID (pagination)" },
3678
+ begin: { type: "string", description: "Begin timestamp filter, Unix ms" },
3679
+ end: { type: "string", description: "End timestamp filter, Unix ms" },
3680
+ limit: { type: "number", description: "Results per request, max 100 (default 100)" }
3681
+ }
3682
+ },
3683
+ handler: async (rawArgs, context) => {
3684
+ const args = asRecord(rawArgs);
3685
+ return withDcdErrors(async () => {
3686
+ const response = await context.client.privateGet(
3687
+ "/api/v5/finance/sfp/dcd/order-history",
3688
+ compactObject({
3689
+ ordId: readString(args, "ordId"),
3690
+ productId: readString(args, "productId"),
3691
+ uly: readString(args, "uly"),
3692
+ state: readString(args, "state"),
3693
+ beginId: readString(args, "beginId"),
3694
+ endId: readString(args, "endId"),
3695
+ begin: readString(args, "begin"),
3696
+ end: readString(args, "end"),
3697
+ limit: readNumber(args, "limit")
3698
+ }),
3699
+ privateRateLimit("dcd_get_orders", 5)
3700
+ );
3701
+ return normalizeResponse(response);
3702
+ });
3703
+ }
3704
+ }
3705
+ ];
3706
+ }
3707
+ function registerAllEarnTools() {
3708
+ return [
3709
+ ...registerEarnTools(),
3710
+ ...registerOnchainEarnTools(),
3711
+ ...registerDcdTools()
3712
+ ];
3713
+ }
3714
+ var FUTURES_INST_TYPES = ["FUTURES", "SWAP"];
3715
+ function normalize5(response) {
3716
+ return {
3717
+ endpoint: response.endpoint,
3718
+ requestTime: response.requestTime,
3719
+ data: response.data
3720
+ };
3721
+ }
3722
+ function registerFuturesTools() {
3723
+ return [
3724
+ {
3725
+ name: "futures_place_order",
3726
+ module: "futures",
3727
+ description: "Place a FUTURES delivery contract order (e.g. instId: BTC-USDT-240329). Optionally attach TP/SL via tpTriggerPx/slTriggerPx. [CAUTION] Executes real trades. Private endpoint. Rate limit: 60 req/s.",
3728
+ isWrite: true,
3729
+ inputSchema: {
3730
+ type: "object",
3731
+ properties: {
3732
+ instId: {
3525
3733
  type: "string",
3526
- description: "Protocol type filter: staking, defi. Omit for all types."
3734
+ description: "e.g. BTC-USDT-240329"
3527
3735
  },
3528
- ccy: {
3736
+ tdMode: {
3529
3737
  type: "string",
3530
- description: "Currency filter, e.g. ETH. Omit for all currencies."
3738
+ enum: ["cross", "isolated"],
3739
+ description: "cross|isolated margin"
3740
+ },
3741
+ side: {
3742
+ type: "string",
3743
+ enum: ["buy", "sell"],
3744
+ description: "one-way: buy=open long, sell=open short (use reduceOnly=true to close); hedge: combined with posSide"
3745
+ },
3746
+ posSide: {
3747
+ type: "string",
3748
+ enum: ["long", "short", "net"],
3749
+ description: "net=one-way mode (default); long/short=hedge mode only"
3750
+ },
3751
+ ordType: {
3752
+ type: "string",
3753
+ enum: ["market", "limit", "post_only", "fok", "ioc"],
3754
+ description: "market(no px)|limit(px req)|post_only(maker)|fok(all-or-cancel)|ioc(partial fill)"
3755
+ },
3756
+ sz: {
3757
+ type: "string",
3758
+ description: "Number of contracts (NOT USDT amount). Use market_get_instruments to get ctVal for conversion."
3759
+ },
3760
+ px: {
3761
+ type: "string",
3762
+ description: "Required for limit/post_only/fok/ioc"
3763
+ },
3764
+ reduceOnly: {
3765
+ type: "boolean",
3766
+ description: "Close/reduce only, no new position (one-way mode)"
3767
+ },
3768
+ clOrdId: {
3769
+ type: "string",
3770
+ description: "Client order ID (max 32 chars)"
3771
+ },
3772
+ tpTriggerPx: {
3773
+ type: "string",
3774
+ description: "TP trigger price; places TP at tpOrdPx"
3775
+ },
3776
+ tpOrdPx: {
3777
+ type: "string",
3778
+ description: "TP order price; -1=market"
3779
+ },
3780
+ slTriggerPx: {
3781
+ type: "string",
3782
+ description: "SL trigger price; places SL at slOrdPx"
3783
+ },
3784
+ slOrdPx: {
3785
+ type: "string",
3786
+ description: "SL order price; -1=market"
3531
3787
  }
3532
- }
3788
+ },
3789
+ required: ["instId", "tdMode", "side", "ordType", "sz"]
3533
3790
  },
3534
3791
  handler: async (rawArgs, context) => {
3535
3792
  const args = asRecord(rawArgs);
3536
- const response = await context.client.privateGet(
3537
- "/api/v5/finance/staking-defi/offers",
3793
+ const reduceOnly = args.reduceOnly;
3794
+ const tpTriggerPx = readString(args, "tpTriggerPx");
3795
+ const tpOrdPx = readString(args, "tpOrdPx");
3796
+ const slTriggerPx = readString(args, "slTriggerPx");
3797
+ const slOrdPx = readString(args, "slOrdPx");
3798
+ const algoEntry = compactObject({ tpTriggerPx, tpOrdPx, slTriggerPx, slOrdPx });
3799
+ const attachAlgoOrds = Object.keys(algoEntry).length > 0 ? [algoEntry] : void 0;
3800
+ const response = await context.client.privatePost(
3801
+ "/api/v5/trade/order",
3538
3802
  compactObject({
3539
- productId: readString(args, "productId"),
3540
- protocolType: readString(args, "protocolType"),
3541
- ccy: readString(args, "ccy")
3803
+ instId: requireString(args, "instId"),
3804
+ tdMode: requireString(args, "tdMode"),
3805
+ side: requireString(args, "side"),
3806
+ posSide: readString(args, "posSide"),
3807
+ ordType: requireString(args, "ordType"),
3808
+ sz: requireString(args, "sz"),
3809
+ px: readString(args, "px"),
3810
+ reduceOnly: typeof reduceOnly === "boolean" ? String(reduceOnly) : void 0,
3811
+ clOrdId: readString(args, "clOrdId"),
3812
+ tag: context.config.sourceTag,
3813
+ attachAlgoOrds
3542
3814
  }),
3543
- privateRateLimit("onchain_earn_get_offers", 3)
3815
+ privateRateLimit("futures_place_order", 60)
3544
3816
  );
3545
- return normalizeResponse(response);
3817
+ return normalize5(response);
3546
3818
  }
3547
3819
  },
3548
- // -------------------------------------------------------------------------
3549
- // Purchase
3550
- // -------------------------------------------------------------------------
3551
3820
  {
3552
- name: "onchain_earn_purchase",
3553
- module: "earn.onchain",
3554
- description: "Purchase on-chain earn (staking/DeFi) product. [CAUTION] Moves real funds into staking/DeFi product. Not supported in demo/simulated trading mode. Private endpoint. Rate limit: 2 req/s.",
3821
+ name: "futures_cancel_order",
3822
+ module: "futures",
3823
+ description: "Cancel an unfilled FUTURES delivery order. Private endpoint. Rate limit: 60 req/s.",
3555
3824
  isWrite: true,
3556
3825
  inputSchema: {
3557
3826
  type: "object",
3558
3827
  properties: {
3559
- productId: {
3828
+ instId: {
3560
3829
  type: "string",
3561
- description: "Product ID to purchase"
3562
- },
3563
- investData: {
3564
- type: "array",
3565
- description: "Investment data array: [{ccy, amt}]. Each item specifies currency and amount.",
3566
- items: {
3567
- type: "object",
3568
- properties: {
3569
- ccy: { type: "string", description: "Currency, e.g. ETH" },
3570
- amt: { type: "string", description: "Amount to invest" }
3571
- },
3572
- required: ["ccy", "amt"]
3573
- }
3830
+ description: "e.g. BTC-USDT-240329"
3574
3831
  },
3575
- term: {
3576
- type: "string",
3577
- description: "Investment term in days. Required for fixed-term products."
3832
+ ordId: {
3833
+ type: "string"
3578
3834
  },
3579
- tag: {
3835
+ clOrdId: {
3580
3836
  type: "string",
3581
- description: "Order tag for tracking (optional)."
3837
+ description: "Client order ID"
3582
3838
  }
3583
3839
  },
3584
- required: ["productId", "investData"]
3840
+ required: ["instId"]
3585
3841
  },
3586
3842
  handler: async (rawArgs, context) => {
3587
- assertNotDemo(context.config, "onchain_earn_purchase");
3588
3843
  const args = asRecord(rawArgs);
3589
3844
  const response = await context.client.privatePost(
3590
- "/api/v5/finance/staking-defi/purchase",
3845
+ "/api/v5/trade/cancel-order",
3591
3846
  compactObject({
3592
- productId: requireString(args, "productId"),
3593
- investData: args.investData,
3594
- term: readString(args, "term"),
3595
- tag: readString(args, "tag")
3847
+ instId: requireString(args, "instId"),
3848
+ ordId: readString(args, "ordId"),
3849
+ clOrdId: readString(args, "clOrdId")
3596
3850
  }),
3597
- privateRateLimit("onchain_earn_purchase", 2)
3851
+ privateRateLimit("futures_cancel_order", 60)
3598
3852
  );
3599
- return normalizeResponse(response);
3853
+ return normalize5(response);
3600
3854
  }
3601
3855
  },
3602
- // -------------------------------------------------------------------------
3603
- // Redeem
3604
- // -------------------------------------------------------------------------
3605
3856
  {
3606
- name: "onchain_earn_redeem",
3607
- module: "earn.onchain",
3608
- description: "Redeem on-chain earn (staking/DeFi) investment. [CAUTION] Withdraws funds from staking/DeFi product. Some products may have lock periods. Not supported in demo mode. Private endpoint. Rate limit: 2 req/s.",
3609
- isWrite: true,
3857
+ name: "futures_get_order",
3858
+ module: "futures",
3859
+ description: "Get details of a single FUTURES delivery order by ordId or clOrdId. Private endpoint. Rate limit: 60 req/s.",
3860
+ isWrite: false,
3610
3861
  inputSchema: {
3611
3862
  type: "object",
3612
3863
  properties: {
3613
- ordId: {
3864
+ instId: {
3614
3865
  type: "string",
3615
- description: "Order ID to redeem"
3866
+ description: "e.g. BTC-USDT-240329"
3616
3867
  },
3617
- protocolType: {
3868
+ ordId: {
3618
3869
  type: "string",
3619
- description: "Protocol type: staking, defi"
3870
+ description: "Provide ordId or clOrdId"
3620
3871
  },
3621
- allowEarlyRedeem: {
3622
- type: "boolean",
3623
- description: "Allow early redemption for fixed-term products (may incur penalties). Default false."
3872
+ clOrdId: {
3873
+ type: "string",
3874
+ description: "Provide ordId or clOrdId"
3624
3875
  }
3625
3876
  },
3626
- required: ["ordId", "protocolType"]
3877
+ required: ["instId"]
3627
3878
  },
3628
3879
  handler: async (rawArgs, context) => {
3629
- assertNotDemo(context.config, "onchain_earn_redeem");
3630
3880
  const args = asRecord(rawArgs);
3631
- const response = await context.client.privatePost(
3632
- "/api/v5/finance/staking-defi/redeem",
3881
+ const response = await context.client.privateGet(
3882
+ "/api/v5/trade/order",
3633
3883
  compactObject({
3634
- ordId: requireString(args, "ordId"),
3635
- protocolType: requireString(args, "protocolType"),
3636
- allowEarlyRedeem: readBoolean(args, "allowEarlyRedeem")
3884
+ instId: requireString(args, "instId"),
3885
+ ordId: readString(args, "ordId"),
3886
+ clOrdId: readString(args, "clOrdId")
3637
3887
  }),
3638
- privateRateLimit("onchain_earn_redeem", 2)
3888
+ privateRateLimit("futures_get_order", 60)
3639
3889
  );
3640
- return normalizeResponse(response);
3890
+ return normalize5(response);
3641
3891
  }
3642
3892
  },
3643
- // -------------------------------------------------------------------------
3644
- // Cancel
3645
- // -------------------------------------------------------------------------
3646
3893
  {
3647
- name: "onchain_earn_cancel",
3648
- module: "earn.onchain",
3649
- description: "Cancel pending on-chain earn purchase. [CAUTION] Cancels a pending investment order. Not supported in demo mode. Private endpoint. Rate limit: 2 req/s.",
3650
- isWrite: true,
3894
+ name: "futures_get_orders",
3895
+ module: "futures",
3896
+ description: "Query FUTURES open orders, history (last 7 days), or archive (up to 3 months). Private. Rate limit: 20 req/s.",
3897
+ isWrite: false,
3651
3898
  inputSchema: {
3652
3899
  type: "object",
3653
3900
  properties: {
3654
- ordId: {
3901
+ status: {
3655
3902
  type: "string",
3656
- description: "Order ID to cancel"
3903
+ enum: ["open", "history", "archive"],
3904
+ description: "open=active, history=7d, archive=3mo"
3657
3905
  },
3658
- protocolType: {
3906
+ instType: {
3659
3907
  type: "string",
3660
- description: "Protocol type: staking, defi"
3908
+ enum: [...FUTURES_INST_TYPES],
3909
+ description: "FUTURES (default) or SWAP"
3910
+ },
3911
+ instId: {
3912
+ type: "string",
3913
+ description: "e.g. BTC-USDT-240329"
3914
+ },
3915
+ ordType: {
3916
+ type: "string",
3917
+ description: "Order type filter"
3918
+ },
3919
+ state: {
3920
+ type: "string",
3921
+ description: "canceled|filled"
3922
+ },
3923
+ after: {
3924
+ type: "string",
3925
+ description: "Pagination: before this order ID"
3926
+ },
3927
+ before: {
3928
+ type: "string",
3929
+ description: "Pagination: after this order ID"
3930
+ },
3931
+ begin: {
3932
+ type: "string",
3933
+ description: "Start time (ms)"
3934
+ },
3935
+ end: {
3936
+ type: "string",
3937
+ description: "End time (ms)"
3938
+ },
3939
+ limit: {
3940
+ type: "number",
3941
+ description: "Max results (default 100)"
3661
3942
  }
3662
- },
3663
- required: ["ordId", "protocolType"]
3943
+ }
3664
3944
  },
3665
3945
  handler: async (rawArgs, context) => {
3666
- assertNotDemo(context.config, "onchain_earn_cancel");
3667
3946
  const args = asRecord(rawArgs);
3668
- const response = await context.client.privatePost(
3669
- "/api/v5/finance/staking-defi/cancel",
3670
- {
3671
- ordId: requireString(args, "ordId"),
3672
- protocolType: requireString(args, "protocolType")
3673
- },
3674
- privateRateLimit("onchain_earn_cancel", 2)
3947
+ const status = readString(args, "status") ?? "open";
3948
+ const instType = readString(args, "instType") ?? "FUTURES";
3949
+ assertEnum(instType, "instType", FUTURES_INST_TYPES);
3950
+ const path4 = status === "archive" ? "/api/v5/trade/orders-history-archive" : status === "history" ? "/api/v5/trade/orders-history" : "/api/v5/trade/orders-pending";
3951
+ const response = await context.client.privateGet(
3952
+ path4,
3953
+ compactObject({
3954
+ instType,
3955
+ instId: readString(args, "instId"),
3956
+ ordType: readString(args, "ordType"),
3957
+ state: readString(args, "state"),
3958
+ after: readString(args, "after"),
3959
+ before: readString(args, "before"),
3960
+ begin: readString(args, "begin"),
3961
+ end: readString(args, "end"),
3962
+ limit: readNumber(args, "limit")
3963
+ }),
3964
+ privateRateLimit("futures_get_orders", 20)
3675
3965
  );
3676
- return normalizeResponse(response);
3966
+ return normalize5(response);
3677
3967
  }
3678
3968
  },
3679
- // -------------------------------------------------------------------------
3680
- // Get Active Orders
3681
- // -------------------------------------------------------------------------
3682
3969
  {
3683
- name: "onchain_earn_get_active_orders",
3684
- module: "earn.onchain",
3685
- description: "Get active on-chain earn orders. Returns current staking/DeFi investments. Private endpoint. Rate limit: 3 req/s.",
3970
+ name: "futures_get_positions",
3971
+ module: "futures",
3972
+ description: "Get current FUTURES delivery contract positions. Private endpoint. Rate limit: 10 req/s.",
3686
3973
  isWrite: false,
3687
3974
  inputSchema: {
3688
3975
  type: "object",
3689
3976
  properties: {
3690
- productId: {
3691
- type: "string",
3692
- description: "Filter by product ID. Omit for all."
3693
- },
3694
- protocolType: {
3977
+ instType: {
3695
3978
  type: "string",
3696
- description: "Filter by protocol type: staking, defi. Omit for all."
3979
+ enum: [...FUTURES_INST_TYPES],
3980
+ description: "FUTURES (default) or SWAP"
3697
3981
  },
3698
- ccy: {
3982
+ instId: {
3699
3983
  type: "string",
3700
- description: "Filter by currency, e.g. ETH. Omit for all."
3984
+ description: "e.g. BTC-USDT-240329"
3701
3985
  },
3702
- state: {
3703
- type: "string",
3704
- description: "Filter by state: 8 (pending), 13 (cancelling), 9 (onchain), 1 (earning), 2 (redeeming). Omit for all."
3986
+ posId: {
3987
+ type: "string"
3705
3988
  }
3706
3989
  }
3707
3990
  },
3708
3991
  handler: async (rawArgs, context) => {
3709
3992
  const args = asRecord(rawArgs);
3993
+ const instType = readString(args, "instType") ?? "FUTURES";
3994
+ assertEnum(instType, "instType", FUTURES_INST_TYPES);
3710
3995
  const response = await context.client.privateGet(
3711
- "/api/v5/finance/staking-defi/orders-active",
3996
+ "/api/v5/account/positions",
3712
3997
  compactObject({
3713
- productId: readString(args, "productId"),
3714
- protocolType: readString(args, "protocolType"),
3715
- ccy: readString(args, "ccy"),
3716
- state: readString(args, "state")
3998
+ instType,
3999
+ instId: readString(args, "instId"),
4000
+ posId: readString(args, "posId")
3717
4001
  }),
3718
- privateRateLimit("onchain_earn_get_active_orders", 3)
4002
+ privateRateLimit("futures_get_positions", 10)
3719
4003
  );
3720
- return normalizeResponse(response);
4004
+ return normalize5(response);
3721
4005
  }
3722
4006
  },
3723
- // -------------------------------------------------------------------------
3724
- // Get Order History
3725
- // -------------------------------------------------------------------------
3726
4007
  {
3727
- name: "onchain_earn_get_order_history",
3728
- module: "earn.onchain",
3729
- description: "Get on-chain earn order history. Returns past staking/DeFi investments including redeemed orders. Private endpoint. Rate limit: 3 req/s.",
4008
+ name: "futures_get_fills",
4009
+ module: "futures",
4010
+ description: "Get FUTURES fill details. archive=false: last 3 days. archive=true: up to 3 months. Private. Rate limit: 20 req/s.",
3730
4011
  isWrite: false,
3731
4012
  inputSchema: {
3732
4013
  type: "object",
3733
4014
  properties: {
3734
- productId: {
4015
+ archive: {
4016
+ type: "boolean",
4017
+ description: "true=up to 3 months; false=last 3 days (default)"
4018
+ },
4019
+ instType: {
3735
4020
  type: "string",
3736
- description: "Filter by product ID. Omit for all."
4021
+ enum: [...FUTURES_INST_TYPES],
4022
+ description: "FUTURES (default) or SWAP"
3737
4023
  },
3738
- protocolType: {
4024
+ instId: {
3739
4025
  type: "string",
3740
- description: "Filter by protocol type: staking, defi. Omit for all."
4026
+ description: "Instrument ID filter"
3741
4027
  },
3742
- ccy: {
4028
+ ordId: {
3743
4029
  type: "string",
3744
- description: "Filter by currency, e.g. ETH. Omit for all."
4030
+ description: "Order ID filter"
4031
+ },
4032
+ after: {
4033
+ type: "string",
4034
+ description: "Pagination: before this bill ID"
4035
+ },
4036
+ before: {
4037
+ type: "string",
4038
+ description: "Pagination: after this bill ID"
3745
4039
  },
3746
- after: {
4040
+ begin: {
3747
4041
  type: "string",
3748
- description: "Pagination: return results before this order ID"
4042
+ description: "Start time (ms)"
3749
4043
  },
3750
- before: {
4044
+ end: {
3751
4045
  type: "string",
3752
- description: "Pagination: return results after this order ID"
4046
+ description: "End time (ms)"
3753
4047
  },
3754
4048
  limit: {
3755
- type: "string",
3756
- description: "Max results to return (default 100, max 100)"
4049
+ type: "number",
4050
+ description: "Max results (default 100 or 20 for archive)"
3757
4051
  }
3758
4052
  }
3759
4053
  },
3760
4054
  handler: async (rawArgs, context) => {
3761
4055
  const args = asRecord(rawArgs);
4056
+ const archive = readBoolean(args, "archive") ?? false;
4057
+ const instType = readString(args, "instType") ?? "FUTURES";
4058
+ assertEnum(instType, "instType", FUTURES_INST_TYPES);
4059
+ const path4 = archive ? "/api/v5/trade/fills-history" : "/api/v5/trade/fills";
3762
4060
  const response = await context.client.privateGet(
3763
- "/api/v5/finance/staking-defi/orders-history",
4061
+ path4,
3764
4062
  compactObject({
3765
- productId: readString(args, "productId"),
3766
- protocolType: readString(args, "protocolType"),
3767
- ccy: readString(args, "ccy"),
4063
+ instType,
4064
+ instId: readString(args, "instId"),
4065
+ ordId: readString(args, "ordId"),
3768
4066
  after: readString(args, "after"),
3769
4067
  before: readString(args, "before"),
3770
- limit: readString(args, "limit")
4068
+ begin: readString(args, "begin"),
4069
+ end: readString(args, "end"),
4070
+ limit: readNumber(args, "limit") ?? (archive ? 20 : void 0)
3771
4071
  }),
3772
- privateRateLimit("onchain_earn_get_order_history", 3)
4072
+ privateRateLimit("futures_get_fills", 20)
3773
4073
  );
3774
- return normalizeResponse(response);
4074
+ return normalize5(response);
3775
4075
  }
3776
4076
  }
3777
4077
  ];
@@ -4253,6 +4553,40 @@ function registerMarketTools() {
4253
4553
  );
4254
4554
  return normalize6(response);
4255
4555
  }
4556
+ },
4557
+ {
4558
+ name: "market_get_stock_tokens",
4559
+ module: "market",
4560
+ description: "Get all stock token instruments (instCategory=3). Stock tokens track real-world stock prices on OKX (e.g. AAPL-USDT-SWAP, TSLA-USDT-SWAP). Fetches all instruments of the given type and filters client-side by instCategory=3. Public endpoint. Rate limit: 20 req/s.",
4561
+ isWrite: false,
4562
+ inputSchema: {
4563
+ type: "object",
4564
+ properties: {
4565
+ instType: {
4566
+ type: "string",
4567
+ enum: ["SPOT", "SWAP"],
4568
+ description: "Instrument type. Default: SWAP"
4569
+ },
4570
+ instId: {
4571
+ type: "string",
4572
+ description: "Optional: filter by specific instrument ID, e.g. AAPL-USDT-SWAP"
4573
+ }
4574
+ },
4575
+ required: []
4576
+ },
4577
+ handler: async (rawArgs, context) => {
4578
+ const args = asRecord(rawArgs);
4579
+ const instType = readString(args, "instType") ?? "SWAP";
4580
+ const instId = readString(args, "instId");
4581
+ const response = await context.client.publicGet(
4582
+ "/api/v5/public/instruments",
4583
+ compactObject({ instType, instId }),
4584
+ publicRateLimit("market_get_stock_tokens", 20)
4585
+ );
4586
+ const data = response.data;
4587
+ const filtered = Array.isArray(data) ? data.filter((item) => item.instCategory === "3") : data;
4588
+ return normalize6({ ...response, data: filtered });
4589
+ }
4256
4590
  }
4257
4591
  ];
4258
4592
  }
@@ -4772,17 +5106,20 @@ function registerSpotTradeTools() {
4772
5106
  description: "e.g. BTC-USDT"
4773
5107
  },
4774
5108
  ordId: {
4775
- type: "string"
5109
+ type: "string",
5110
+ description: "Order ID"
4776
5111
  },
4777
5112
  clOrdId: {
4778
5113
  type: "string",
4779
5114
  description: "Client order ID"
4780
5115
  },
4781
5116
  newSz: {
4782
- type: "string"
5117
+ type: "string",
5118
+ description: "New order size in base currency (e.g. BTC amount)"
4783
5119
  },
4784
5120
  newPx: {
4785
- type: "string"
5121
+ type: "string",
5122
+ description: "New order price"
4786
5123
  },
4787
5124
  newClOrdId: {
4788
5125
  type: "string",
@@ -4957,7 +5294,7 @@ function registerSpotTradeTools() {
4957
5294
  properties: {
4958
5295
  instId: { type: "string", description: "e.g. BTC-USDT" },
4959
5296
  algoId: { type: "string", description: "Algo order ID" },
4960
- newSz: { type: "string" },
5297
+ newSz: { type: "string", description: "New order size in base currency (e.g. BTC amount)" },
4961
5298
  newTpTriggerPx: { type: "string", description: "New TP trigger price" },
4962
5299
  newTpOrdPx: { type: "string", description: "New TP order price; -1=market" },
4963
5300
  newSlTriggerPx: { type: "string", description: "New SL trigger price" },
@@ -5980,8 +6317,7 @@ function allToolSpecs() {
5980
6317
  ...registerAlgoTradeTools(),
5981
6318
  ...registerAccountTools(),
5982
6319
  ...registerBotTools(),
5983
- ...registerEarnTools(),
5984
- ...registerOnchainEarnTools(),
6320
+ ...registerAllEarnTools(),
5985
6321
  ...registerAuditTools()
5986
6322
  ];
5987
6323
  }
@@ -6355,7 +6691,7 @@ function readCliVersion() {
6355
6691
  return "0.0.0";
6356
6692
  }
6357
6693
  var CLI_VERSION = readCliVersion();
6358
- var GIT_HASH = true ? "4427916" : "dev";
6694
+ var GIT_HASH = true ? "1df90cc" : "dev";
6359
6695
  var Report = class {
6360
6696
  lines = [];
6361
6697
  add(key, value) {
@@ -6582,18 +6918,19 @@ async function checkNetwork(config, client, report) {
6582
6918
  }
6583
6919
  return passed;
6584
6920
  }
6585
- function getAuthHints(msg) {
6921
+ function getAuthHints(msg, baseUrl) {
6922
+ const accountUrl = baseUrl.replace(/\/+$/, "") + "/account/my-api";
6586
6923
  if (msg.includes("50111") || msg.includes("Invalid OK-ACCESS-KEY")) {
6587
- return ["API key is invalid or expired", "Regenerate at https://www.okx.com/account/my-api"];
6924
+ return ["API key is invalid or expired", `Regenerate at ${accountUrl}`];
6588
6925
  }
6589
6926
  if (msg.includes("50112") || msg.includes("Invalid Sign")) {
6590
- return ["Secret key or passphrase may be wrong", "Regenerate API key at https://www.okx.com/account/my-api"];
6927
+ return ["Secret key or passphrase may be wrong", `Regenerate API key at ${accountUrl}`];
6591
6928
  }
6592
6929
  if (msg.includes("50113")) {
6593
6930
  return ["Passphrase is incorrect"];
6594
6931
  }
6595
6932
  if (msg.includes("50100")) {
6596
- return ["API key lacks required permissions", "Update permissions at https://www.okx.com/account/my-api"];
6933
+ return ["API key lacks required permissions", `Update permissions at ${accountUrl}`];
6597
6934
  }
6598
6935
  return ["Check API credentials and permissions"];
6599
6936
  }
@@ -6616,7 +6953,7 @@ async function checkAuth(client, config, report) {
6616
6953
  } catch (e) {
6617
6954
  const ms = Date.now() - t1;
6618
6955
  const msg = e instanceof Error ? e.message : String(e);
6619
- const hints = getAuthHints(msg);
6956
+ const hints = getAuthHints(msg, config.baseUrl);
6620
6957
  fail("Account balance", msg, hints);
6621
6958
  passed = false;
6622
6959
  report.add("auth_api", `FAIL /account/balance ${msg} (${ms}ms)`);
@@ -6738,6 +7075,10 @@ var HELP_TREE = {
6738
7075
  "open-interest": {
6739
7076
  usage: "okx market open-interest --instType <SWAP|FUTURES|OPTION> [--instId <id>]",
6740
7077
  description: "Get open interest for instruments"
7078
+ },
7079
+ "stock-tokens": {
7080
+ usage: "okx market stock-tokens [--instType <SPOT|SWAP>] [--instId <id>]",
7081
+ description: "List all stock token instruments (instCategory=3, e.g. AAPL-USDT-SWAP)"
6741
7082
  }
6742
7083
  }
6743
7084
  },
@@ -7005,7 +7346,7 @@ var HELP_TREE = {
7005
7346
  }
7006
7347
  },
7007
7348
  earn: {
7008
- description: "Earn products \u2014 Simple Earn (savings/lending) and On-chain Earn (staking/DeFi)",
7349
+ description: "Earn products \u2014 Simple Earn, On-chain Earn, and DCD (Dual Currency Deposit)",
7009
7350
  subgroups: {
7010
7351
  savings: {
7011
7352
  description: "Simple Earn \u2014 flexible savings and lending",
@@ -7068,6 +7409,51 @@ var HELP_TREE = {
7068
7409
  description: "Get on-chain earn order history"
7069
7410
  }
7070
7411
  }
7412
+ },
7413
+ dcd: {
7414
+ description: "DCD (Dual Currency Deposit) \u2014 structured products with fixed yield",
7415
+ commands: {
7416
+ pairs: {
7417
+ usage: "okx earn dcd pairs",
7418
+ description: "List available DCD currency pairs"
7419
+ },
7420
+ products: {
7421
+ usage: "okx earn dcd products --baseCcy <ccy> --quoteCcy <ccy> --optType <C|P>\n [--minYield <n>] [--strikeNear <price>]\n [--termDays <n>] [--minTermDays <n>] [--maxTermDays <n>]\n [--expDate <YYYY-MM-DD|YYYY-MM-DDTHH:mm>]",
7422
+ description: "List active DCD products (baseCcy, quoteCcy, optType required). Client-side filters: minYield (e.g. 0.05=5%), strikeNear (\xB110%), term range, expDate"
7423
+ },
7424
+ quote: {
7425
+ usage: "okx earn dcd quote --productId <id> --sz <n> --notionalCcy <ccy>",
7426
+ description: "Request a real-time DCD quote (TTL: 30 seconds)"
7427
+ },
7428
+ buy: {
7429
+ usage: "okx earn dcd buy --quoteId <id> [--clOrdId <id>]",
7430
+ description: "[CAUTION] Execute a DCD quote to place a trade. Auto-queries order state after placement"
7431
+ },
7432
+ "quote-and-buy": {
7433
+ usage: "okx earn dcd quote-and-buy --productId <id> --sz <n> --notionalCcy <ccy> [--clOrdId <id>]",
7434
+ description: "[CAUTION] Request quote and execute immediately in one step (no confirmation \u2014 for AI agent use)"
7435
+ },
7436
+ "redeem-quote": {
7437
+ usage: "okx earn dcd redeem-quote --ordId <id>",
7438
+ description: "Request an early redemption quote for a live DCD order (TTL: 15 seconds)"
7439
+ },
7440
+ redeem: {
7441
+ usage: "okx earn dcd redeem --ordId <id> --quoteId <id>",
7442
+ description: "[CAUTION] Execute early redemption of a DCD position"
7443
+ },
7444
+ "redeem-execute": {
7445
+ usage: "okx earn dcd redeem-execute --ordId <id>",
7446
+ description: "[CAUTION] Re-quote and execute early redemption in one step (recommended for AI agent use)"
7447
+ },
7448
+ order: {
7449
+ usage: "okx earn dcd order --ordId <id>",
7450
+ description: "Query current state of a DCD order"
7451
+ },
7452
+ orders: {
7453
+ usage: "okx earn dcd orders [--ordId <id>] [--productId <id>] [--uly <uly>] [--state <state>] [--limit <n>]",
7454
+ description: "Get DCD order history. State: initial|live|pending_settle|settled|pending_redeem|redeemed|rejected"
7455
+ }
7456
+ }
7071
7457
  }
7072
7458
  }
7073
7459
  },
@@ -7103,7 +7489,7 @@ var HELP_TREE = {
7103
7489
  description: "Contract DCA (Martingale) bot \u2014 leveraged recurring buys on futures/swaps",
7104
7490
  commands: {
7105
7491
  orders: {
7106
- usage: "okx bot dca orders [--history]",
7492
+ usage: "okx bot dca orders [--algoId <id>] [--instId <id>] [--history]",
7107
7493
  description: "List active or historical Contract DCA bot orders"
7108
7494
  },
7109
7495
  details: {
@@ -7390,6 +7776,21 @@ var CLI_OPTIONS = {
7390
7776
  tag: { type: "string" },
7391
7777
  allowEarlyRedeem: { type: "boolean", default: false },
7392
7778
  state: { type: "string" },
7779
+ // dcd
7780
+ quoteId: { type: "string" },
7781
+ notionalCcy: { type: "string" },
7782
+ optType: { type: "string" },
7783
+ baseCcy: { type: "string" },
7784
+ beginId: { type: "string" },
7785
+ endId: { type: "string" },
7786
+ begin: { type: "string" },
7787
+ end: { type: "string" },
7788
+ minYield: { type: "string" },
7789
+ strikeNear: { type: "string" },
7790
+ termDays: { type: "string" },
7791
+ minTermDays: { type: "string" },
7792
+ maxTermDays: { type: "string" },
7793
+ expDate: { type: "string" },
7393
7794
  // diagnostics
7394
7795
  verbose: { type: "boolean", default: false }
7395
7796
  };
@@ -7649,6 +8050,22 @@ async function cmdMarketCandles(run, instId, opts) {
7649
8050
  }))
7650
8051
  );
7651
8052
  }
8053
+ async function cmdMarketStockTokens(run, opts) {
8054
+ const result = await run("market_get_stock_tokens", { instType: opts.instType, instId: opts.instId });
8055
+ const items = getData(result);
8056
+ if (opts.json) return printJson(items);
8057
+ printTable(
8058
+ (items ?? []).slice(0, 50).map((t) => ({
8059
+ instId: t["instId"],
8060
+ instCategory: t["instCategory"],
8061
+ ctVal: t["ctVal"],
8062
+ lotSz: t["lotSz"],
8063
+ minSz: t["minSz"],
8064
+ tickSz: t["tickSz"],
8065
+ state: t["state"]
8066
+ }))
8067
+ );
8068
+ }
7652
8069
 
7653
8070
  // src/commands/account.ts
7654
8071
  import * as fs4 from "fs";
@@ -9278,7 +9695,9 @@ async function cmdDcaStop(run, opts) {
9278
9695
  }
9279
9696
  async function cmdDcaOrders(run, opts) {
9280
9697
  const result = await run("dca_get_orders", {
9281
- status: opts.history ? "history" : "active"
9698
+ status: opts.history ? "history" : "active",
9699
+ algoId: opts.algoId,
9700
+ instId: opts.instId
9282
9701
  });
9283
9702
  const orders = getData7(result) ?? [];
9284
9703
  if (opts.json) return printJson(orders);
@@ -9394,10 +9813,362 @@ function cmdOnchainEarnOrderHistory(run, v) {
9394
9813
  });
9395
9814
  }
9396
9815
 
9816
+ // src/commands/dcd.ts
9817
+ function extractArray(result) {
9818
+ if (result && typeof result === "object") {
9819
+ const data = result["data"];
9820
+ if (Array.isArray(data)) return data;
9821
+ }
9822
+ return [];
9823
+ }
9824
+ function extractProducts(result) {
9825
+ if (result && typeof result === "object") {
9826
+ const data = result["data"];
9827
+ if (data && typeof data === "object" && !Array.isArray(data)) {
9828
+ const products = data["products"];
9829
+ if (Array.isArray(products)) return products;
9830
+ }
9831
+ }
9832
+ return [];
9833
+ }
9834
+ async function cmdDcdPairs(run, json) {
9835
+ const result = await run("dcd_get_currency_pairs", {});
9836
+ const data = extractArray(result);
9837
+ if (json) {
9838
+ printJson(data);
9839
+ return;
9840
+ }
9841
+ if (!data.length) {
9842
+ process.stdout.write("No currency pairs available\n");
9843
+ return;
9844
+ }
9845
+ printTable(data.map((r) => ({
9846
+ baseCcy: r["baseCcy"],
9847
+ quoteCcy: r["quoteCcy"],
9848
+ optType: r["optType"]
9849
+ })));
9850
+ }
9851
+ function filterByYield(data, minYield) {
9852
+ return data.filter((r) => {
9853
+ const y = parseFloat(r["annualizedYield"]);
9854
+ return !isNaN(y) && y >= minYield;
9855
+ });
9856
+ }
9857
+ function filterByStrike(data, ref) {
9858
+ return data.filter((r) => {
9859
+ const strike = parseFloat(r["strike"]);
9860
+ return !isNaN(strike) && Math.abs(strike - ref) / ref <= 0.1;
9861
+ });
9862
+ }
9863
+ function filterByTerm(data, termDays, minTermDays, maxTermDays) {
9864
+ const MS_PER_DAY = 864e5;
9865
+ return data.filter((r) => {
9866
+ const exp = Number(r["expTime"]);
9867
+ const start = Number(r["interestAccrualTime"]);
9868
+ if (!exp || !start) return false;
9869
+ const days = Math.round((exp - start) / MS_PER_DAY);
9870
+ if (termDays !== void 0 && days !== termDays) return false;
9871
+ if (minTermDays !== void 0 && days < minTermDays) return false;
9872
+ if (maxTermDays !== void 0 && days > maxTermDays) return false;
9873
+ return true;
9874
+ });
9875
+ }
9876
+ function filterByExpDate(data, expDate) {
9877
+ const hasTime = expDate.includes("T") || expDate.includes(" ");
9878
+ const precision = hasTime ? 13 : 10;
9879
+ const target = new Date(expDate).toISOString().slice(0, precision);
9880
+ return data.filter((r) => {
9881
+ const exp = Number(r["expTime"]);
9882
+ if (!exp) return false;
9883
+ return new Date(exp).toISOString().slice(0, precision) === target;
9884
+ });
9885
+ }
9886
+ function applyProductFilters(data, opts) {
9887
+ if (opts.minYield !== void 0) data = filterByYield(data, opts.minYield);
9888
+ if (opts.strikeNear !== void 0) data = filterByStrike(data, opts.strikeNear);
9889
+ if (opts.termDays !== void 0 || opts.minTermDays !== void 0 || opts.maxTermDays !== void 0) {
9890
+ data = filterByTerm(data, opts.termDays, opts.minTermDays, opts.maxTermDays);
9891
+ }
9892
+ if (opts.expDate !== void 0) data = filterByExpDate(data, opts.expDate);
9893
+ return data;
9894
+ }
9895
+ async function cmdDcdProducts(run, opts) {
9896
+ const result = await run("dcd_get_products", {
9897
+ baseCcy: opts.baseCcy,
9898
+ quoteCcy: opts.quoteCcy,
9899
+ optType: opts.optType
9900
+ });
9901
+ const data = applyProductFilters(extractProducts(result), opts);
9902
+ if (opts.json) {
9903
+ printJson(data);
9904
+ return;
9905
+ }
9906
+ if (!data.length) {
9907
+ process.stdout.write("No products matched\n");
9908
+ return;
9909
+ }
9910
+ printTable(data.map((r) => ({
9911
+ productId: r["productId"],
9912
+ baseCcy: r["baseCcy"],
9913
+ quoteCcy: r["quoteCcy"],
9914
+ optType: r["optType"],
9915
+ strike: r["strike"],
9916
+ // products endpoint returns decimal (e.g. 0.3423 = 34.23%) — multiply by 100
9917
+ annualizedYield: r["annualizedYield"] ? `${(parseFloat(r["annualizedYield"]) * 100).toFixed(2)}%` : "\u2014",
9918
+ minSize: r["minSize"],
9919
+ expTime: r["expTime"] ? new Date(Number(r["expTime"])).toLocaleDateString() : ""
9920
+ })));
9921
+ }
9922
+ async function cmdDcdQuote(run, opts) {
9923
+ const result = await run("dcd_request_quote", {
9924
+ productId: opts.productId,
9925
+ notionalSz: opts.notionalSz,
9926
+ notionalCcy: opts.notionalCcy
9927
+ });
9928
+ const data = extractArray(result);
9929
+ if (opts.json) {
9930
+ printJson(data);
9931
+ return;
9932
+ }
9933
+ const r = data[0];
9934
+ if (!r) {
9935
+ process.stdout.write("No quote returned\n");
9936
+ return;
9937
+ }
9938
+ printKv({
9939
+ quoteId: r["quoteId"],
9940
+ productId: r["productId"],
9941
+ notionalSz: r["notionalSz"],
9942
+ notionalCcy: r["notionalCcy"],
9943
+ // quote endpoint returns percentage directly (e.g. 18.34 = 18.34%) — no ×100 needed
9944
+ annualizedYield: r["annualizedYield"] ? `${r["annualizedYield"]}%` : "\u2014",
9945
+ absYield: r["absYield"],
9946
+ idxPx: r["idxPx"],
9947
+ validUntil: r["validUntil"] ? new Date(Number(r["validUntil"])).toLocaleString() : "\u2014"
9948
+ });
9949
+ process.stdout.write("\nQuote expires soon. Use 'earn dcd buy --quoteId <id>' to execute.\n");
9950
+ }
9951
+ async function cmdDcdBuy(run, opts) {
9952
+ const result = await run("dcd_execute_quote", {
9953
+ quoteId: opts.quoteId,
9954
+ clOrdId: opts.clOrdId
9955
+ });
9956
+ const data = extractArray(result);
9957
+ const r = data[0];
9958
+ if (!r) {
9959
+ process.stdout.write("No response data\n");
9960
+ return;
9961
+ }
9962
+ const ordId = r["ordId"];
9963
+ let stateRow;
9964
+ if (ordId) {
9965
+ try {
9966
+ const stateResult = await run("dcd_get_order_state", { ordId });
9967
+ stateRow = extractArray(stateResult)[0];
9968
+ } catch {
9969
+ }
9970
+ }
9971
+ if (opts.json) {
9972
+ printJson({ order: r, state: stateRow ?? null });
9973
+ return;
9974
+ }
9975
+ process.stdout.write("Order placed:\n");
9976
+ printKv({ ordId: r["ordId"], quoteId: r["quoteId"], state: r["state"] });
9977
+ if (stateRow) {
9978
+ process.stdout.write("\nOrder state:\n");
9979
+ printKv({
9980
+ ordId: stateRow["ordId"],
9981
+ state: stateRow["state"]
9982
+ });
9983
+ }
9984
+ }
9985
+ async function cmdDcdRedeemQuote(run, opts) {
9986
+ const result = await run("dcd_request_redeem_quote", { ordId: opts.ordId });
9987
+ const data = extractArray(result);
9988
+ if (opts.json) {
9989
+ printJson(data);
9990
+ return;
9991
+ }
9992
+ const r = data[0];
9993
+ if (!r) {
9994
+ process.stdout.write("No redeem quote returned\n");
9995
+ return;
9996
+ }
9997
+ const redeemSzRaw = r["redeemSz"];
9998
+ const redeemSzDisplay = redeemSzRaw ? `${parseFloat(redeemSzRaw).toFixed(8)} ${r["redeemCcy"]}` : "\u2014";
9999
+ const termRateRaw = r["termRate"];
10000
+ const termRateDisplay = termRateRaw ? `${termRateRaw}%` : "\u2014";
10001
+ const validUntil = r["validUntil"] ? new Date(Number(r["validUntil"])).toLocaleString() : "\u2014";
10002
+ printKv({
10003
+ ordId: r["ordId"],
10004
+ quoteId: r["quoteId"],
10005
+ redeemSz: redeemSzDisplay,
10006
+ termRate: termRateDisplay,
10007
+ validUntil
10008
+ });
10009
+ process.stdout.write("\nQuote expires soon. Use 'earn dcd redeem-execute --ordId <id>' to execute.\n");
10010
+ }
10011
+ async function cmdDcdRedeem(run, opts) {
10012
+ const result = await run("dcd_execute_redeem", { ordId: opts.ordId, quoteId: opts.quoteId });
10013
+ const data = extractArray(result);
10014
+ if (opts.json) {
10015
+ printJson(data);
10016
+ return;
10017
+ }
10018
+ const r = data[0];
10019
+ if (!r) {
10020
+ process.stdout.write("No response data\n");
10021
+ return;
10022
+ }
10023
+ printKv({ ordId: r["ordId"], state: r["state"] });
10024
+ }
10025
+ async function cmdDcdRedeemExecute(run, opts) {
10026
+ const quoteResult = await run("dcd_request_redeem_quote", { ordId: opts.ordId });
10027
+ const quoteData = extractArray(quoteResult);
10028
+ const q = quoteData[0];
10029
+ if (!q) {
10030
+ process.stdout.write("Failed to get redeem quote\n");
10031
+ return;
10032
+ }
10033
+ const redeemResult = await run("dcd_execute_redeem", {
10034
+ ordId: opts.ordId,
10035
+ quoteId: q["quoteId"]
10036
+ });
10037
+ const redeemData = extractArray(redeemResult);
10038
+ const r = redeemData[0];
10039
+ if (!r) {
10040
+ process.stdout.write("No response data\n");
10041
+ return;
10042
+ }
10043
+ if (opts.json) {
10044
+ printJson({ quote: q, redeem: r });
10045
+ return;
10046
+ }
10047
+ printKv({
10048
+ ordId: r["ordId"],
10049
+ state: r["state"],
10050
+ redeemSz: q["redeemSz"] ? `${parseFloat(q["redeemSz"]).toFixed(8)} ${q["redeemCcy"]}` : "\u2014",
10051
+ termRate: q["termRate"] ? `${q["termRate"]}%` : "\u2014",
10052
+ validUntil: q["validUntil"] ? new Date(Number(q["validUntil"])).toLocaleString() : "\u2014"
10053
+ });
10054
+ }
10055
+ async function cmdDcdOrderState(run, opts) {
10056
+ const result = await run("dcd_get_order_state", { ordId: opts.ordId });
10057
+ const data = extractArray(result);
10058
+ if (opts.json) {
10059
+ printJson(data);
10060
+ return;
10061
+ }
10062
+ const r = data[0];
10063
+ if (!r) {
10064
+ process.stdout.write("Order not found\n");
10065
+ return;
10066
+ }
10067
+ printKv({
10068
+ ordId: r["ordId"],
10069
+ state: r["state"],
10070
+ productId: r["productId"],
10071
+ strike: r["strike"],
10072
+ notionalSz: r["notionalSz"],
10073
+ settleTime: r["settleTime"] ? new Date(Number(r["settleTime"])).toLocaleDateString() : ""
10074
+ });
10075
+ }
10076
+ async function cmdDcdOrders(run, opts) {
10077
+ const result = await run("dcd_get_orders", {
10078
+ ordId: opts.ordId,
10079
+ productId: opts.productId,
10080
+ uly: opts.uly,
10081
+ state: opts.state,
10082
+ beginId: opts.beginId,
10083
+ endId: opts.endId,
10084
+ begin: opts.begin,
10085
+ end: opts.end,
10086
+ limit: opts.limit
10087
+ });
10088
+ const data = extractArray(result);
10089
+ if (opts.json) {
10090
+ printJson(data);
10091
+ return;
10092
+ }
10093
+ if (!data.length) {
10094
+ process.stdout.write("No orders found\n");
10095
+ return;
10096
+ }
10097
+ printTable(data.map((r) => ({
10098
+ ordId: r["ordId"],
10099
+ productId: r["productId"],
10100
+ state: r["state"],
10101
+ baseCcy: r["baseCcy"],
10102
+ quoteCcy: r["quoteCcy"],
10103
+ strike: r["strike"],
10104
+ notionalSz: r["notionalSz"],
10105
+ annualizedYield: r["annualizedYield"],
10106
+ yieldSz: r["yieldSz"],
10107
+ settleTime: r["settleTime"] ? new Date(Number(r["settleTime"])).toLocaleDateString() : "",
10108
+ // scheduled settlement time
10109
+ settledTime: r["settledTime"] ? new Date(Number(r["settledTime"])).toLocaleDateString() : ""
10110
+ // actual settled time (non-empty only after settlement)
10111
+ })));
10112
+ }
10113
+ async function cmdDcdQuoteAndBuy(run, opts) {
10114
+ const quoteResult = await run("dcd_request_quote", {
10115
+ productId: opts.productId,
10116
+ notionalSz: opts.notionalSz,
10117
+ notionalCcy: opts.notionalCcy
10118
+ });
10119
+ const quoteData = extractArray(quoteResult);
10120
+ const q = quoteData[0];
10121
+ if (!q) {
10122
+ process.stdout.write("No quote returned\n");
10123
+ return;
10124
+ }
10125
+ const buyResult = await run("dcd_execute_quote", {
10126
+ quoteId: q["quoteId"],
10127
+ clOrdId: opts.clOrdId
10128
+ });
10129
+ const buyData = extractArray(buyResult);
10130
+ const r = buyData[0];
10131
+ if (!r) {
10132
+ process.stdout.write("No order response\n");
10133
+ return;
10134
+ }
10135
+ const ordId = r["ordId"];
10136
+ let stateRow;
10137
+ if (ordId) {
10138
+ try {
10139
+ const stateResult = await run("dcd_get_order_state", { ordId });
10140
+ stateRow = extractArray(stateResult)[0];
10141
+ } catch {
10142
+ }
10143
+ }
10144
+ if (opts.json) {
10145
+ printJson({ quote: q, order: r, state: stateRow ?? null });
10146
+ return;
10147
+ }
10148
+ process.stdout.write("Quote:\n");
10149
+ printKv({
10150
+ quoteId: q["quoteId"],
10151
+ // quote endpoint returns percentage directly (e.g. 18.34 = 18.34%) — no ×100 needed
10152
+ annualizedYield: q["annualizedYield"] ? `${q["annualizedYield"]}%` : "\u2014",
10153
+ absYield: q["absYield"],
10154
+ notionalSz: q["notionalSz"],
10155
+ notionalCcy: q["notionalCcy"]
10156
+ });
10157
+ process.stdout.write("\nOrder placed:\n");
10158
+ printKv({ ordId: r["ordId"], quoteId: r["quoteId"], state: r["state"] ?? r["status"] });
10159
+ if (stateRow) {
10160
+ process.stdout.write("\nOrder state:\n");
10161
+ printKv({
10162
+ ordId: stateRow["ordId"],
10163
+ state: stateRow["state"]
10164
+ });
10165
+ }
10166
+ }
10167
+
9397
10168
  // src/index.ts
9398
10169
  var _require2 = createRequire2(import.meta.url);
9399
10170
  var CLI_VERSION2 = _require2("../package.json").version;
9400
- var GIT_HASH2 = true ? "4427916" : "dev";
10171
+ var GIT_HASH2 = true ? "1df90cc" : "dev";
9401
10172
  function handleConfigCommand(action, rest, json, lang, force) {
9402
10173
  if (action === "init") return cmdConfigInit(lang === "zh" ? "zh" : "en");
9403
10174
  if (action === "show") return cmdConfigShow(json);
@@ -9442,6 +10213,8 @@ function handleMarketPublicCommand(run, action, rest, v, json) {
9442
10213
  if (action === "price-limit") return cmdMarketPriceLimit(run, rest[0], json);
9443
10214
  if (action === "open-interest")
9444
10215
  return cmdMarketOpenInterest(run, { instType: v.instType, instId: v.instId, json });
10216
+ if (action === "stock-tokens")
10217
+ return cmdMarketStockTokens(run, { instType: v.instType, instId: v.instId, json });
9445
10218
  }
9446
10219
  function handleMarketDataCommand(run, action, rest, v, json) {
9447
10220
  const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
@@ -9828,7 +10601,7 @@ function handleBotGridCommand(run, v, rest, json) {
9828
10601
  }
9829
10602
  function handleBotDcaCommand(run, subAction, v, json) {
9830
10603
  if (subAction === "orders")
9831
- return cmdDcaOrders(run, { history: v.history ?? false, json });
10604
+ return cmdDcaOrders(run, { algoId: v.algoId, instId: v.instId, history: v.history ?? false, json });
9832
10605
  if (subAction === "details")
9833
10606
  return cmdDcaDetails(run, { algoId: v.algoId, json });
9834
10607
  if (subAction === "sub-orders")
@@ -9864,8 +10637,9 @@ function handleEarnCommand(run, submodule, rest, v, json) {
9864
10637
  const innerRest = rest.slice(1);
9865
10638
  if (submodule === "savings") return handleEarnSavingsCommand(run, action, innerRest, v, json);
9866
10639
  if (submodule === "onchain") return handleEarnOnchainCommand(run, action, v, json);
10640
+ if (submodule === "dcd") return handleEarnDcdCommand(run, action, v, json);
9867
10641
  process.stderr.write(`Unknown earn sub-module: ${submodule}
9868
- Valid: savings, onchain
10642
+ Valid: savings, onchain, dcd
9869
10643
  `);
9870
10644
  process.exitCode = 1;
9871
10645
  }
@@ -9893,6 +10667,70 @@ function handleEarnOnchainCommand(run, action, v, json) {
9893
10667
  `);
9894
10668
  process.exitCode = 1;
9895
10669
  }
10670
+ function parseDcdOpts(v) {
10671
+ return {
10672
+ limit: v.limit !== void 0 ? Number(v.limit) : void 0,
10673
+ minYield: v.minYield !== void 0 ? parseFloat(v.minYield) : void 0,
10674
+ strikeNear: v.strikeNear !== void 0 ? parseFloat(v.strikeNear) : void 0,
10675
+ termDays: v.termDays !== void 0 ? parseInt(v.termDays, 10) : void 0,
10676
+ minTermDays: v.minTermDays !== void 0 ? parseInt(v.minTermDays, 10) : void 0,
10677
+ maxTermDays: v.maxTermDays !== void 0 ? parseInt(v.maxTermDays, 10) : void 0
10678
+ };
10679
+ }
10680
+ function handleEarnDcdCommand(run, action, v, json) {
10681
+ const { limit, minYield, strikeNear, termDays, minTermDays, maxTermDays } = parseDcdOpts(v);
10682
+ if (action === "pairs") return cmdDcdPairs(run, json);
10683
+ if (action === "products")
10684
+ return cmdDcdProducts(run, {
10685
+ baseCcy: v.baseCcy,
10686
+ quoteCcy: v.quoteCcy,
10687
+ optType: v.optType,
10688
+ minYield,
10689
+ strikeNear,
10690
+ termDays,
10691
+ minTermDays,
10692
+ maxTermDays,
10693
+ expDate: v.expDate,
10694
+ json
10695
+ });
10696
+ if (action === "quote")
10697
+ return cmdDcdQuote(run, { productId: v.productId, notionalSz: v.sz, notionalCcy: v.notionalCcy, json });
10698
+ if (action === "buy")
10699
+ return cmdDcdBuy(run, { quoteId: v.quoteId, clOrdId: v.clOrdId, json });
10700
+ if (action === "quote-and-buy")
10701
+ return cmdDcdQuoteAndBuy(run, {
10702
+ productId: v.productId,
10703
+ notionalSz: v.sz,
10704
+ notionalCcy: v.notionalCcy,
10705
+ clOrdId: v.clOrdId,
10706
+ json
10707
+ });
10708
+ if (action === "redeem-quote")
10709
+ return cmdDcdRedeemQuote(run, { ordId: v.ordId, json });
10710
+ if (action === "redeem")
10711
+ return cmdDcdRedeem(run, { ordId: v.ordId, quoteId: v.quoteId, json });
10712
+ if (action === "redeem-execute")
10713
+ return cmdDcdRedeemExecute(run, { ordId: v.ordId, json });
10714
+ if (action === "order")
10715
+ return cmdDcdOrderState(run, { ordId: v.ordId, json });
10716
+ if (action === "orders")
10717
+ return cmdDcdOrders(run, {
10718
+ ordId: v.ordId,
10719
+ productId: v.productId,
10720
+ uly: v.uly,
10721
+ state: v.state,
10722
+ beginId: v.beginId,
10723
+ endId: v.endId,
10724
+ begin: v.begin,
10725
+ end: v.end,
10726
+ limit,
10727
+ json
10728
+ });
10729
+ process.stderr.write(`Unknown earn dcd command: ${action}
10730
+ Valid: pairs, products, quote, buy, quote-and-buy, redeem-quote, redeem, redeem-execute, order, orders
10731
+ `);
10732
+ process.exitCode = 1;
10733
+ }
9896
10734
  function outputResult(result, json) {
9897
10735
  if (json) {
9898
10736
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");