@pionex/pionex-ai-kit 0.2.47 → 0.2.48

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.
@@ -2038,23 +2038,6 @@ function asPositiveDecimalString2(value, field) {
2038
2038
  function normalizePerpBase(base) {
2039
2039
  return base.endsWith(".PERP") ? base : `${base}.PERP`;
2040
2040
  }
2041
- function parseSmartCopyBuOrderData(raw) {
2042
- const quoteInvestment = asPositiveDecimalString2(raw.quoteInvestment, "buOrderData.quoteInvestment");
2043
- const leverageType = asNonEmptyString3(raw.leverageType, "buOrderData.leverageType");
2044
- assertEnum3(leverageType, "buOrderData.leverageType", ["follow", "fixed"]);
2045
- if (leverageType === "fixed" && raw.leverage == null) {
2046
- throw new Error('Invalid "buOrderData.leverage": required when leverageType is "fixed".');
2047
- }
2048
- const out = { quoteInvestment, leverageType };
2049
- if (raw.leverage != null) out.leverage = asPositiveNumber3(raw.leverage, "buOrderData.leverage");
2050
- if (raw.maxInvestPerOrder != null) out.maxInvestPerOrder = asPositiveDecimalString2(raw.maxInvestPerOrder, "buOrderData.maxInvestPerOrder");
2051
- if (raw.copyMode != null) {
2052
- const copyMode = asNonEmptyString3(raw.copyMode, "buOrderData.copyMode");
2053
- assertEnum3(copyMode, "buOrderData.copyMode", ["fixed_amount", "fixed_ratio"]);
2054
- out.copyMode = copyMode;
2055
- }
2056
- return out;
2057
- }
2058
2041
  function registerBotTools() {
2059
2042
  return [
2060
2043
  {
@@ -2544,62 +2527,76 @@ function registerBotTools() {
2544
2527
  name: "pionex_bot_smart_copy_check_params",
2545
2528
  module: "bot",
2546
2529
  isWrite: false,
2547
- description: "Validate smart copy bot parameters before creating an order. Uses the same buOrderData structure as smart_copy_create. On FailedWithData error the response includes min_investment, max_investment. Endpoint: POST /api/v1/bot/orders/smartCopy/checkParams",
2530
+ description: "Validate smart copy bot parameters before creating an order. Pass quote_investment='0' to get the allowed range only (no investment estimate). Returns max_investment, max_leverage, available_limit (and notional_limit when invest>0). Endpoint: POST /api/v1/bot/orders/smartCopy/checkParams",
2548
2531
  inputSchema: {
2549
2532
  type: "object",
2550
2533
  additionalProperties: false,
2551
- required: ["base", "quote", "buOrderData"],
2534
+ required: ["base", "quote", "leverage", "quote_investment"],
2552
2535
  properties: {
2553
2536
  base: { type: "string", description: "Base currency (e.g. BTC)" },
2554
2537
  quote: { type: "string", description: "Quote currency (e.g. USDT)" },
2555
- buOrderData: {
2556
- type: "object",
2557
- additionalProperties: false,
2558
- required: ["quoteInvestment", "leverageType"],
2559
- properties: {
2560
- quoteInvestment: { type: "string", description: "Investment amount in quote currency." },
2561
- leverageType: { type: "string", enum: ["follow", "fixed"], description: "Follow signal provider's leverage or use fixed value." },
2562
- leverage: { type: "number", description: "Custom leverage (required when leverageType is 'fixed')." },
2563
- maxInvestPerOrder: { type: "string", description: "Maximum investment per replicated order." },
2564
- copyMode: { type: "string", enum: ["fixed_amount", "fixed_ratio"], description: "Copy mode." }
2565
- }
2566
- }
2538
+ leverage: { type: "integer", description: "Leverage multiplier (e.g. 2)" },
2539
+ quote_investment: { type: "string", description: "Investment amount in quote currency; use '0' to get range only" },
2540
+ signal_type: { type: "string", description: "Optional; signal provider UUID to scope the check" },
2541
+ signal_param: { type: "string", description: "Optional; signal parameters as a JSON string" }
2567
2542
  }
2568
2543
  },
2569
2544
  async handler(args, { client }) {
2570
2545
  const base = asNonEmptyString3(args.base, "base");
2571
2546
  const quote = asNonEmptyString3(args.quote, "quote");
2572
- const buOrderData = parseSmartCopyBuOrderData(asObject(args.buOrderData, "buOrderData"));
2573
- return (await client.signedPost("/api/v1/bot/orders/smartCopy/checkParams", { base, quote, buOrderData })).data;
2547
+ const leverage = asPositiveInteger3(args.leverage, "leverage");
2548
+ const quote_investment = asNonEmptyString3(args.quote_investment, "quote_investment");
2549
+ const body = { base, quote, leverage, quote_investment };
2550
+ if (args.signal_type != null) body.signal_type = String(args.signal_type);
2551
+ if (args.signal_param != null) body.signal_param = String(args.signal_param);
2552
+ return (await client.signedPost("/api/v1/bot/orders/smartCopy/checkParams", body)).data;
2574
2553
  }
2575
2554
  },
2576
2555
  {
2577
2556
  name: "pionex_bot_smart_copy_create",
2578
2557
  module: "bot",
2579
2558
  isWrite: true,
2580
- description: "Create a smart copy bot order. Required: base, quote, buOrderData (quoteInvestment, leverageType). Optional top-level: copyFrom (signal source ID), copyBotOrderId. buOrderData optional: leverage (required if leverageType=fixed), maxInvestPerOrder, copyMode.",
2559
+ description: "Create a smart copy bot order. Required: base, quote, bu_order_data.quote_total_investment, bu_order_data.portfolio (each portfolio item needs base, signal_type, leverage). Returns buOrderId on success. Endpoint: POST /api/v1/bot/orders/smartCopy/create",
2581
2560
  inputSchema: {
2582
2561
  type: "object",
2583
2562
  additionalProperties: false,
2584
- required: ["base", "quote", "buOrderData"],
2563
+ required: ["base", "quote", "bu_order_data"],
2585
2564
  properties: {
2586
2565
  base: { type: "string", description: "Base currency (e.g. BTC)" },
2587
2566
  quote: { type: "string", description: "Quote currency (e.g. USDT)" },
2588
- buOrderData: {
2567
+ bu_order_data: {
2589
2568
  type: "object",
2590
2569
  additionalProperties: false,
2591
- required: ["quoteInvestment", "leverageType"],
2570
+ required: ["quote_total_investment", "portfolio"],
2592
2571
  properties: {
2593
- quoteInvestment: { type: "string", description: "Investment amount in quote currency." },
2594
- leverageType: { type: "string", enum: ["follow", "fixed"], description: "Follow signal provider's leverage or use fixed value." },
2595
- leverage: { type: "number", description: "Custom leverage (required when leverageType is 'fixed')." },
2596
- maxInvestPerOrder: { type: "string", description: "Maximum investment per replicated order." },
2597
- copyMode: { type: "string", enum: ["fixed_amount", "fixed_ratio"], description: "Copy mode." }
2572
+ quote_total_investment: { type: "string", description: "Total investment in quote currency" },
2573
+ portfolio: {
2574
+ type: "array",
2575
+ items: {
2576
+ type: "object",
2577
+ additionalProperties: false,
2578
+ required: ["base", "signal_type", "leverage"],
2579
+ properties: {
2580
+ base: { type: "string", description: "Base currency for this signal" },
2581
+ signal_type: { type: "string", description: "Signal provider UUID" },
2582
+ leverage: { type: "integer", description: "Leverage multiplier" },
2583
+ percent: { type: "string", description: "Allocation fraction of total investment (e.g. '1' for 100%)" },
2584
+ signal_param: { type: "string", description: "Signal parameters as a JSON string" },
2585
+ profit_stop_ratio: { type: "string", description: "Take-profit ratio" },
2586
+ loss_stop_ratio: { type: "string", description: "Stop-loss ratio" }
2587
+ }
2588
+ },
2589
+ description: "Portfolio of signals to copy"
2590
+ },
2591
+ compound: { type: "boolean", description: "Enable compound reinvestment" },
2592
+ profit_stop_maker: { type: "boolean", description: "Enable profit stop maker" }
2598
2593
  }
2599
2594
  },
2600
- copyFrom: { type: "string", description: "Signal source / trader ID to copy from." },
2601
- copyBotOrderId: { type: "string", description: "Reference bot order ID for copying settings." },
2602
- __dryRun: { type: "boolean", description: "If true, validate and return resolved body without placing an order." }
2595
+ key_id: { type: "string", description: "Optional key ID" },
2596
+ note: { type: "string", description: "Optional note" },
2597
+ copy_from: { type: "string", description: "Source bot order ID to copy settings from" },
2598
+ copy_type: { type: "string", description: "Copy type" },
2599
+ __dryRun: { type: "boolean", description: "If true, return resolved body without placing an order." }
2603
2600
  }
2604
2601
  },
2605
2602
  async handler(args, { client, config }) {
@@ -2608,16 +2605,33 @@ function registerBotTools() {
2608
2605
  }
2609
2606
  const base = asNonEmptyString3(args.base, "base");
2610
2607
  const quote = asNonEmptyString3(args.quote, "quote");
2611
- const buOrderData = parseSmartCopyBuOrderData(asObject(args.buOrderData, "buOrderData"));
2612
- const body = { base, quote, buOrderData };
2613
- if (args.copyFrom != null) body.copyFrom = String(args.copyFrom);
2614
- if (args.copyBotOrderId != null) body.copyBotOrderId = String(args.copyBotOrderId);
2615
- if (args.__dryRun === true) {
2616
- return {
2617
- dryRun: true,
2618
- note: "No order was sent. Body matches smartCopy/create request.",
2619
- resolvedBody: body
2608
+ const rawBuOrderData = asObject(args.bu_order_data, "bu_order_data");
2609
+ const quote_total_investment = asNonEmptyString3(rawBuOrderData.quote_total_investment, "bu_order_data.quote_total_investment");
2610
+ if (!Array.isArray(rawBuOrderData.portfolio) || rawBuOrderData.portfolio.length === 0) {
2611
+ throw new Error('Invalid "bu_order_data.portfolio": expected non-empty array.');
2612
+ }
2613
+ const portfolio = rawBuOrderData.portfolio.map((item, i) => {
2614
+ const p = {
2615
+ base: asNonEmptyString3(item.base, `portfolio[${i}].base`),
2616
+ signal_type: asNonEmptyString3(item.signal_type, `portfolio[${i}].signal_type`),
2617
+ leverage: asPositiveInteger3(item.leverage, `portfolio[${i}].leverage`)
2620
2618
  };
2619
+ if (item.percent != null) p.percent = asNonEmptyString3(item.percent, `portfolio[${i}].percent`);
2620
+ if (item.signal_param != null) p.signal_param = String(item.signal_param);
2621
+ if (item.profit_stop_ratio != null) p.profit_stop_ratio = String(item.profit_stop_ratio);
2622
+ if (item.loss_stop_ratio != null) p.loss_stop_ratio = String(item.loss_stop_ratio);
2623
+ return p;
2624
+ });
2625
+ const buOrderData = { quote_total_investment, portfolio };
2626
+ if (rawBuOrderData.compound != null) buOrderData.compound = asBoolean2(rawBuOrderData.compound, "bu_order_data.compound");
2627
+ if (rawBuOrderData.profit_stop_maker != null) buOrderData.profit_stop_maker = asBoolean2(rawBuOrderData.profit_stop_maker, "bu_order_data.profit_stop_maker");
2628
+ const body = { base, quote, bu_order_data: buOrderData };
2629
+ if (args.key_id != null) body.key_id = String(args.key_id);
2630
+ if (args.note != null) body.note = String(args.note);
2631
+ if (args.copy_from != null) body.copy_from = String(args.copy_from);
2632
+ if (args.copy_type != null) body.copy_type = String(args.copy_type);
2633
+ if (args.__dryRun === true) {
2634
+ return { dryRun: true, note: "No order was sent.", resolvedBody: body };
2621
2635
  }
2622
2636
  return (await client.signedPost("/api/v1/bot/orders/smartCopy/create", body)).data;
2623
2637
  }
@@ -2630,23 +2644,21 @@ function registerBotTools() {
2630
2644
  inputSchema: {
2631
2645
  type: "object",
2632
2646
  additionalProperties: false,
2633
- required: ["buOrderId"],
2647
+ required: ["bu_order_id"],
2634
2648
  properties: {
2635
- buOrderId: { type: "string", description: "Smart copy bot order ID." },
2636
- closeSellModel: { type: "string", enum: ["NOT_SELL", "TO_QUOTE", "TO_USDT"], description: "How to handle the base asset on close." }
2649
+ bu_order_id: { type: "string", description: "Smart copy bot order ID." },
2650
+ close_note: { type: "string", description: "Optional close note." },
2651
+ convert_into_earn_coin: { type: "boolean", description: "Whether to convert remaining funds into earn coin." }
2637
2652
  }
2638
2653
  },
2639
2654
  async handler(args, { client, config }) {
2640
2655
  if (config.readOnly) {
2641
2656
  throw new Error("Server is running in --read-only mode; bot smart_copy cancel is disabled.");
2642
2657
  }
2643
- const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
2644
- const body = { buOrderId };
2645
- if (args.closeSellModel != null) {
2646
- const closeSellModel = asNonEmptyString3(args.closeSellModel, "closeSellModel");
2647
- assertEnum3(closeSellModel, "closeSellModel", ["NOT_SELL", "TO_QUOTE", "TO_USDT"]);
2648
- body.closeSellModel = closeSellModel;
2649
- }
2658
+ const bu_order_id = asNonEmptyString3(args.bu_order_id, "bu_order_id");
2659
+ const body = { bu_order_id };
2660
+ if (args.close_note != null) body.close_note = String(args.close_note);
2661
+ if (args.convert_into_earn_coin != null) body.convert_into_earn_coin = asBoolean2(args.convert_into_earn_coin, "convert_into_earn_coin");
2650
2662
  return (await client.signedPost("/api/v1/bot/orders/smartCopy/cancel", body)).data;
2651
2663
  }
2652
2664
  },
@@ -2655,24 +2667,49 @@ function registerBotTools() {
2655
2667
  name: "pionex_bot_signal_add_listener",
2656
2668
  module: "bot",
2657
2669
  isWrite: true,
2658
- description: "Subscribe to a signal provider / add a signal listener. Endpoint: POST /api/v1/bot/signal/listener",
2670
+ description: "Push a trading signal to the Pionex signal platform (signal provider use). The platform forwards the signal to all smart copy bots subscribed to the given signalType. Use action='buy' to open a position and action='sell' to close it. Endpoint: POST /api/v1/bot/signal/listener",
2659
2671
  inputSchema: {
2660
2672
  type: "object",
2661
2673
  additionalProperties: false,
2662
- required: ["signalSourceId"],
2674
+ required: ["signalType", "signalParam", "base", "quote", "time", "price", "data"],
2663
2675
  properties: {
2664
- signalSourceId: { type: "string", description: "Signal provider ID to subscribe to." },
2665
- listenMode: { type: "string", description: "Subscription mode." }
2676
+ signalType: { type: "string", description: "Signal provider UUID." },
2677
+ signalParam: { type: "string", description: "Signal parameters as a JSON string (use '{}' for no extra params)." },
2678
+ base: { type: "string", description: "Base currency (e.g. BTC)." },
2679
+ quote: { type: "string", description: "Quote currency (e.g. USDT)." },
2680
+ time: { type: "string", description: "Signal timestamp in RFC 3339 format (e.g. '2024-01-01T12:00:00Z')." },
2681
+ price: { type: "string", description: "Current price at time of signal (e.g. '85000')." },
2682
+ data: {
2683
+ type: "object",
2684
+ additionalProperties: false,
2685
+ required: ["action", "position_size", "contracts"],
2686
+ properties: {
2687
+ action: { type: "string", enum: ["buy", "sell"], description: "'buy' to open a position, 'sell' to close." },
2688
+ position_size: { type: "string", description: "Target position size as a fraction (e.g. '1' = 100%)." },
2689
+ contracts: { type: "string", description: "Number of contracts." },
2690
+ direction: { type: "string", description: "Optional trade direction." }
2691
+ }
2692
+ }
2666
2693
  }
2667
2694
  },
2668
2695
  async handler(args, { client, config }) {
2669
2696
  if (config.readOnly) {
2670
2697
  throw new Error("Server is running in --read-only mode; bot signal add_listener is disabled.");
2671
2698
  }
2672
- const signalSourceId = asNonEmptyString3(args.signalSourceId, "signalSourceId");
2673
- const body = { signalSourceId };
2674
- if (args.listenMode != null) body.listenMode = String(args.listenMode);
2675
- return (await client.signedPost("/api/v1/bot/signal/listener", body)).data;
2699
+ const signalType = asNonEmptyString3(args.signalType, "signalType");
2700
+ const signalParam = asNonEmptyString3(args.signalParam, "signalParam");
2701
+ const base = asNonEmptyString3(args.base, "base");
2702
+ const quote = asNonEmptyString3(args.quote, "quote");
2703
+ const time = asNonEmptyString3(args.time, "time");
2704
+ const price = asNonEmptyString3(args.price, "price");
2705
+ const rawData = asObject(args.data, "data");
2706
+ const action = asNonEmptyString3(rawData.action, "data.action");
2707
+ assertEnum3(action, "data.action", ["buy", "sell"]);
2708
+ const position_size = asNonEmptyString3(rawData.position_size, "data.position_size");
2709
+ const contracts = asNonEmptyString3(rawData.contracts, "data.contracts");
2710
+ const data = { action, position_size, contracts };
2711
+ if (rawData.direction != null) data.direction = String(rawData.direction);
2712
+ return (await client.signedPost("/api/v1/bot/signal/listener", { signalType, signalParam, base, quote, time, price, data })).data;
2676
2713
  }
2677
2714
  }
2678
2715
  ];
@@ -3068,4 +3105,4 @@ smol-toml/dist/index.js:
3068
3105
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3069
3106
  *)
3070
3107
  */
3071
- //# sourceMappingURL=chunk-6GZTCD5R.js.map
3108
+ //# sourceMappingURL=chunk-NAOQJBW5.js.map