@okx_ai/okx-trade-cli 1.3.1-beta.9 → 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
@@ -969,7 +969,7 @@ function classifyAndCache(node, hostname, failedNodes, cachePath) {
969
969
  if (!node) {
970
970
  return { mode: null, node: null };
971
971
  }
972
- if (node.ip === hostname || node.host === hostname) {
972
+ if (node.ip === hostname && node.host === hostname) {
973
973
  writeCache(hostname, {
974
974
  mode: "direct",
975
975
  node: null,
@@ -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",
@@ -7843,32 +8393,34 @@ function langHeader(lang) {
7843
8393
  return { "Accept-Language": "en-US" };
7844
8394
  }
7845
8395
  var NEWS_DETAIL_LVL = ["brief", "summary", "full"];
7846
- var NEWS_IMPORTANCE = ["high", "medium", "low"];
8396
+ var NEWS_IMPORTANCE = ["high", "low"];
7847
8397
  var NEWS_SENTIMENT = ["bullish", "bearish", "neutral"];
7848
8398
  var NEWS_SORT = ["latest", "relevant"];
7849
8399
  var SENTIMENT_PERIOD = ["1h", "4h", "24h"];
7850
8400
  var D_COINS_NEWS = 'Comma-separated uppercase ticker symbols (e.g. "BTC,ETH"). Normalize names/aliases to standard tickers.';
7851
8401
  var D_COINS_SENTIMENT = 'Comma-separated uppercase ticker symbols, max 20 (e.g. "BTC,ETH"). Normalize names/aliases to standard tickers.';
7852
8402
  var D_LANGUAGE = "Content language: zh-CN or en-US. Infer from user's message. No server default.";
7853
- var D_BEGIN = "Start time, Unix epoch milliseconds. Parse relative time if given (e.g. 'yesterday', 'last 7 days').";
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), medium, 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.";
8406
+ var D_PLATFORM = "Filter by news source. Use values from news_get_domains (e.g. blockbeats, odaily_flash). Omit for all sources.";
7856
8407
  var D_LIMIT = "Number of results (default 10, max 50).";
7857
8408
  function registerNewsTools() {
7858
- return [
8409
+ const tools = [
7859
8410
  // -----------------------------------------------------------------------
7860
8411
  // News browsing tools
7861
8412
  // -----------------------------------------------------------------------
7862
8413
  {
7863
8414
  name: "news_get_latest",
7864
8415
  module: "news",
7865
- description: "Get crypto news sorted by time. Omitting importance still returns only high-importance news (server default). Pass importance='medium' or '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.",
7866
8417
  isWrite: false,
7867
8418
  inputSchema: {
7868
8419
  type: "object",
7869
8420
  properties: {
7870
8421
  coins: { type: "string", description: D_COINS_NEWS + " Optional." },
7871
8422
  importance: { type: "string", enum: [...NEWS_IMPORTANCE], description: D_IMPORTANCE },
8423
+ platform: { type: "string", description: D_PLATFORM },
7872
8424
  begin: { type: "number", description: D_BEGIN },
7873
8425
  end: { type: "number", description: D_END },
7874
8426
  language: { type: "string", enum: [...NEWS_LANGUAGE], description: D_LANGUAGE },
@@ -7889,6 +8441,7 @@ function registerNewsTools() {
7889
8441
  compactObject({
7890
8442
  sortBy: "latest",
7891
8443
  importance: readString(args, "importance"),
8444
+ platform: readString(args, "platform"),
7892
8445
  ccyList: readString(args, "coins"),
7893
8446
  begin: readNumber(args, "begin"),
7894
8447
  end: readNumber(args, "end"),
@@ -7912,6 +8465,7 @@ function registerNewsTools() {
7912
8465
  properties: {
7913
8466
  coins: { type: "string", description: D_COINS_NEWS + " Required." },
7914
8467
  importance: { type: "string", enum: [...NEWS_IMPORTANCE], description: D_IMPORTANCE },
8468
+ platform: { type: "string", description: D_PLATFORM },
7915
8469
  begin: { type: "number", description: D_BEGIN },
7916
8470
  end: { type: "number", description: D_END },
7917
8471
  language: { type: "string", enum: [...NEWS_LANGUAGE], description: D_LANGUAGE },
@@ -7932,6 +8486,7 @@ function registerNewsTools() {
7932
8486
  sortBy: "latest",
7933
8487
  ccyList: coins,
7934
8488
  importance: readString(args, "importance"),
8489
+ platform: readString(args, "platform"),
7935
8490
  begin: readNumber(args, "begin"),
7936
8491
  end: readNumber(args, "end"),
7937
8492
  detailLvl: readString(args, "detailLvl"),
@@ -7957,6 +8512,7 @@ function registerNewsTools() {
7957
8512
  },
7958
8513
  coins: { type: "string", description: D_COINS_NEWS + " Optional." },
7959
8514
  importance: { type: "string", enum: [...NEWS_IMPORTANCE], description: D_IMPORTANCE },
8515
+ platform: { type: "string", description: D_PLATFORM },
7960
8516
  sentiment: {
7961
8517
  type: "string",
7962
8518
  enum: [...NEWS_SENTIMENT],
@@ -7984,6 +8540,7 @@ function registerNewsTools() {
7984
8540
  keyword: readString(args, "keyword") || void 0,
7985
8541
  sortBy: readString(args, "sortBy") ?? "relevant",
7986
8542
  importance: readString(args, "importance"),
8543
+ platform: readString(args, "platform"),
7987
8544
  ccyList: readString(args, "coins"),
7988
8545
  sentiment: readString(args, "sentiment"),
7989
8546
  begin: readNumber(args, "begin"),
@@ -8129,6 +8686,24 @@ function registerNewsTools() {
8129
8686
  }
8130
8687
  }
8131
8688
  ];
8689
+ const domainsIdx = tools.findIndex((t) => t.name === "news_get_domains");
8690
+ if (domainsIdx === -1) throw new Error("news_get_domains not found in tools list");
8691
+ const [domainsTool] = tools.splice(domainsIdx, 1);
8692
+ return [...tools.map(withNewsDemoGuard), domainsTool];
8693
+ }
8694
+ var NEWS_DEMO_MESSAGE = "News features are not available in demo/simulated trading mode.";
8695
+ var NEWS_DEMO_SUGGESTION = "Switch to a live profile to use News features.";
8696
+ function withNewsDemoGuard(tool) {
8697
+ const originalHandler = tool.handler;
8698
+ return {
8699
+ ...tool,
8700
+ handler: async (args, context) => {
8701
+ if (context.config.demo) {
8702
+ throw new ConfigError(NEWS_DEMO_MESSAGE, NEWS_DEMO_SUGGESTION);
8703
+ }
8704
+ return originalHandler(args, context);
8705
+ }
8706
+ };
8132
8707
  }
8133
8708
  function registerOptionAlgoTools() {
8134
8709
  return [
@@ -9499,6 +10074,82 @@ function registerSpotTradeTools() {
9499
10074
  );
9500
10075
  return normalizeResponse(response);
9501
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
+ }
9502
10153
  }
9503
10154
  ];
9504
10155
  }
@@ -9630,6 +10281,7 @@ function allToolSpecs() {
9630
10281
  ...registerNewsTools(),
9631
10282
  ...registerBotTools(),
9632
10283
  ...registerAllEarnTools(),
10284
+ ...registerSmartmoneyTools(),
9633
10285
  ...registerAuditTools(),
9634
10286
  ...registerSkillsTools()
9635
10287
  ];
@@ -10990,7 +11642,7 @@ async function cmdDiagnoseMcp(options = {}) {
10990
11642
 
10991
11643
  // src/commands/diagnose.ts
10992
11644
  var CLI_VERSION = readCliVersion();
10993
- var GIT_HASH = true ? "e0312e6" : "dev";
11645
+ var GIT_HASH = true ? "d5c8ab1" : "dev";
10994
11646
  function maskKey2(key) {
10995
11647
  if (!key) return "(not set)";
10996
11648
  if (key.length <= 8) return "****";
@@ -11529,17 +12181,17 @@ var CLI_REGISTRY = {
11529
12181
  },
11530
12182
  filter: {
11531
12183
  toolName: "market_filter",
11532
- 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>]",
11533
- 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`."
11534
12186
  },
11535
12187
  "oi-history": {
11536
12188
  toolName: "market_get_oi_history",
11537
- 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>]",
11538
12190
  description: "Open interest history time series with bar-over-bar delta for a single instrument"
11539
12191
  },
11540
12192
  "oi-change": {
11541
12193
  toolName: "market_filter_oi_change",
11542
- 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>]",
11543
12195
  description: "Find instruments with largest OI changes over a bar window (accumulation/distribution scanner)"
11544
12196
  }
11545
12197
  },
@@ -11552,10 +12204,10 @@ var CLI_REGISTRY = {
11552
12204
  usage: "okx market indicator list",
11553
12205
  description: "List all supported technical indicators"
11554
12206
  },
11555
- "<instId> <indicator>": {
12207
+ "<indicator> <instId>": {
11556
12208
  toolName: "market_get_indicator",
11557
- usage: "okx market indicator <instId> <indicator> [--bar <bar>] [--limit <n>] [--backtest-time <ts>] [--params <json>]",
11558
- 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."
11559
12211
  }
11560
12212
  }
11561
12213
  }
@@ -11675,6 +12327,11 @@ var CLI_REGISTRY = {
11675
12327
  alternateTools: ["spot_batch_amend", "spot_batch_cancel"],
11676
12328
  usage: "okx spot batch --action <place|amend|cancel> --orders '<json>'",
11677
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."
11678
12335
  }
11679
12336
  },
11680
12337
  subgroups: {
@@ -11757,8 +12414,8 @@ var CLI_REGISTRY = {
11757
12414
  },
11758
12415
  leverage: {
11759
12416
  toolName: "swap_set_leverage",
11760
- usage: "okx swap leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <side>]",
11761
- 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."
11762
12419
  },
11763
12420
  "get-leverage": {
11764
12421
  toolName: "swap_get_leverage",
@@ -11856,8 +12513,8 @@ var CLI_REGISTRY = {
11856
12513
  },
11857
12514
  leverage: {
11858
12515
  toolName: "futures_set_leverage",
11859
- usage: "okx futures leverage --instId <id> --lever <n> --mgnMode <cross|isolated> [--posSide <net|long|short>]",
11860
- 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."
11861
12518
  },
11862
12519
  batch: {
11863
12520
  toolName: "futures_batch_orders",
@@ -12167,9 +12824,14 @@ var CLI_REGISTRY = {
12167
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>]",
12168
12825
  description: "Create a new grid bot order (contract grid opens base position by default)"
12169
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
+ },
12170
12832
  stop: {
12171
12833
  toolName: "grid_stop_order",
12172
- 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>]",
12173
12835
  description: "Stop a running grid bot order"
12174
12836
  }
12175
12837
  }
@@ -12257,6 +12919,37 @@ var CLI_REGISTRY = {
12257
12919
  }
12258
12920
  }
12259
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
+ },
12260
12953
  // ── config ─────────────────────────────────────────────────────────────────
12261
12954
  config: {
12262
12955
  description: "Manage CLI configuration profiles",
@@ -12314,7 +13007,7 @@ var CLI_REGISTRY = {
12314
13007
  commands: {
12315
13008
  latest: {
12316
13009
  toolName: "news_get_latest",
12317
- usage: "okx news latest [--coins BTC,ETH] [--lang zh-CN] [--limit 20]"
13010
+ usage: "okx news latest [--coins BTC,ETH] [--platform blockbeats] [--lang zh-CN] [--limit 20]"
12318
13011
  },
12319
13012
  important: {
12320
13013
  toolName: "news_get_latest",
@@ -12323,20 +13016,20 @@ var CLI_REGISTRY = {
12323
13016
  },
12324
13017
  "by-coin": {
12325
13018
  toolName: "news_get_by_coin",
12326
- usage: "okx news by-coin --coins BTC [--importance high] [--lang zh-CN]"
13019
+ usage: "okx news by-coin --coins BTC [--importance high] [--platform blockbeats] [--lang zh-CN]"
12327
13020
  },
12328
13021
  search: {
12329
13022
  toolName: "news_search",
12330
- usage: "okx news search --keyword <term> [--coins BTC] [--sentiment bullish] [--lang zh-CN]"
13023
+ usage: "okx news search --keyword <term> [--coins BTC] [--sentiment bullish] [--platform blockbeats] [--lang zh-CN]"
12331
13024
  },
12332
13025
  detail: {
12333
13026
  toolName: "news_get_detail",
12334
13027
  usage: "okx news detail <id> [--lang zh-CN]"
12335
13028
  },
12336
- domains: {
13029
+ platforms: {
12337
13030
  toolName: "news_get_domains",
12338
- usage: "okx news domains",
12339
- description: "List available news source domains"
13031
+ usage: "okx news platforms",
13032
+ description: "List available news platforms"
12340
13033
  },
12341
13034
  "coin-sentiment": {
12342
13035
  toolName: "news_get_coin_sentiment",
@@ -12349,7 +13042,7 @@ var CLI_REGISTRY = {
12349
13042
  },
12350
13043
  "by-sentiment": {
12351
13044
  toolName: "news_search",
12352
- usage: "okx news by-sentiment --sentiment bullish [--coins BTC] [--sort-by latest]",
13045
+ usage: "okx news by-sentiment --sentiment bullish [--coins BTC] [--importance high] [--platform <source>] [--sort-by latest] [--begin <ms>] [--end <ms>]",
12353
13046
  description: "Browse news filtered by sentiment direction"
12354
13047
  },
12355
13048
  "sentiment-rank": {
@@ -12556,7 +13249,8 @@ function formatTime(ts) {
12556
13249
  async function cmdNewsLatest(run, opts) {
12557
13250
  const result = await run("news_get_latest", {
12558
13251
  coins: opts.coins,
12559
- importance: opts.importance,
13252
+ importance: opts.importance ?? "low",
13253
+ platform: opts.platform,
12560
13254
  begin: opts.begin,
12561
13255
  end: opts.end,
12562
13256
  language: opts.language,
@@ -12583,6 +13277,7 @@ async function cmdNewsImportant(run, opts) {
12583
13277
  const result = await run("news_get_latest", {
12584
13278
  coins: opts.coins,
12585
13279
  importance: "high",
13280
+ platform: opts.platform,
12586
13281
  begin: opts.begin,
12587
13282
  end: opts.end,
12588
13283
  language: opts.language,
@@ -12606,7 +13301,8 @@ async function cmdNewsImportant(run, opts) {
12606
13301
  async function cmdNewsByCoin(run, coins, opts) {
12607
13302
  const result = await run("news_get_by_coin", {
12608
13303
  coins,
12609
- importance: opts.importance,
13304
+ importance: opts.importance ?? "low",
13305
+ platform: opts.platform,
12610
13306
  begin: opts.begin,
12611
13307
  end: opts.end,
12612
13308
  language: opts.language,
@@ -12631,7 +13327,8 @@ async function cmdNewsSearch(run, keyword, opts) {
12631
13327
  const result = await run("news_search", {
12632
13328
  keyword: keyword || void 0,
12633
13329
  coins: opts.coins,
12634
- importance: opts.importance,
13330
+ importance: opts.importance ?? "low",
13331
+ platform: opts.platform,
12635
13332
  sentiment: opts.sentiment,
12636
13333
  sortBy: opts.sortBy,
12637
13334
  begin: opts.begin,
@@ -12684,12 +13381,12 @@ async function cmdNewsDetail(run, id, opts) {
12684
13381
  content
12685
13382
  });
12686
13383
  }
12687
- async function cmdNewsDomains(run, opts) {
13384
+ async function cmdNewsPlatforms(run, opts) {
12688
13385
  const result = await run("news_get_domains", {});
12689
13386
  const raw = getData(result);
12690
13387
  const items = raw?.[0]?.["platform"] ?? [];
12691
13388
  if (opts.json) return printJson(items);
12692
- outputLine("Available news source domains:");
13389
+ outputLine("Available news platforms:");
12693
13390
  items.forEach((d) => outputLine(` ${d}`));
12694
13391
  }
12695
13392
  async function cmdNewsCoinSentiment(run, coins, opts) {
@@ -12979,6 +13676,7 @@ var CLI_OPTIONS = {
12979
13676
  slRatio: { type: "string" },
12980
13677
  algoClOrdId: { type: "string" },
12981
13678
  stopType: { type: "string" },
13679
+ topUpAmt: { type: "string" },
12982
13680
  live: { type: "boolean", default: false },
12983
13681
  // market extras
12984
13682
  instType: { type: "string" },
@@ -13035,6 +13733,22 @@ var CLI_OPTIONS = {
13035
13733
  // audit
13036
13734
  since: { type: "string" },
13037
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" },
13038
13752
  // upgrade
13039
13753
  beta: { type: "boolean", default: false },
13040
13754
  check: { type: "boolean", default: false },
@@ -13071,6 +13785,7 @@ var CLI_OPTIONS = {
13071
13785
  coins: { type: "string" },
13072
13786
  sentiment: { type: "string" },
13073
13787
  importance: { type: "string" },
13788
+ platform: { type: "string" },
13074
13789
  keyword: { type: "string" },
13075
13790
  "detail-lvl": { type: "string" },
13076
13791
  period: { type: "string" },
@@ -14035,6 +14750,19 @@ async function cmdSpotBatch(run, opts) {
14035
14750
  if (opts.json) return printJson(data);
14036
14751
  emitBatchResults(data ?? []);
14037
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
+ }
14038
14766
 
14039
14767
  // src/commands/swap.ts
14040
14768
  function getData5(result) {
@@ -15402,6 +16130,178 @@ function extractFixedOffers(result) {
15402
16130
  return [];
15403
16131
  }
15404
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
+
15405
16305
  // src/commands/auto-earn.ts
15406
16306
  var USDG_EARN_CURRENCIES = /* @__PURE__ */ new Set(["USDG", "BUIDL"]);
15407
16307
  function isSupported(status) {
@@ -15655,6 +16555,28 @@ async function cmdGridCreate(run, opts) {
15655
16555
  if (opts.json) return printJson(data);
15656
16556
  emitWriteResult5(data?.[0], "Grid bot created", "algoId");
15657
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
+ }
15658
16580
  async function cmdGridStop(run, opts) {
15659
16581
  const result = await run("grid_stop_order", {
15660
16582
  algoId: opts.algoId,
@@ -16882,7 +17804,7 @@ async function cmdEventCancel(run, opts) {
16882
17804
  // src/index.ts
16883
17805
  var _require3 = createRequire3(import.meta.url);
16884
17806
  var CLI_VERSION2 = _require3("../package.json").version;
16885
- var GIT_HASH2 = true ? "e0312e6" : "dev";
17807
+ var GIT_HASH2 = true ? "d5c8ab1" : "dev";
16886
17808
  function handleDohCommand(action, json, force, binaryPath) {
16887
17809
  if (action === "status") return cmdDohStatus(json, binaryPath);
16888
17810
  if (action === "install") return cmdDohInstall(json, binaryPath);
@@ -16987,6 +17909,9 @@ function handleMarketFilterCommand(run, action, rest, v, json) {
16987
17909
  limit,
16988
17910
  json
16989
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;
16990
17915
  }
16991
17916
  function handleIndicatorAction(run, rest, v, json) {
16992
17917
  if (rest[0] === "list") return cmdMarketIndicatorList(json);
@@ -17157,6 +18082,14 @@ function handleSpotCommand(run, action, rest, v, json) {
17157
18082
  return handleSpotAlgoCommand(run, rest[0], v, json);
17158
18083
  if (action === "batch")
17159
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
+ });
17160
18093
  }
17161
18094
  function handleSwapAlgoCommand(run, subAction, v, json) {
17162
18095
  if (subAction === "trail")
@@ -17550,6 +18483,20 @@ function handleBotGridCommand(run, v, rest, json) {
17550
18483
  algoClOrdId: v.algoClOrdId,
17551
18484
  json
17552
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
+ });
17553
18500
  if (subAction === "stop")
17554
18501
  return cmdGridStop(run, {
17555
18502
  algoId: v.algoId,
@@ -17642,6 +18589,82 @@ function handleEarnFlashEarnCommand(run, action, v, json) {
17642
18589
  errorLine("Valid: projects");
17643
18590
  process.exitCode = 1;
17644
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
+ }
17645
18668
  function handleEarnSavingsCommand(run, action, rest, v, json) {
17646
18669
  const limit = v.limit !== void 0 ? Number(v.limit) : void 0;
17647
18670
  if (action === "balance") return cmdEarnSavingsBalance(run, rest[0] ?? v.ccy, json);
@@ -17732,15 +18755,16 @@ function handleNewsCommand(run, action, rest, v, json) {
17732
18755
  const period = v.period;
17733
18756
  const points = v.points !== void 0 ? Number(v.points) : 24;
17734
18757
  const sortBy = v["sort-by"];
17735
- const searchOpts = { coins: v.coins, importance: v.importance, sentiment: v.sentiment, sortBy, begin, end, language, detailLvl, limit, after, json };
17736
- const listOpts = { coins: v.coins, importance: v.importance, begin, end, language, detailLvl, limit, after, json };
18758
+ const platform2 = v.platform;
18759
+ const searchOpts = { coins: v.coins, importance: v.importance, platform: platform2, sentiment: v.sentiment, sortBy, begin, end, language, detailLvl, limit, after, json };
18760
+ const listOpts = { coins: v.coins, importance: v.importance, platform: platform2, begin, end, language, detailLvl, limit, after, json };
17737
18761
  const dispatch = {
17738
18762
  latest: () => cmdNewsLatest(run, listOpts),
17739
- important: () => cmdNewsImportant(run, { coins: v.coins, begin, end, language, detailLvl, limit, json }),
17740
- "by-coin": () => cmdNewsByCoin(run, v.coins ?? rest[0], { importance: v.importance, begin, end, language, detailLvl, limit, json }),
18763
+ important: () => cmdNewsImportant(run, { coins: v.coins, platform: platform2, begin, end, language, detailLvl, limit, json }),
18764
+ "by-coin": () => cmdNewsByCoin(run, v.coins ?? rest[0], { importance: v.importance, platform: platform2, begin, end, language, detailLvl, limit, json }),
17741
18765
  search: () => cmdNewsSearch(run, v.keyword ?? rest[0], searchOpts),
17742
18766
  detail: () => cmdNewsDetail(run, rest[0], { language, json }),
17743
- domains: () => cmdNewsDomains(run, { json }),
18767
+ platforms: () => cmdNewsPlatforms(run, { json }),
17744
18768
  "coin-sentiment": () => cmdNewsCoinSentiment(run, v.coins ?? rest[0], { period, json }),
17745
18769
  "coin-trend": () => cmdNewsCoinTrend(run, v.coins ?? rest[0], { period, points, json }),
17746
18770
  // by-sentiment is a convenience wrapper over news_search (no keyword, sentiment filter only)
@@ -17930,6 +18954,7 @@ async function main() {
17930
18954
  news: () => handleNewsCommand(run, action, rest, v, json),
17931
18955
  bot: () => handleBotCommand(run, action, rest, v, json),
17932
18956
  earn: () => handleEarnCommand(run, action, rest, v, json),
18957
+ smartmoney: () => handleSmartmoneyCommand(run, action, rest, v, json),
17933
18958
  skill: () => handleSkillCommand(run, action, rest, v, json, config)
17934
18959
  };
17935
18960
  const handler = moduleHandlers[module];
@@ -17964,6 +18989,7 @@ export {
17964
18989
  handleOptionCommand,
17965
18990
  handleSetupCommand,
17966
18991
  handleSkillCommand,
18992
+ handleSmartmoneyCommand,
17967
18993
  handleSpotAlgoCommand,
17968
18994
  handleSpotCommand,
17969
18995
  handleSwapAlgoCommand,