@okx_ai/okx-trade-cli 1.3.1 → 1.3.2-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
@@ -1453,13 +1453,14 @@ var OkxRestClient = class _OkxRestClient {
1453
1453
  rateLimit
1454
1454
  });
1455
1455
  }
1456
- async privatePost(path42, body, rateLimit) {
1456
+ async privatePost(path42, body, rateLimit, retryOnNetworkError) {
1457
1457
  return this.request({
1458
1458
  method: "POST",
1459
1459
  path: path42,
1460
1460
  auth: "private",
1461
1461
  body,
1462
- rateLimit
1462
+ rateLimit,
1463
+ retryOnNetworkError
1463
1464
  });
1464
1465
  }
1465
1466
  setAuthHeaders(headers, method, requestPath, bodyJson, timestamp) {
@@ -1742,7 +1743,7 @@ var OkxRestClient = class _OkxRestClient {
1742
1743
  vlog2(`Network failure, refreshing DoH: ${cause}`);
1743
1744
  }
1744
1745
  const shouldRetry = await this.doh.handleNetworkFailure();
1745
- if (shouldRetry && reqConfig.method === "GET") {
1746
+ if (shouldRetry && (reqConfig.method === "GET" || reqConfig.retryOnNetworkError)) {
1746
1747
  return this.request(reqConfig);
1747
1748
  }
1748
1749
  }
@@ -2218,6 +2219,7 @@ var MODULES = [
2218
2219
  "account",
2219
2220
  "event",
2220
2221
  "news",
2222
+ "smartmoney",
2221
2223
  ...EARN_SUB_MODULE_IDS,
2222
2224
  ...BOT_SUB_MODULE_IDS,
2223
2225
  "skills"
@@ -2240,6 +2242,7 @@ var MODULE_DESCRIPTIONS = {
2240
2242
  "bot.grid": "Grid trading bot \u2014 create, monitor, and stop grid orders",
2241
2243
  "bot.dca": "DCA (Martingale) bot \u2014 spot or contract recurring buys",
2242
2244
  news: "Crypto news, sentiment analysis, and coin trend tracking",
2245
+ smartmoney: "Smart money signals \u2014 trader leaderboard, consensus signals, and position analysis",
2243
2246
  skills: SKILLS_MARKETPLACE_DESC,
2244
2247
  earn: "Earn products \u2014 Simple Earn, On-chain Earn, DCD, Flash Earn, and Auto-Earn",
2245
2248
  bot: "Trading bot strategies (grid, dca)",
@@ -4246,10 +4249,133 @@ function registerGridTools() {
4246
4249
  return normalizeWrite(response);
4247
4250
  }
4248
4251
  },
4252
+ {
4253
+ name: "grid_amend_order",
4254
+ module: "bot.grid",
4255
+ description: "Amend a running grid bot. [CAUTION] Modifies a running bot. Use grid_list_orders to confirm the bot is running and obtain the algoId before calling.\nSupports two modes, which can be combined in a single call:\n\u2022 Price-range mode (maxPx+minPx+gridNum): change upper/lower price boundary and grid count. Contract grid: if new range requires more margin, pass topUpAmt; omit to auto-use the minimum required. Spot grid: topUpAmt is not supported.\n\u2022 TP/SL mode (instId + any of tpTriggerPx/slTriggerPx/tpRatio/slRatio): update take-profit and/or stop-loss. Pass '-1' to explicitly clear an existing TP or SL. tpTriggerPx/slTriggerPx are absolute prices; tpRatio/slRatio are profit ratios (e.g. '0.1' = 10%).\nWhen both sets of params are provided, both APIs are called sequentially.\nDo NOT use to create a new grid bot \u2014 use grid_create_order instead. Do NOT use to stop a grid bot \u2014 use grid_stop_order instead.",
4256
+ isWrite: true,
4257
+ inputSchema: {
4258
+ type: "object",
4259
+ properties: {
4260
+ algoId: {
4261
+ type: "string",
4262
+ description: "Grid bot algo order ID (required)"
4263
+ },
4264
+ // ── Price-range mode ──────────────────────────────────────────────
4265
+ maxPx: {
4266
+ type: "string",
4267
+ description: "[Price-range mode] New upper price boundary. Triggers amend-algo-basic-param when provided."
4268
+ },
4269
+ minPx: {
4270
+ type: "string",
4271
+ description: "[Price-range mode] New lower price boundary. Required when maxPx is set."
4272
+ },
4273
+ gridNum: {
4274
+ type: "string",
4275
+ description: "[Price-range mode] New number of grid intervals (integer). Required when maxPx is set."
4276
+ },
4277
+ // ── TP/SL mode ────────────────────────────────────────────────────
4278
+ instId: {
4279
+ type: "string",
4280
+ description: "[TP/SL mode] Instrument ID, e.g. BTC-USDT. Required when setting TP/SL."
4281
+ },
4282
+ tpTriggerPx: {
4283
+ type: "string",
4284
+ description: "[TP/SL mode] Take-profit trigger price (absolute). Pass '-1' to clear."
4285
+ },
4286
+ slTriggerPx: {
4287
+ type: "string",
4288
+ description: "[TP/SL mode] Stop-loss trigger price (absolute). Pass '-1' to clear."
4289
+ },
4290
+ tpRatio: {
4291
+ type: "string",
4292
+ description: "[TP/SL mode] Take-profit ratio, e.g. '0.1' = 10% profit. Pass '-1' to clear."
4293
+ },
4294
+ slRatio: {
4295
+ type: "string",
4296
+ description: "[TP/SL mode] Stop-loss ratio, e.g. '0.1' = 10% drawdown. Pass '-1' to clear."
4297
+ },
4298
+ // ── Shared optional ───────────────────────────────────────────────
4299
+ topUpAmt: {
4300
+ type: "string",
4301
+ description: "Top-up amount. In price-range mode maps to topupAmount (contract grid only; omit to use minimum required). In TP/SL mode maps to topUpAmt."
4302
+ }
4303
+ },
4304
+ required: ["algoId"]
4305
+ },
4306
+ handler: async (rawArgs, context) => {
4307
+ const args = asRecord(rawArgs);
4308
+ const algoId = requireString(args, "algoId");
4309
+ const maxPx = readString(args, "maxPx");
4310
+ const instId = readString(args, "instId");
4311
+ const hasTpsl = readString(args, "tpTriggerPx") || readString(args, "slTriggerPx") || readString(args, "tpRatio") || readString(args, "slRatio");
4312
+ if (!maxPx && !hasTpsl) {
4313
+ throw new OkxApiError(
4314
+ "Nothing to amend. Provide maxPx+minPx+gridNum for price-range mode, or any of tpTriggerPx/slTriggerPx/tpRatio/slRatio (instId also required) for TP/SL mode (both can be combined).",
4315
+ { code: "", endpoint: "grid_amend_order" }
4316
+ );
4317
+ }
4318
+ if (hasTpsl && !instId) {
4319
+ throw new OkxApiError(
4320
+ "TP/SL mode requires instId. Provide instId alongside the TP/SL parameters.",
4321
+ { code: "", endpoint: "grid_amend_order" }
4322
+ );
4323
+ }
4324
+ const results = [];
4325
+ if (maxPx) {
4326
+ results.push(normalizeWrite(await context.client.privatePost(
4327
+ "/api/v5/tradingBot/grid/amend-algo-basic-param",
4328
+ compactObject({
4329
+ algoId,
4330
+ maxPx,
4331
+ minPx: requireString(args, "minPx"),
4332
+ gridNum: requireString(args, "gridNum"),
4333
+ // API field is "topupAmount" (lowercase u) — different from TP/SL mode's "topUpAmt"
4334
+ // Contract grid only; omitting lets the API use the minimum required
4335
+ topupAmount: readString(args, "topUpAmt")
4336
+ }),
4337
+ privateRateLimit("grid_amend_order", 20),
4338
+ true
4339
+ // retryOnNetworkError: amend sets fixed values, safe to retry
4340
+ )));
4341
+ }
4342
+ if (hasTpsl) {
4343
+ try {
4344
+ results.push(normalizeWrite(await context.client.privatePost(
4345
+ "/api/v5/tradingBot/grid/amend-order-algo",
4346
+ compactObject({
4347
+ algoId,
4348
+ instId,
4349
+ tpTriggerPx: readString(args, "tpTriggerPx"),
4350
+ slTriggerPx: readString(args, "slTriggerPx"),
4351
+ tpRatio: readString(args, "tpRatio"),
4352
+ slRatio: readString(args, "slRatio"),
4353
+ topUpAmt: readString(args, "topUpAmt")
4354
+ // API field is "topUpAmt" (uppercase U) — different from price-range mode's "topupAmount"
4355
+ }),
4356
+ privateRateLimit("grid_amend_order", 20),
4357
+ true
4358
+ // retryOnNetworkError: amend sets fixed values, safe to retry
4359
+ )));
4360
+ } catch (err) {
4361
+ if (results.length > 0) {
4362
+ const msg = err instanceof Error ? err.message : String(err);
4363
+ throw new OkxApiError(
4364
+ `TP/SL amend failed (price-range amend already succeeded): ${msg}`,
4365
+ { code: "", endpoint: "grid_amend_order" }
4366
+ );
4367
+ }
4368
+ throw err;
4369
+ }
4370
+ }
4371
+ const merged = results.flatMap((r) => Array.isArray(r.data) ? r.data : [r.data]);
4372
+ return { endpoint: results[0].endpoint, requestTime: results[0].requestTime, data: merged };
4373
+ }
4374
+ },
4249
4375
  {
4250
4376
  name: "grid_stop_order",
4251
4377
  module: "bot.grid",
4252
- description: "Stop a grid bot. [CAUTION] Closes or cancels orders. For contract: stopType controls close ('1') vs cancel-only ('2').",
4378
+ description: "Stop a running grid bot. [CAUTION] This stops the strategy and handles open orders/positions according to stopType. Default (stopType='1') closes all positions immediately \u2014 use this for a clean exit. stopType='2' stops the strategy without selling: spot grid keeps all base assets as-is (no sell-back to quote); contract grid cancels all grid orders but leaves the position open for manual close later.",
4253
4379
  isWrite: true,
4254
4380
  inputSchema: {
4255
4381
  type: "object",
@@ -4258,13 +4384,13 @@ function registerGridTools() {
4258
4384
  algoOrdType: {
4259
4385
  type: "string",
4260
4386
  enum: ["grid", "contract_grid"],
4261
- description: "grid=Spot, contract_grid=Contract"
4387
+ description: "grid=Spot grid, contract_grid=Contract grid"
4262
4388
  },
4263
- instId: { type: "string", description: "e.g. BTC-USDT, BTC-USD-SWAP" },
4389
+ instId: { type: "string", description: "Instrument ID, e.g. BTC-USDT, BTC-USDT-SWAP" },
4264
4390
  stopType: {
4265
4391
  type: "string",
4266
- enum: ["1", "2", "3", "5", "6"],
4267
- description: "1=close all (default); 2=keep assets; 3=limit close; 5=partial; 6=no sell"
4392
+ enum: ["1", "2"],
4393
+ description: "'1' (default): stop strategy and sell \u2014 spot grid sells all base assets back to quote; contract grid market-closes all positions. '2': stop strategy without selling \u2014 spot grid keeps base assets as-is; contract grid cancels all grid orders but leaves the position open. After stopType='2', the remaining position can be closed manually from the Positions page."
4268
4394
  }
4269
4395
  },
4270
4396
  required: ["algoId", "algoOrdType", "instId"]
@@ -4279,7 +4405,9 @@ function registerGridTools() {
4279
4405
  instId: requireString(args, "instId"),
4280
4406
  stopType: readString(args, "stopType") ?? "1"
4281
4407
  })],
4282
- privateRateLimit("grid_stop_order", 20)
4408
+ privateRateLimit("grid_stop_order", 20),
4409
+ true
4410
+ // retryOnNetworkError: safe to retry — already-stopped returns an error but does not harm state
4283
4411
  );
4284
4412
  return normalizeWrite(response);
4285
4413
  }
@@ -6426,6 +6554,401 @@ function registerEventContractTools() {
6426
6554
  }
6427
6555
  ];
6428
6556
  }
6557
+ var PATH_LEADERBOARD = "/api/v5/orbit/public/leaderboard";
6558
+ var PATH_POSITION_CURRENT = "/api/v5/orbit/public/position-current";
6559
+ var PATH_TRADE_RECORDS = "/api/v5/orbit/public/trade-records";
6560
+ var PATH_OVERVIEW = "/api/v5/journal/public/smartmoney/overview";
6561
+ var PATH_SIGNAL = "/api/v5/journal/public/smartmoney/signal";
6562
+ var PATH_SIGNAL_HISTORY = "/api/v5/journal/public/smartmoney/signal-history";
6563
+ var SIGNAL_POOL_FILTER_PROPS = {
6564
+ sortType: {
6565
+ type: "string",
6566
+ description: "pnl or pnlRatio"
6567
+ },
6568
+ period: {
6569
+ type: "string",
6570
+ description: "3|7|30|90 days"
6571
+ },
6572
+ pnl: {
6573
+ type: "string",
6574
+ description: "PNL_ANY|PNL_TOP50|PNL_TOP20|PNL_TOP5"
6575
+ },
6576
+ winRatio: {
6577
+ type: "string",
6578
+ description: "WR_ANY|WR_GE_50|WR_GE_80"
6579
+ },
6580
+ maxRetreat: {
6581
+ type: "string",
6582
+ description: "MR_ANY|MR_LE_20|MR_LE_50"
6583
+ },
6584
+ asset: {
6585
+ type: "string",
6586
+ description: "AUM_ANY|AUM_TOP50|AUM_TOP20|AUM_TOP5"
6587
+ }
6588
+ };
6589
+ var LEADERBOARD_POOL_FILTER_PROPS = {
6590
+ sortType: {
6591
+ type: "string",
6592
+ description: "pnl or pnl_ratio"
6593
+ },
6594
+ period: {
6595
+ type: "string",
6596
+ description: "3|7|30|90 days, empty=all"
6597
+ },
6598
+ pnl: {
6599
+ type: "string",
6600
+ description: "Min PnL USD"
6601
+ },
6602
+ winRatio: {
6603
+ type: "string",
6604
+ description: "Min ratio (0.8=80%)"
6605
+ },
6606
+ maxRetreat: {
6607
+ type: "string",
6608
+ description: "Max DD (0.1=10%)"
6609
+ },
6610
+ asset: {
6611
+ type: "string",
6612
+ description: "Min AUM USD"
6613
+ }
6614
+ };
6615
+ var POOL_FILTER_KEYS = ["sortType", "period", "pnl", "winRatio", "maxRetreat", "asset"];
6616
+ function readPoolFilters(args) {
6617
+ const result = {};
6618
+ for (const key of POOL_FILTER_KEYS) {
6619
+ const val = readString(args, key);
6620
+ if (val) result[key] = val;
6621
+ }
6622
+ return result;
6623
+ }
6624
+ function extractLeaderboardData(data) {
6625
+ if (Array.isArray(data)) return data;
6626
+ if (data && typeof data === "object") {
6627
+ const inner = data.data;
6628
+ if (Array.isArray(inner)) return inner;
6629
+ }
6630
+ return [];
6631
+ }
6632
+ var SMARTMONEY_DEMO_MESSAGE = "Smart Money features are not available in demo/simulated trading mode.";
6633
+ var SMARTMONEY_DEMO_SUGGESTION = "Switch to a live profile to use Smart Money features.";
6634
+ function withSmartmoneyDemoGuard(tool) {
6635
+ const originalHandler = tool.handler;
6636
+ return {
6637
+ ...tool,
6638
+ handler: async (args, context) => {
6639
+ if (context.config.demo) {
6640
+ throw new ConfigError(
6641
+ SMARTMONEY_DEMO_MESSAGE,
6642
+ SMARTMONEY_DEMO_SUGGESTION
6643
+ );
6644
+ }
6645
+ return originalHandler(args, context);
6646
+ }
6647
+ };
6648
+ }
6649
+ function registerSmartmoneyTools() {
6650
+ const tools = [
6651
+ /* ---------- 1. Overview ---------- */
6652
+ {
6653
+ name: "smartmoney_get_overview",
6654
+ module: "smartmoney",
6655
+ description: "Multi-currency smart money overview ranked by most-watched currencies. Pass ts=Date.now() for latest data, or dataVersion (yyyyMMddHHmm) from a prior call. For single-currency signal with entry prices and trend, use smartmoney_get_signal.",
6656
+ isWrite: false,
6657
+ inputSchema: {
6658
+ type: "object",
6659
+ properties: {
6660
+ dataVersion: {
6661
+ type: "string",
6662
+ description: "yyyyMMddHHmm UTC (or use ts)"
6663
+ },
6664
+ ts: {
6665
+ type: "string",
6666
+ description: "Timestamp ms (or use dataVersion)"
6667
+ },
6668
+ instType: {
6669
+ type: "string",
6670
+ description: "SPOT|MARGIN|FUTURES|SWAP|OPTION"
6671
+ },
6672
+ ...SIGNAL_POOL_FILTER_PROPS,
6673
+ lmtNum: {
6674
+ type: "string",
6675
+ description: "Trader pool size 1-500"
6676
+ },
6677
+ instCcyList: {
6678
+ type: "string",
6679
+ description: "Comma-separated e.g. BTC,ETH,SOL"
6680
+ },
6681
+ instCcy: {
6682
+ type: "string",
6683
+ description: "Single currency e.g. BTC"
6684
+ },
6685
+ topInstruments: {
6686
+ type: "string",
6687
+ description: "Top N instruments 1-100"
6688
+ }
6689
+ }
6690
+ },
6691
+ handler: async (rawArgs, context) => {
6692
+ const args = asRecord(rawArgs);
6693
+ const dv = readString(args, "dataVersion");
6694
+ const ts = readString(args, "ts");
6695
+ if (!dv && !ts) {
6696
+ throw new ValidationError('Either "dataVersion" or "ts" is required for smartmoney_get_overview.');
6697
+ }
6698
+ const response = await context.client.privateGet(
6699
+ PATH_OVERVIEW,
6700
+ compactObject({
6701
+ dataVersion: dv,
6702
+ ts,
6703
+ instType: readString(args, "instType"),
6704
+ ...readPoolFilters(args),
6705
+ lmtNum: readString(args, "lmtNum"),
6706
+ instCcyList: readString(args, "instCcyList"),
6707
+ instCcy: readString(args, "instCcy"),
6708
+ topInstruments: readString(args, "topInstruments")
6709
+ }),
6710
+ publicRateLimit("smartmoney_get_overview", 5)
6711
+ );
6712
+ return normalizeResponse(response);
6713
+ }
6714
+ },
6715
+ /* ---------- 2. Signal ---------- */
6716
+ {
6717
+ name: "smartmoney_get_signal",
6718
+ module: "smartmoney",
6719
+ description: "Single-currency consensus signal: long/short ratio, entry prices, trend, capital flow. Requires instId or instCcy. Pass ts=Date.now() for latest data, or dataVersion from a prior call. For multi-currency overview, use smartmoney_get_overview. For timeline, use smartmoney_get_signal_history.",
6720
+ isWrite: false,
6721
+ inputSchema: {
6722
+ type: "object",
6723
+ properties: {
6724
+ instId: {
6725
+ type: "string",
6726
+ description: "e.g. BTC-USDT-SWAP (or use instCcy)"
6727
+ },
6728
+ instCcy: {
6729
+ type: "string",
6730
+ description: "e.g. BTC, SPOT/SWAP only (or use instId)"
6731
+ },
6732
+ dataVersion: {
6733
+ type: "string",
6734
+ description: "yyyyMMddHHmm UTC (or use ts)"
6735
+ },
6736
+ ts: {
6737
+ type: "string",
6738
+ description: "Timestamp ms (or use dataVersion)"
6739
+ },
6740
+ ...SIGNAL_POOL_FILTER_PROPS,
6741
+ lmtNum: {
6742
+ type: "string",
6743
+ description: "Trader pool size 1-500"
6744
+ },
6745
+ authorIds: {
6746
+ type: "string",
6747
+ description: "Comma-separated user IDs e.g. 1001,1002"
6748
+ }
6749
+ }
6750
+ },
6751
+ handler: async (rawArgs, context) => {
6752
+ const args = asRecord(rawArgs);
6753
+ const instId = readString(args, "instId");
6754
+ const instCcy = readString(args, "instCcy");
6755
+ if (!instId && !instCcy) {
6756
+ throw new ValidationError('Either "instId" or "instCcy" is required for smartmoney_get_signal.');
6757
+ }
6758
+ const dv = readString(args, "dataVersion");
6759
+ const ts = readString(args, "ts");
6760
+ if (!dv && !ts) {
6761
+ throw new ValidationError('Either "dataVersion" or "ts" is required for smartmoney_get_signal.');
6762
+ }
6763
+ const response = await context.client.privateGet(
6764
+ PATH_SIGNAL,
6765
+ compactObject({
6766
+ instId,
6767
+ instCcy,
6768
+ dataVersion: dv,
6769
+ ts,
6770
+ ...readPoolFilters(args),
6771
+ lmtNum: readString(args, "lmtNum"),
6772
+ authorIds: readString(args, "authorIds")
6773
+ }),
6774
+ publicRateLimit("smartmoney_get_signal", 5)
6775
+ );
6776
+ return normalizeResponse(response);
6777
+ }
6778
+ },
6779
+ /* ---------- 3. Signal History ---------- */
6780
+ {
6781
+ name: "smartmoney_get_signal_history",
6782
+ module: "smartmoney",
6783
+ description: "Signal history timeline sorted by ts DESC for trend analysis. Requires instId. Pass ts=Date.now() for latest data, or dataVersion from a prior call. For current snapshot, use smartmoney_get_signal.",
6784
+ isWrite: false,
6785
+ inputSchema: {
6786
+ type: "object",
6787
+ properties: {
6788
+ instId: {
6789
+ type: "string",
6790
+ description: "e.g. BTC-USDT-SWAP"
6791
+ },
6792
+ dataVersion: {
6793
+ type: "string",
6794
+ description: "yyyyMMddHHmm UTC (or use ts)"
6795
+ },
6796
+ ts: {
6797
+ type: "string",
6798
+ description: "Timestamp ms (or use dataVersion)"
6799
+ },
6800
+ granularity: {
6801
+ type: "string",
6802
+ description: "1h or 1d"
6803
+ },
6804
+ limit: {
6805
+ type: "string",
6806
+ description: "Data points 1-500"
6807
+ },
6808
+ ...SIGNAL_POOL_FILTER_PROPS
6809
+ },
6810
+ required: ["instId"]
6811
+ },
6812
+ handler: async (rawArgs, context) => {
6813
+ const args = asRecord(rawArgs);
6814
+ const dv = readString(args, "dataVersion");
6815
+ const ts = readString(args, "ts");
6816
+ if (!dv && !ts) {
6817
+ throw new ValidationError('Either "dataVersion" or "ts" is required for smartmoney_get_signal_history.');
6818
+ }
6819
+ const response = await context.client.privateGet(
6820
+ PATH_SIGNAL_HISTORY,
6821
+ compactObject({
6822
+ instId: requireString(args, "instId"),
6823
+ dataVersion: dv,
6824
+ ts,
6825
+ granularity: readString(args, "granularity"),
6826
+ limit: readString(args, "limit"),
6827
+ ...readPoolFilters(args)
6828
+ }),
6829
+ publicRateLimit("smartmoney_get_signal_history", 5)
6830
+ );
6831
+ return normalizeResponse(response);
6832
+ }
6833
+ },
6834
+ /* ---------- 4. Traders (list) ---------- */
6835
+ {
6836
+ name: "smartmoney_get_traders",
6837
+ module: "smartmoney",
6838
+ description: "List/filter leaderboard traders. For single trader detail: smartmoney_get_trader_detail.",
6839
+ isWrite: false,
6840
+ inputSchema: {
6841
+ type: "object",
6842
+ properties: {
6843
+ dataVersion: {
6844
+ type: "string",
6845
+ description: "yyyyMMddHHmm, omit=latest"
6846
+ },
6847
+ ...LEADERBOARD_POOL_FILTER_PROPS,
6848
+ authorIds: {
6849
+ type: "string",
6850
+ description: "Comma-separated author IDs"
6851
+ },
6852
+ after: {
6853
+ type: "string",
6854
+ description: "Cursor after this authorId"
6855
+ },
6856
+ before: {
6857
+ type: "string",
6858
+ description: "Cursor before this authorId"
6859
+ },
6860
+ limit: {
6861
+ type: "string",
6862
+ description: "Max results 1-100"
6863
+ }
6864
+ }
6865
+ },
6866
+ handler: async (rawArgs, context) => {
6867
+ const args = asRecord(rawArgs);
6868
+ const response = await context.client.privateGet(
6869
+ PATH_LEADERBOARD,
6870
+ compactObject({
6871
+ dataVersion: readString(args, "dataVersion"),
6872
+ ...readPoolFilters(args),
6873
+ authorIds: readString(args, "authorIds"),
6874
+ after: readString(args, "after"),
6875
+ before: readString(args, "before"),
6876
+ limit: readString(args, "limit")
6877
+ }),
6878
+ publicRateLimit("smartmoney_get_traders", 5)
6879
+ );
6880
+ const normalized = normalizeResponse(response);
6881
+ return { ...normalized, data: extractLeaderboardData(normalized.data) };
6882
+ }
6883
+ },
6884
+ /* ---------- 5. Trader Detail (composite) ---------- */
6885
+ {
6886
+ name: "smartmoney_get_trader_detail",
6887
+ module: "smartmoney",
6888
+ description: "Trader portrait: profile + positions + trades. Requires authorId from smartmoney_get_traders. Do NOT use for listing \u2014 use smartmoney_get_traders.",
6889
+ isWrite: false,
6890
+ inputSchema: {
6891
+ type: "object",
6892
+ properties: {
6893
+ authorId: {
6894
+ type: "string",
6895
+ description: "Trader author ID"
6896
+ },
6897
+ period: {
6898
+ type: "string",
6899
+ description: "3|7|30|90 days, omit=all"
6900
+ },
6901
+ instCcy: {
6902
+ type: "string",
6903
+ description: "Currency filter e.g. BTC"
6904
+ },
6905
+ tradeLimit: {
6906
+ type: "string",
6907
+ description: "Max trades 1-100"
6908
+ }
6909
+ },
6910
+ required: ["authorId"]
6911
+ },
6912
+ handler: async (rawArgs, context) => {
6913
+ const args = asRecord(rawArgs);
6914
+ const authorId = requireString(args, "authorId");
6915
+ const period = readString(args, "period");
6916
+ const instCcy = readString(args, "instCcy");
6917
+ const tradeLimit = readString(args, "tradeLimit");
6918
+ const [profileRes, positionsRes, tradesRes] = await Promise.all([
6919
+ context.client.privateGet(
6920
+ PATH_LEADERBOARD,
6921
+ compactObject({ authorIds: authorId, period }),
6922
+ publicRateLimit("smartmoney_get_traders", 5)
6923
+ ),
6924
+ context.client.privateGet(
6925
+ PATH_POSITION_CURRENT,
6926
+ compactObject({ authorId, instCcy }),
6927
+ publicRateLimit("smartmoney_trader_positions", 5)
6928
+ ),
6929
+ context.client.privateGet(
6930
+ PATH_TRADE_RECORDS,
6931
+ compactObject({ authorId, instCcy, limit: tradeLimit }),
6932
+ publicRateLimit("smartmoney_trade_records", 5)
6933
+ )
6934
+ ]);
6935
+ const profileNorm = normalizeResponse(profileRes);
6936
+ const positionsNorm = normalizeResponse(positionsRes);
6937
+ const tradesNorm = normalizeResponse(tradesRes);
6938
+ return {
6939
+ endpoint: "smartmoney_get_trader_detail (composite)",
6940
+ requestTime: (/* @__PURE__ */ new Date()).toISOString(),
6941
+ data: {
6942
+ profile: extractLeaderboardData(profileNorm.data),
6943
+ positions: positionsNorm.data,
6944
+ trades: tradesNorm.data
6945
+ }
6946
+ };
6947
+ }
6948
+ }
6949
+ ];
6950
+ return tools.map(withSmartmoneyDemoGuard);
6951
+ }
6429
6952
  function buildContractTradeTools(cfg) {
6430
6953
  const { prefix, module, label, instTypes, instIdExample } = cfg;
6431
6954
  const [defaultType, otherType] = instTypes;
@@ -6767,31 +7290,58 @@ function buildContractTradeTools(cfg) {
6767
7290
  {
6768
7291
  name: n("set_leverage"),
6769
7292
  module,
6770
- description: `Set leverage for a ${label} instrument or position. [CAUTION] Changes risk parameters.`,
7293
+ description: `Set leverage for a ${label} instrument or position. [CAUTION] Changes risk parameters.
7294
+ Scenarios (SWAP/FUTURES only):
7295
+ \u2022 cross + any instId under the index \u2192 sets leverage at the index level
7296
+ \u2022 isolated + buy-sell (net) posMode \u2192 instId only
7297
+ \u2022 isolated + long-short (hedge) posMode \u2192 instId + posSide=long|short (BOTH directions must be set separately)
7298
+ Not supported: PORTFOLIO MARGIN accounts cannot adjust cross leverage for SWAP/FUTURES \u2014 the request will be rejected by OKX. Use account_get_config first if unsure of the account's margin mode.`,
6771
7299
  isWrite: true,
6772
7300
  inputSchema: {
6773
7301
  type: "object",
6774
7302
  properties: {
6775
7303
  instId: { type: "string", description: instIdExample },
6776
- lever: { type: "string", description: "Leverage, e.g. '10'" },
7304
+ lever: {
7305
+ type: "string",
7306
+ description: "Leverage multiplier as a positive number string, e.g. '10'. Max value depends on the instrument (query market_get_instruments \u2192 lever)."
7307
+ },
6777
7308
  mgnMode: { type: "string", enum: ["cross", "isolated"] },
6778
7309
  posSide: {
6779
7310
  type: "string",
6780
- enum: ["long", "short", "net"],
6781
- description: "Required for isolated margin in hedge mode"
7311
+ enum: ["long", "short"],
7312
+ description: "REQUIRED when mgnMode=isolated AND the account is in hedge (long/short) position mode. Use 'long' or 'short' \u2014 setting one side does NOT auto-apply to the other. Omit entirely for one-way (net) position mode or for cross margin."
6782
7313
  }
6783
7314
  },
6784
7315
  required: ["instId", "lever", "mgnMode"]
6785
7316
  },
6786
7317
  handler: async (rawArgs, context) => {
6787
7318
  const args = asRecord(rawArgs);
7319
+ const instId = requireString(args, "instId");
7320
+ const leverRaw = requireString(args, "lever");
7321
+ const leverNum = Number(leverRaw);
7322
+ if (!Number.isFinite(leverNum) || leverNum <= 0) {
7323
+ throw new ValidationError(
7324
+ `Parameter "lever" must be a positive number string, got "${leverRaw}".`
7325
+ );
7326
+ }
7327
+ const mgnMode = requireString(args, "mgnMode");
7328
+ assertEnum(mgnMode, "mgnMode", ["cross", "isolated"]);
7329
+ const posSide = readString(args, "posSide");
7330
+ if (posSide !== void 0) {
7331
+ assertEnum(posSide, "posSide", ["long", "short"]);
7332
+ if (mgnMode === "cross") {
7333
+ throw new ValidationError(
7334
+ `posSide="${posSide}" is only valid with mgnMode="isolated" in hedge mode. Omit posSide for cross margin.`
7335
+ );
7336
+ }
7337
+ }
6788
7338
  const response = await context.client.privatePost(
6789
7339
  "/api/v5/account/set-leverage",
6790
7340
  compactObject({
6791
- instId: requireString(args, "instId"),
6792
- lever: requireString(args, "lever"),
6793
- mgnMode: requireString(args, "mgnMode"),
6794
- posSide: readString(args, "posSide")
7341
+ instId,
7342
+ lever: leverRaw,
7343
+ mgnMode,
7344
+ posSide
6795
7345
  }),
6796
7346
  privateRateLimit(n("set_leverage"), 20)
6797
7347
  );
@@ -7664,7 +8214,7 @@ function registerMarketFilterTools() {
7664
8214
  sortBy: {
7665
8215
  type: "string",
7666
8216
  enum: ["last", "chg24hPct", "marketCapUsd", "volUsd24h", "fundingRate", "oiUsd", "listTime"],
7667
- description: "Sort field. Default: volUsd24h. Note: marketCapUsd is only meaningful for SPOT (null for SWAP/FUTURES)."
8217
+ description: "Sort field. Default: volUsd24h. Note: marketCapUsd is only meaningful for SPOT (null for SWAP/FUTURES). To rank by OI *change* (oiDeltaPct / absOiDeltaPct), use market_filter_oi_change \u2014 market_filter only sorts by the current snapshot."
7668
8218
  },
7669
8219
  sortOrder: {
7670
8220
  type: "string",
@@ -7777,7 +8327,7 @@ function registerMarketFilterTools() {
7777
8327
  bar: {
7778
8328
  type: "string",
7779
8329
  enum: [...OI_BARS],
7780
- description: "Bar window for OI change computation: 5m, 15m, 1H, 4H, 1D. Default: 1H"
8330
+ description: "Bar window for OI change computation: 5m, 15m, 1H, 4H, 1D (case-insensitive on server, but send canonical form here). Default: 1H"
7781
8331
  },
7782
8332
  // Filters
7783
8333
  minOiUsd: {
@@ -7795,8 +8345,8 @@ function registerMarketFilterTools() {
7795
8345
  // Sort / pagination
7796
8346
  sortBy: {
7797
8347
  type: "string",
7798
- enum: ["oiUsd", "oiDeltaUsd", "oiDeltaPct", "volUsd24h", "last"],
7799
- description: "Sort field. Default: oiDeltaPct (largest movers first)"
8348
+ enum: ["oiUsd", "oiDeltaUsd", "oiDeltaPct", "absOiDeltaPct", "volUsd24h", "fundingRate", "last"],
8349
+ description: "Sort field. Default: oiDeltaPct (largest movers first, signed \u2014 longs and shorts separate). Use absOiDeltaPct to sort by |oiDeltaPct| (largest-magnitude moves regardless of direction). fundingRate is also supported for SWAP. Do NOT use the market_filter tool's sort fields (chg24hPct, marketCapUsd, listTime) here \u2014 they are not in the OI-change Row."
7800
8350
  },
7801
8351
  sortOrder: {
7802
8352
  type: "string",
@@ -7852,7 +8402,7 @@ var D_COINS_SENTIMENT = 'Comma-separated uppercase ticker symbols, max 20 (e.g.
7852
8402
  var D_LANGUAGE = "Content language: zh-CN or en-US. Infer from user's message. No server default.";
7853
8403
  var D_BEGIN = "Start time, Unix epoch milliseconds. API defaults to 72 hours ago when omitted. Pass explicitly for older topics (e.g. 'last 30 days'). Max range: 180 days. Parse relative time if given.";
7854
8404
  var D_END = "End time, Unix epoch milliseconds. Parse relative time if given. Omit for no upper bound.";
7855
- var D_IMPORTANCE = "Importance filter: high (server default) or low. Omit unless user wants broader coverage.";
8405
+ var D_IMPORTANCE = "Importance filter: 'low' returns all news (both low and high importance); 'high' narrows to major/breaking news only. Omitted \u2192 server default (high-only). Default to 'low' for broad browsing; pass 'high' only when the user explicitly asks for major news.";
7856
8406
  var D_PLATFORM = "Filter by news source. Use values from news_get_domains (e.g. blockbeats, odaily_flash). Omit for all sources.";
7857
8407
  var D_LIMIT = "Number of results (default 10, max 50).";
7858
8408
  function registerNewsTools() {
@@ -7863,7 +8413,7 @@ function registerNewsTools() {
7863
8413
  {
7864
8414
  name: "news_get_latest",
7865
8415
  module: "news",
7866
- description: "Get crypto news sorted by time. Omitting importance still returns only high-importance news (server default). Pass importance='low' explicitly to broaden results. Use when user asks 'what happened recently', 'latest news', 'any big news today', or wants to browse without a keyword. For coin-specific news, use news_get_by_coin instead.",
8416
+ description: "Get crypto news sorted by time. For broad browsing ('what happened recently', 'latest news', 'any big news today'), pass importance='low' to include both high and low importance. Server default (when importance omitted) returns only high-importance news. For coin-specific news, use news_get_by_coin instead.",
7867
8417
  isWrite: false,
7868
8418
  inputSchema: {
7869
8419
  type: "object",
@@ -9524,6 +10074,82 @@ function registerSpotTradeTools() {
9524
10074
  );
9525
10075
  return normalizeResponse(response);
9526
10076
  }
10077
+ },
10078
+ // ── set_leverage (SPOT margin: instId-level isolated OR ccy-level cross) ──
10079
+ // Covers OKX scenarios 1–5 (everything except SWAP/FUTURES, which are in
10080
+ // contract-trade.ts). Callers supply exactly one of {instId, ccy}:
10081
+ // • instId + isolated → scenario 1 (pair-level margin)
10082
+ // • instId + cross → scenario 3 (contract-mode pair-level cross margin)
10083
+ // • ccy + cross → scenarios 2 / 4 / 5 (spot/multi-ccy/PM currency-level cross)
10084
+ // Not applicable: posSide (spot has no long/short hedge).
10085
+ {
10086
+ name: "spot_set_leverage",
10087
+ module: "spot",
10088
+ description: "Set leverage for SPOT margin trading. Provide exactly ONE of instId (pair-level) or ccy (currency-level cross, requires borrow-enabled account / multi-ccy / portfolio margin). [CAUTION] Changes risk parameters.\nScenarios:\n \u2022 instId + mgnMode=isolated \u2192 pair-level isolated margin\n \u2022 instId + mgnMode=cross \u2192 pair-level cross margin (contract-mode account)\n \u2022 ccy + mgnMode=cross \u2192 currency-level cross margin (spot-with-borrow / multi-ccy / portfolio margin)\nWhen ccy is supplied, mgnMode MUST be cross. posSide is never applicable to spot margin.",
10089
+ isWrite: true,
10090
+ inputSchema: {
10091
+ type: "object",
10092
+ properties: {
10093
+ instId: {
10094
+ type: "string",
10095
+ description: "Spot pair, e.g. BTC-USDT. Provide instId OR ccy, not both."
10096
+ },
10097
+ ccy: {
10098
+ type: "string",
10099
+ description: "Margin currency, e.g. BTC. Required only for currency-level cross margin (borrow-enabled / multi-ccy / portfolio margin). Mutually exclusive with instId."
10100
+ },
10101
+ lever: {
10102
+ type: "string",
10103
+ description: "Leverage multiplier as a positive number string, e.g. '3'. Max depends on the pair (query market_get_instruments \u2192 lever) or the account policy for ccy-level."
10104
+ },
10105
+ mgnMode: {
10106
+ type: "string",
10107
+ enum: ["cross", "isolated"],
10108
+ description: "cross or isolated. Must be cross when ccy is supplied."
10109
+ }
10110
+ },
10111
+ required: ["lever", "mgnMode"]
10112
+ },
10113
+ handler: async (rawArgs, context) => {
10114
+ const args = asRecord(rawArgs);
10115
+ const instId = readString(args, "instId");
10116
+ const ccy = readString(args, "ccy");
10117
+ if (!instId && !ccy) {
10118
+ throw new ValidationError(
10119
+ `Missing required parameter: provide either "instId" (pair-level) or "ccy" (currency-level cross margin).`
10120
+ );
10121
+ }
10122
+ if (instId && ccy) {
10123
+ throw new ValidationError(
10124
+ `Parameters "instId" and "ccy" are mutually exclusive \u2014 provide only one. instId sets pair-level leverage; ccy sets currency-level cross margin leverage.`
10125
+ );
10126
+ }
10127
+ const leverRaw = requireString(args, "lever");
10128
+ const leverNum = Number(leverRaw);
10129
+ if (!Number.isFinite(leverNum) || leverNum <= 0) {
10130
+ throw new ValidationError(
10131
+ `Parameter "lever" must be a positive number string, got "${leverRaw}".`
10132
+ );
10133
+ }
10134
+ const mgnMode = requireString(args, "mgnMode");
10135
+ assertEnum(mgnMode, "mgnMode", ["cross", "isolated"]);
10136
+ if (ccy && mgnMode !== "cross") {
10137
+ throw new ValidationError(
10138
+ `When "ccy" is supplied, "mgnMode" must be "cross" (currency-level leverage only applies to cross margin).`
10139
+ );
10140
+ }
10141
+ const response = await context.client.privatePost(
10142
+ "/api/v5/account/set-leverage",
10143
+ compactObject({
10144
+ instId,
10145
+ ccy,
10146
+ lever: leverRaw,
10147
+ mgnMode
10148
+ }),
10149
+ privateRateLimit("spot_set_leverage", 20)
10150
+ );
10151
+ return normalizeResponse(response);
10152
+ }
9527
10153
  }
9528
10154
  ];
9529
10155
  }
@@ -9655,6 +10281,7 @@ function allToolSpecs() {
9655
10281
  ...registerNewsTools(),
9656
10282
  ...registerBotTools(),
9657
10283
  ...registerAllEarnTools(),
10284
+ ...registerSmartmoneyTools(),
9658
10285
  ...registerAuditTools(),
9659
10286
  ...registerSkillsTools()
9660
10287
  ];
@@ -11015,7 +11642,7 @@ async function cmdDiagnoseMcp(options = {}) {
11015
11642
 
11016
11643
  // src/commands/diagnose.ts
11017
11644
  var CLI_VERSION = readCliVersion();
11018
- var GIT_HASH = true ? "e9764c9" : "dev";
11645
+ var GIT_HASH = true ? "d5c8ab1" : "dev";
11019
11646
  function maskKey2(key) {
11020
11647
  if (!key) return "(not set)";
11021
11648
  if (key.length <= 8) return "****";
@@ -11554,17 +12181,17 @@ var CLI_REGISTRY = {
11554
12181
  },
11555
12182
  filter: {
11556
12183
  toolName: "market_filter",
11557
- usage: "okx market filter --instType <SPOT|SWAP|FUTURES> [--sortBy <field>] [--sortOrder <asc|desc>] [--limit <n>] [--baseCcy <ccy>] [--quoteCcy <ccy>] [--settleCcy <ccy>] [--instFamily <fam>] [--ctType <linear|inverse>] [--minLast <n>] [--maxLast <n>] [--minChg24hPct <n>] [--maxChg24hPct <n>] [--minMarketCapUsd <n>] [--maxMarketCapUsd <n>] [--minVolUsd24h <n>] [--maxVolUsd24h <n>] [--minFundingRate <n>] [--maxFundingRate <n>] [--minOiUsd <n>] [--maxOiUsd <n>]",
11558
- description: "Screen / rank instruments by multi-dimensional criteria (price, volume, OI, funding rate, market cap, etc.)"
12184
+ usage: "okx market filter --instType <SPOT|SWAP|FUTURES> [--sortBy <last|chg24hPct|marketCapUsd|volUsd24h|fundingRate|oiUsd|listTime>] [--sortOrder <asc|desc>] [--limit <1-100>] [--baseCcy <ccy>] [--quoteCcy <ccy>] [--settleCcy <ccy>] [--instFamily <fam>] [--ctType <linear|inverse>] [--minLast <n>] [--maxLast <n>] [--minChg24hPct <n>] [--maxChg24hPct <n>] [--minMarketCapUsd <n>] [--maxMarketCapUsd <n>] [--minVolUsd24h <n>] [--maxVolUsd24h <n>] [--minFundingRate <n>] [--maxFundingRate <n>] [--minOiUsd <n>] [--maxOiUsd <n>]",
12185
+ description: "Screen / rank instruments by multi-dimensional criteria (price, volume, OI, funding rate, market cap, etc.). For OI *change* ranking use `market oi-change`."
11559
12186
  },
11560
12187
  "oi-history": {
11561
12188
  toolName: "market_get_oi_history",
11562
- usage: "okx market oi-history <instId> [--bar <5m|15m|1H|4H|1D>] [--limit <n>] [--ts <ms>]",
12189
+ usage: "okx market oi-history <instId> [--bar <5m|15m|1H|4H|1D>] [--limit <1-500>] [--ts <ms>]",
11563
12190
  description: "Open interest history time series with bar-over-bar delta for a single instrument"
11564
12191
  },
11565
12192
  "oi-change": {
11566
12193
  toolName: "market_filter_oi_change",
11567
- usage: "okx market oi-change --instType <SWAP|FUTURES> [--bar <5m|15m|1H|4H|1D>] [--sortBy <field>] [--sortOrder <asc|desc>] [--limit <n>] [--minOiUsd <n>] [--minVolUsd24h <n>] [--minAbsOiDeltaPct <n>]",
12194
+ usage: "okx market oi-change --instType <SWAP|FUTURES> [--bar <5m|15m|1H|4H|1D>] [--sortBy <oiUsd|oiDeltaUsd|oiDeltaPct|absOiDeltaPct|volUsd24h|fundingRate|last>] [--sortOrder <asc|desc>] [--limit <1-100>] [--minOiUsd <n>] [--minVolUsd24h <n>] [--minAbsOiDeltaPct <n>]",
11568
12195
  description: "Find instruments with largest OI changes over a bar window (accumulation/distribution scanner)"
11569
12196
  }
11570
12197
  },
@@ -11577,10 +12204,10 @@ var CLI_REGISTRY = {
11577
12204
  usage: "okx market indicator list",
11578
12205
  description: "List all supported technical indicators"
11579
12206
  },
11580
- "<instId> <indicator>": {
12207
+ "<indicator> <instId>": {
11581
12208
  toolName: "market_get_indicator",
11582
- usage: "okx market indicator <instId> <indicator> [--bar <bar>] [--limit <n>] [--backtest-time <ts>] [--params <json>]",
11583
- description: "Get indicator values for an instrument (e.g. okx market indicator BTC-USDT-SWAP rsi)"
12209
+ usage: "okx market indicator <indicator> <instId> [--bar <3m|5m|15m|1H|4H|12Hutc|1Dutc|3Dutc|1Wutc>] [--limit <1-100>] [--backtest-time <ts>] [--params <json>]",
12210
+ description: "Get indicator values for an instrument (e.g. okx market indicator rsi BTC-USDT-SWAP). NOTE: 1m is not supported for indicators."
11584
12211
  }
11585
12212
  }
11586
12213
  }
@@ -11700,6 +12327,11 @@ var CLI_REGISTRY = {
11700
12327
  alternateTools: ["spot_batch_amend", "spot_batch_cancel"],
11701
12328
  usage: "okx spot batch --action <place|amend|cancel> --orders '<json>'",
11702
12329
  description: "Batch place, amend, or cancel spot orders"
12330
+ },
12331
+ leverage: {
12332
+ toolName: "spot_set_leverage",
12333
+ usage: "okx spot leverage ( --instId <pair> | --ccy <ccy> ) --lever <positive-number> --mgnMode <cross|isolated>",
12334
+ description: "Set leverage for SPOT margin. Provide instId (pair-level) OR ccy (currency-level cross, for borrow-enabled/multi-ccy/portfolio margin). When ccy is used, mgnMode must be cross."
11703
12335
  }
11704
12336
  },
11705
12337
  subgroups: {
@@ -11782,8 +12414,8 @@ var CLI_REGISTRY = {
11782
12414
  },
11783
12415
  leverage: {
11784
12416
  toolName: "swap_set_leverage",
11785
- usage: "okx swap leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <side>]",
11786
- description: "Set leverage for a swap instrument"
12417
+ usage: "okx swap leverage --instId <id> --lever <positive-number> --mgnMode <cross|isolated> [--posSide <long|short>]",
12418
+ description: "Set leverage for a swap instrument. posSide is REQUIRED when mgnMode=isolated and account is in hedge mode \u2014 must be set for BOTH long and short separately. Not supported for portfolio margin + cross."
11787
12419
  },
11788
12420
  "get-leverage": {
11789
12421
  toolName: "swap_get_leverage",
@@ -11881,8 +12513,8 @@ var CLI_REGISTRY = {
11881
12513
  },
11882
12514
  leverage: {
11883
12515
  toolName: "futures_set_leverage",
11884
- usage: "okx futures leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <net|long|short>]",
11885
- description: "Set leverage for a futures instrument"
12516
+ usage: "okx futures leverage --instId <id> --lever <positive-number> --mgnMode <cross|isolated> [--posSide <long|short>]",
12517
+ description: "Set leverage for a futures instrument. posSide is REQUIRED when mgnMode=isolated and account is in hedge mode \u2014 must be set for BOTH long and short separately. Not supported for portfolio margin + cross."
11886
12518
  },
11887
12519
  batch: {
11888
12520
  toolName: "futures_batch_orders",
@@ -12192,9 +12824,14 @@ var CLI_REGISTRY = {
12192
12824
  usage: "okx bot grid create --instId <id> --algoOrdType <grid|contract_grid> --maxPx <px> --minPx <px> --gridNum <n>\n [--runType <1|2>] [--quoteSz <n>] [--baseSz <n>]\n [--direction <long|short|neutral>] [--lever <n>] [--sz <n>] [--basePos] [--no-basePos]\n [--tpTriggerPx <px>] [--slTriggerPx <px>] [--tpRatio <n>] [--slRatio <n>] [--algoClOrdId <id>]",
12193
12825
  description: "Create a new grid bot order (contract grid opens base position by default)"
12194
12826
  },
12827
+ amend: {
12828
+ toolName: "grid_amend_order",
12829
+ usage: "okx bot grid amend --algoId <id> --maxPx <px> --minPx <px> --gridNum <n> [--topUpAmt <n>]\n okx bot grid amend --algoId <id> --instId <id> [--tpTriggerPx <px>] [--slTriggerPx <px>] [--tpRatio <n>] [--slRatio <n>] [--topUpAmt <n>]",
12830
+ description: "Amend a running grid bot. Price-range mode: provide --maxPx/--minPx/--gridNum. TP/SL mode: provide --instId and TP/SL flags."
12831
+ },
12195
12832
  stop: {
12196
12833
  toolName: "grid_stop_order",
12197
- usage: "okx bot grid stop --algoId <id> --algoOrdType <type> --instId <id> [--stopType <1|2|3|5|6>]",
12834
+ usage: "okx bot grid stop --algoId <id> --algoOrdType <type> --instId <id> [--stopType <1|2>]",
12198
12835
  description: "Stop a running grid bot order"
12199
12836
  }
12200
12837
  }
@@ -12282,6 +12919,37 @@ var CLI_REGISTRY = {
12282
12919
  }
12283
12920
  }
12284
12921
  },
12922
+ // ── smartmoney ─────────────────────────────────────────────────────────────
12923
+ smartmoney: {
12924
+ description: "Smart money signals \u2014 trader leaderboard, consensus signals, and position analysis",
12925
+ commands: {
12926
+ overview: {
12927
+ toolName: "smartmoney_get_overview",
12928
+ usage: "okx smartmoney overview [--dataVersion <ver>] [--ts <ms>] [--instType <SWAP|SPOT>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--lmtNum <n>] [--instCcyList <ccys>] [--instCcy <ccy>] [--topInstruments <n>] [--json]",
12929
+ description: "Multi-currency smart money overview with aggregated signals"
12930
+ },
12931
+ signal: {
12932
+ toolName: "smartmoney_get_signal",
12933
+ usage: "okx smartmoney signal [--instId <id>] [--instCcy <ccy>] [--dataVersion <ver>] [--ts <ms>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--lmtNum <n>] [--authorIds <ids>] [--json]",
12934
+ description: "Single-currency aggregated consensus signal"
12935
+ },
12936
+ "signal-history": {
12937
+ toolName: "smartmoney_get_signal_history",
12938
+ usage: "okx smartmoney signal-history --instId <id> [--dataVersion <ver>] [--ts <ms>] [--granularity <1h|1d>] [--limit <n>] [--sortType <pnl|pnlRatio>] [--period <3|7|30|90>] [--pnl <tier>] [--winRatio <tier>] [--maxRetreat <tier>] [--asset <tier>] [--json]",
12939
+ description: "Signal history timeline for trend analysis"
12940
+ },
12941
+ traders: {
12942
+ toolName: "smartmoney_get_traders",
12943
+ usage: 'okx smartmoney traders [--dataVersion <ts>] [--sortType <pnl|pnl_ratio>] [--period <""|3|7|30|90>] [--pnl <n>] [--winRatio <r>] [--maxRetreat <r>] [--asset <n>] [--authorIds <ids>] [--limit <n>] [--after <id>] [--before <id>] [--json]',
12944
+ description: "List/filter traders from the smart money leaderboard"
12945
+ },
12946
+ trader: {
12947
+ toolName: "smartmoney_get_trader_detail",
12948
+ usage: "okx smartmoney trader --authorId <id> [--period <3|7|30|90>] [--instCcy <ccy>] [--tradeLimit <n>] [--json]",
12949
+ description: "Trader full portrait (profile + positions + trades)"
12950
+ }
12951
+ }
12952
+ },
12285
12953
  // ── config ─────────────────────────────────────────────────────────────────
12286
12954
  config: {
12287
12955
  description: "Manage CLI configuration profiles",
@@ -12581,7 +13249,7 @@ function formatTime(ts) {
12581
13249
  async function cmdNewsLatest(run, opts) {
12582
13250
  const result = await run("news_get_latest", {
12583
13251
  coins: opts.coins,
12584
- importance: opts.importance,
13252
+ importance: opts.importance ?? "low",
12585
13253
  platform: opts.platform,
12586
13254
  begin: opts.begin,
12587
13255
  end: opts.end,
@@ -12633,7 +13301,7 @@ async function cmdNewsImportant(run, opts) {
12633
13301
  async function cmdNewsByCoin(run, coins, opts) {
12634
13302
  const result = await run("news_get_by_coin", {
12635
13303
  coins,
12636
- importance: opts.importance,
13304
+ importance: opts.importance ?? "low",
12637
13305
  platform: opts.platform,
12638
13306
  begin: opts.begin,
12639
13307
  end: opts.end,
@@ -12659,7 +13327,7 @@ async function cmdNewsSearch(run, keyword, opts) {
12659
13327
  const result = await run("news_search", {
12660
13328
  keyword: keyword || void 0,
12661
13329
  coins: opts.coins,
12662
- importance: opts.importance,
13330
+ importance: opts.importance ?? "low",
12663
13331
  platform: opts.platform,
12664
13332
  sentiment: opts.sentiment,
12665
13333
  sortBy: opts.sortBy,
@@ -13008,6 +13676,7 @@ var CLI_OPTIONS = {
13008
13676
  slRatio: { type: "string" },
13009
13677
  algoClOrdId: { type: "string" },
13010
13678
  stopType: { type: "string" },
13679
+ topUpAmt: { type: "string" },
13011
13680
  live: { type: "boolean", default: false },
13012
13681
  // market extras
13013
13682
  instType: { type: "string" },
@@ -13064,6 +13733,22 @@ var CLI_OPTIONS = {
13064
13733
  // audit
13065
13734
  since: { type: "string" },
13066
13735
  tool: { type: "string" },
13736
+ // smartmoney
13737
+ authorId: { type: "string" },
13738
+ authorIds: { type: "string" },
13739
+ dataVersion: { type: "string" },
13740
+ sortType: { type: "string" },
13741
+ granularity: { type: "string" },
13742
+ lmtNum: { type: "string" },
13743
+ instCcy: { type: "string" },
13744
+ instCcyList: { type: "string" },
13745
+ topInstruments: { type: "string" },
13746
+ tradeLimit: { type: "string" },
13747
+ // smartmoney pool filters
13748
+ pnl: { type: "string" },
13749
+ winRatio: { type: "string" },
13750
+ maxRetreat: { type: "string" },
13751
+ asset: { type: "string" },
13067
13752
  // upgrade
13068
13753
  beta: { type: "boolean", default: false },
13069
13754
  check: { type: "boolean", default: false },
@@ -14065,6 +14750,19 @@ async function cmdSpotBatch(run, opts) {
14065
14750
  if (opts.json) return printJson(data);
14066
14751
  emitBatchResults(data ?? []);
14067
14752
  }
14753
+ async function cmdSpotSetLeverage(run, opts) {
14754
+ const result = await run("spot_set_leverage", {
14755
+ instId: opts.instId,
14756
+ ccy: opts.ccy,
14757
+ lever: opts.lever,
14758
+ mgnMode: opts.mgnMode
14759
+ });
14760
+ const data = getData4(result);
14761
+ if (opts.json) return printJson(data);
14762
+ const r = data?.[0];
14763
+ const target = r?.["instId"] ?? r?.["ccy"] ?? "";
14764
+ outputLine(`Leverage set: ${r?.["lever"]}x ${target} (${r?.["mgnMode"]})`);
14765
+ }
14068
14766
 
14069
14767
  // src/commands/swap.ts
14070
14768
  function getData5(result) {
@@ -15432,6 +16130,178 @@ function extractFixedOffers(result) {
15432
16130
  return [];
15433
16131
  }
15434
16132
 
16133
+ // src/commands/smartmoney.ts
16134
+ function printDataList2(data, json, emptyMsg, mapper) {
16135
+ if (json) {
16136
+ printJson(data);
16137
+ return;
16138
+ }
16139
+ if (!data.length) {
16140
+ outputLine(emptyMsg);
16141
+ return;
16142
+ }
16143
+ printTable(data.map(mapper));
16144
+ }
16145
+ function poolFilterArgs(o) {
16146
+ const result = {};
16147
+ if (o.sortType) result.sortType = o.sortType;
16148
+ if (o.period) result.period = o.period;
16149
+ if (o.pnl) result.pnl = o.pnl;
16150
+ if (o.winRatio) result.winRatio = o.winRatio;
16151
+ if (o.maxRetreat) result.maxRetreat = o.maxRetreat;
16152
+ if (o.asset) result.asset = o.asset;
16153
+ return result;
16154
+ }
16155
+ async function cmdSmartmoneyOverview(run, opts) {
16156
+ const result = await run("smartmoney_get_overview", {
16157
+ dataVersion: opts.dataVersion,
16158
+ ts: opts.ts,
16159
+ instType: opts.instType,
16160
+ ...poolFilterArgs(opts),
16161
+ lmtNum: opts.lmtNum,
16162
+ instCcyList: opts.instCcyList,
16163
+ instCcy: opts.instCcy,
16164
+ topInstruments: opts.topInstruments
16165
+ });
16166
+ const data = extractData(result);
16167
+ printDataList2(data, opts.json, "No overview data", (r) => ({
16168
+ instId: r["instId"],
16169
+ tradersWithPosition: r["tradersWithPosition"],
16170
+ longRatio: r["longRatio"],
16171
+ weightedLongRatio: r["weightedLongRatio"],
16172
+ netNotionalUsdt: r["netNotionalUsdt"],
16173
+ vs24h: r["vs24h"]
16174
+ }));
16175
+ }
16176
+ async function cmdSmartmoneySignal(run, opts) {
16177
+ const result = await run("smartmoney_get_signal", {
16178
+ instId: opts.instId,
16179
+ instCcy: opts.instCcy,
16180
+ dataVersion: opts.dataVersion,
16181
+ ts: opts.ts,
16182
+ ...poolFilterArgs(opts),
16183
+ lmtNum: opts.lmtNum,
16184
+ authorIds: opts.authorIds
16185
+ });
16186
+ const data = extractData(result);
16187
+ const signal = data[0];
16188
+ if (opts.json) {
16189
+ printJson(signal ?? {});
16190
+ return;
16191
+ }
16192
+ if (!signal) {
16193
+ outputLine("No signal data");
16194
+ return;
16195
+ }
16196
+ printKv({
16197
+ instId: signal["instId"],
16198
+ instType: signal["instType"],
16199
+ tradersWithPosition: signal["tradersWithPosition"],
16200
+ tradersTotal: signal["tradersTotal"],
16201
+ longRatio: signal["longRatio"],
16202
+ weightedLongRatio: signal["weightedLongRatio"],
16203
+ avgLongWinRatio: signal["avgLongWinRatio"],
16204
+ avgShortWinRatio: signal["avgShortWinRatio"],
16205
+ longNotionalUsdt: signal["longNotionalUsdt"],
16206
+ shortNotionalUsdt: signal["shortNotionalUsdt"],
16207
+ netNotionalUsdt: signal["netNotionalUsdt"],
16208
+ longTraders: signal["longTraders"],
16209
+ shortTraders: signal["shortTraders"],
16210
+ vs1h: signal["vs1h"],
16211
+ vs24h: signal["vs24h"],
16212
+ vs7d: signal["vs7d"],
16213
+ smartMoneyLongAvgEntry: signal["smartMoneyLongAvgEntry"],
16214
+ smartMoneyShortAvgEntry: signal["smartMoneyShortAvgEntry"],
16215
+ totalNotionalVs24h: signal["totalNotionalVs24h"],
16216
+ currentPrice: signal["currentPrice"],
16217
+ priceChange24h: signal["priceChange24h"],
16218
+ fundingRate: signal["fundingRate"],
16219
+ openInterest: signal["openInterest"],
16220
+ longShortAccountRatio: signal["longShortAccountRatio"]
16221
+ });
16222
+ }
16223
+ async function cmdSmartmoneySignalHistory(run, opts) {
16224
+ const result = await run("smartmoney_get_signal_history", {
16225
+ instId: opts.instId,
16226
+ dataVersion: opts.dataVersion,
16227
+ ts: opts.ts,
16228
+ granularity: opts.granularity,
16229
+ limit: opts.limit,
16230
+ ...poolFilterArgs(opts)
16231
+ });
16232
+ const data = extractData(result);
16233
+ printDataList2(data, opts.json, "No signal history data", (r) => ({
16234
+ ts: r["ts"],
16235
+ longRatio: r["longRatio"],
16236
+ weightedLongRatio: r["weightedLongRatio"],
16237
+ tradersWithPosition: r["tradersWithPosition"],
16238
+ netNotionalUsdt: r["netNotionalUsdt"],
16239
+ totalNotionalUsdt: r["totalNotionalUsdt"],
16240
+ tradersQualified: r["tradersQualified"]
16241
+ }));
16242
+ }
16243
+ async function cmdSmartmoneyTraders(run, opts) {
16244
+ const data = extractData(await run("smartmoney_get_traders", {
16245
+ dataVersion: opts.dataVersion,
16246
+ ...poolFilterArgs(opts),
16247
+ authorIds: opts.authorIds,
16248
+ after: opts.after,
16249
+ before: opts.before,
16250
+ limit: opts.limit
16251
+ }));
16252
+ printDataList2(data, opts.json, "No traders found", (r) => ({
16253
+ authorId: r["authorId"],
16254
+ nickName: r["nickName"],
16255
+ pnl: r["pnl"],
16256
+ pnlRatio: r["pnlRatio"],
16257
+ winRatio: r["winRatio"],
16258
+ asset: r["asset"]
16259
+ }));
16260
+ }
16261
+ async function cmdSmartmoneyTraderDetail(run, opts) {
16262
+ const result = await run("smartmoney_get_trader_detail", {
16263
+ authorId: opts.authorId,
16264
+ period: opts.period,
16265
+ instCcy: opts.instCcy,
16266
+ tradeLimit: opts.tradeLimit
16267
+ });
16268
+ const data = result;
16269
+ const inner = data["data"];
16270
+ if (opts.json) {
16271
+ printJson(inner ?? {});
16272
+ return;
16273
+ }
16274
+ if (!inner) {
16275
+ outputLine("No data");
16276
+ return;
16277
+ }
16278
+ const profileArr = inner["profile"];
16279
+ if (Array.isArray(profileArr) && profileArr.length > 0) {
16280
+ const p = profileArr[0];
16281
+ outputLine("=== Profile ===");
16282
+ printKv({
16283
+ authorId: p["authorId"],
16284
+ nickName: p["nickName"],
16285
+ pnl: p["pnl"],
16286
+ pnlRatio: p["pnlRatio"],
16287
+ winRatio: p["winRatio"],
16288
+ maxRetreat: p["maxRetreat"],
16289
+ asset: p["asset"],
16290
+ onboardDuration: p["onboardDuration"]
16291
+ });
16292
+ }
16293
+ const posArr = inner["positions"];
16294
+ if (Array.isArray(posArr) && posArr.length > 0) {
16295
+ outputLine("\n=== Current Positions ===");
16296
+ printJson(posArr);
16297
+ }
16298
+ const tradeArr = inner["trades"];
16299
+ if (Array.isArray(tradeArr) && tradeArr.length > 0) {
16300
+ outputLine("\n=== Recent Trades ===");
16301
+ printJson(tradeArr);
16302
+ }
16303
+ }
16304
+
15435
16305
  // src/commands/auto-earn.ts
15436
16306
  var USDG_EARN_CURRENCIES = /* @__PURE__ */ new Set(["USDG", "BUIDL"]);
15437
16307
  function isSupported(status) {
@@ -15685,6 +16555,28 @@ async function cmdGridCreate(run, opts) {
15685
16555
  if (opts.json) return printJson(data);
15686
16556
  emitWriteResult5(data?.[0], "Grid bot created", "algoId");
15687
16557
  }
16558
+ async function cmdGridAmend(run, opts) {
16559
+ const result = await run("grid_amend_order", {
16560
+ algoId: opts.algoId,
16561
+ instId: opts.instId,
16562
+ maxPx: opts.maxPx,
16563
+ minPx: opts.minPx,
16564
+ gridNum: opts.gridNum,
16565
+ tpTriggerPx: opts.tpTriggerPx,
16566
+ slTriggerPx: opts.slTriggerPx,
16567
+ tpRatio: opts.tpRatio,
16568
+ slRatio: opts.slRatio,
16569
+ topUpAmt: opts.topUpAmt
16570
+ });
16571
+ const data = getData8(result);
16572
+ if (opts.json) return printJson(data);
16573
+ const item = data?.[0];
16574
+ if (item?.["algoId"]) {
16575
+ outputLine(`Grid bot amended: ${item["algoId"]} (OK)`);
16576
+ } else {
16577
+ emitWriteResult5(item, "Grid bot amended", "algoId");
16578
+ }
16579
+ }
15688
16580
  async function cmdGridStop(run, opts) {
15689
16581
  const result = await run("grid_stop_order", {
15690
16582
  algoId: opts.algoId,
@@ -16912,7 +17804,7 @@ async function cmdEventCancel(run, opts) {
16912
17804
  // src/index.ts
16913
17805
  var _require3 = createRequire3(import.meta.url);
16914
17806
  var CLI_VERSION2 = _require3("../package.json").version;
16915
- var GIT_HASH2 = true ? "e9764c9" : "dev";
17807
+ var GIT_HASH2 = true ? "d5c8ab1" : "dev";
16916
17808
  function handleDohCommand(action, json, force, binaryPath) {
16917
17809
  if (action === "status") return cmdDohStatus(json, binaryPath);
16918
17810
  if (action === "install") return cmdDohInstall(json, binaryPath);
@@ -17017,6 +17909,9 @@ function handleMarketFilterCommand(run, action, rest, v, json) {
17017
17909
  limit,
17018
17910
  json
17019
17911
  });
17912
+ errorLine(`Unknown market command: ${action}`);
17913
+ errorLine("Valid: ticker, tickers, orderbook, candles, trades, instruments, mark-price, funding-rate, open-interest, index-ticker, price-limit, stock-tokens, instruments-by-category, indicator, filter, oi-history, oi-change");
17914
+ process.exitCode = 1;
17020
17915
  }
17021
17916
  function handleIndicatorAction(run, rest, v, json) {
17022
17917
  if (rest[0] === "list") return cmdMarketIndicatorList(json);
@@ -17187,6 +18082,14 @@ function handleSpotCommand(run, action, rest, v, json) {
17187
18082
  return handleSpotAlgoCommand(run, rest[0], v, json);
17188
18083
  if (action === "batch")
17189
18084
  return cmdSpotBatch(run, { action: v.action, orders: v.orders, json });
18085
+ if (action === "leverage")
18086
+ return cmdSpotSetLeverage(run, {
18087
+ instId: v.instId,
18088
+ ccy: v.ccy,
18089
+ lever: v.lever,
18090
+ mgnMode: v.mgnMode,
18091
+ json
18092
+ });
17190
18093
  }
17191
18094
  function handleSwapAlgoCommand(run, subAction, v, json) {
17192
18095
  if (subAction === "trail")
@@ -17580,6 +18483,20 @@ function handleBotGridCommand(run, v, rest, json) {
17580
18483
  algoClOrdId: v.algoClOrdId,
17581
18484
  json
17582
18485
  });
18486
+ if (subAction === "amend")
18487
+ return cmdGridAmend(run, {
18488
+ algoId: v.algoId,
18489
+ instId: v.instId,
18490
+ maxPx: v.maxPx,
18491
+ minPx: v.minPx,
18492
+ gridNum: v.gridNum,
18493
+ tpTriggerPx: v.tpTriggerPx,
18494
+ slTriggerPx: v.slTriggerPx,
18495
+ tpRatio: v.tpRatio,
18496
+ slRatio: v.slRatio,
18497
+ topUpAmt: v.topUpAmt,
18498
+ json
18499
+ });
17583
18500
  if (subAction === "stop")
17584
18501
  return cmdGridStop(run, {
17585
18502
  algoId: v.algoId,
@@ -17672,6 +18589,82 @@ function handleEarnFlashEarnCommand(run, action, v, json) {
17672
18589
  errorLine("Valid: projects");
17673
18590
  process.exitCode = 1;
17674
18591
  }
18592
+ function handleSmartmoneyCommand(run, action, rest, v, json) {
18593
+ const poolFilters = {
18594
+ sortType: v.sortType,
18595
+ period: v.period,
18596
+ pnl: v.pnl,
18597
+ winRatio: v.winRatio,
18598
+ maxRetreat: v.maxRetreat,
18599
+ asset: v.asset
18600
+ };
18601
+ if (action === "overview")
18602
+ return cmdSmartmoneyOverview(run, {
18603
+ dataVersion: v.dataVersion,
18604
+ ts: v.ts,
18605
+ instType: v.instType,
18606
+ ...poolFilters,
18607
+ lmtNum: v.lmtNum,
18608
+ instCcyList: v.instCcyList,
18609
+ instCcy: v.instCcy,
18610
+ topInstruments: v.topInstruments,
18611
+ json
18612
+ });
18613
+ if (action === "signal")
18614
+ return cmdSmartmoneySignal(run, {
18615
+ instId: v.instId,
18616
+ dataVersion: v.dataVersion,
18617
+ ts: v.ts,
18618
+ ...poolFilters,
18619
+ instCcy: v.instCcy,
18620
+ lmtNum: v.lmtNum,
18621
+ authorIds: v.authorIds,
18622
+ json
18623
+ });
18624
+ if (action === "signal-history") {
18625
+ if (!v.instId) {
18626
+ errorLine("Missing required --instId: okx smartmoney signal-history --instId <id>");
18627
+ process.exitCode = 1;
18628
+ return;
18629
+ }
18630
+ return cmdSmartmoneySignalHistory(run, {
18631
+ instId: v.instId,
18632
+ dataVersion: v.dataVersion,
18633
+ ts: v.ts,
18634
+ granularity: v.granularity,
18635
+ limit: v.limit,
18636
+ ...poolFilters,
18637
+ json
18638
+ });
18639
+ }
18640
+ if (action === "traders")
18641
+ return cmdSmartmoneyTraders(run, {
18642
+ dataVersion: v.dataVersion,
18643
+ ...poolFilters,
18644
+ authorIds: v.authorIds,
18645
+ after: v.after,
18646
+ before: v.before,
18647
+ limit: v.limit,
18648
+ json
18649
+ });
18650
+ if (action === "trader") {
18651
+ if (!v.authorId) {
18652
+ errorLine("Missing required --authorId: okx smartmoney trader --authorId <id>");
18653
+ process.exitCode = 1;
18654
+ return;
18655
+ }
18656
+ return cmdSmartmoneyTraderDetail(run, {
18657
+ authorId: v.authorId,
18658
+ period: v.period,
18659
+ instCcy: v.instCcy,
18660
+ tradeLimit: v.tradeLimit,
18661
+ json
18662
+ });
18663
+ }
18664
+ errorLine(`Unknown smartmoney command: ${action}`);
18665
+ errorLine("Valid: overview, signal, signal-history, traders, trader");
18666
+ process.exitCode = 1;
18667
+ }
17675
18668
  function handleEarnSavingsCommand(run, action, rest, v, json) {
17676
18669
  const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
17677
18670
  if (action === "balance") return cmdEarnSavingsBalance(run, rest[0] ?? v.ccy, json);
@@ -17961,6 +18954,7 @@ async function main() {
17961
18954
  news: () => handleNewsCommand(run, action, rest, v, json),
17962
18955
  bot: () => handleBotCommand(run, action, rest, v, json),
17963
18956
  earn: () => handleEarnCommand(run, action, rest, v, json),
18957
+ smartmoney: () => handleSmartmoneyCommand(run, action, rest, v, json),
17964
18958
  skill: () => handleSkillCommand(run, action, rest, v, json, config)
17965
18959
  };
17966
18960
  const handler = moduleHandlers[module];
@@ -17995,6 +18989,7 @@ export {
17995
18989
  handleOptionCommand,
17996
18990
  handleSetupCommand,
17997
18991
  handleSkillCommand,
18992
+ handleSmartmoneyCommand,
17998
18993
  handleSpotAlgoCommand,
17999
18994
  handleSpotCommand,
18000
18995
  handleSwapAlgoCommand,