@pionex/pionex-trade-mcp 0.2.37 → 0.2.39

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/README.md CHANGED
@@ -39,6 +39,7 @@ Credentials are read from `~/.pionex/config.toml` when the server starts; the cl
39
39
  - **Account** (auth): `pionex_account_get_balance`
40
40
  - **Orders** (auth): `pionex_orders_new_order`, `pionex_orders_get_order`, `pionex_orders_get_order_by_client_order_id`, `pionex_orders_get_open_orders`, `pionex_orders_get_all_orders`, `pionex_orders_cancel_order`, `pionex_orders_get_fills`, `pionex_orders_get_fills_by_order_id`, `pionex_orders_cancel_all_orders`
41
41
  - **Bot / Futures Grid** (auth): `pionex_bot_futures_grid_get_order`, `pionex_bot_futures_grid_create`, `pionex_bot_futures_grid_adjust_params`, `pionex_bot_futures_grid_reduce`, `pionex_bot_futures_grid_cancel`
42
+ - **Bot / Spot Grid** (auth): `pionex_bot_spot_grid_get_order`, `pionex_bot_spot_grid_get_ai_strategy`, `pionex_bot_spot_grid_create`, `pionex_bot_spot_grid_adjust_params`, `pionex_bot_spot_grid_invest_in`, `pionex_bot_spot_grid_cancel`, `pionex_bot_spot_grid_profit`
42
43
 
43
44
  ### `pionex_bot_futures_grid_create` (strict OpenAPI)
44
45
 
package/dist/index.js CHANGED
@@ -1536,6 +1536,24 @@ var createFuturesGridCreateToolInputSchema = {
1536
1536
  __dryRun: { type: "boolean", description: "Internal: when true, return resolved body without POST" }
1537
1537
  }
1538
1538
  };
1539
+ var CREATE_SPOT_GRID_ORDER_DATA_KEYS = [
1540
+ "top",
1541
+ "bottom",
1542
+ "row",
1543
+ "gridType",
1544
+ "quoteTotalInvestment",
1545
+ "lossStopType",
1546
+ "lossStop",
1547
+ "lossStopDelay",
1548
+ "profitStopType",
1549
+ "profitStop",
1550
+ "profitStopDelay",
1551
+ "condition",
1552
+ "conditionDirection",
1553
+ "slippage",
1554
+ "closeSellModel"
1555
+ ];
1556
+ var ORDER_DATA_KEY_SET2 = new Set(CREATE_SPOT_GRID_ORDER_DATA_KEYS);
1539
1557
  function asNonEmptyString2(value, field) {
1540
1558
  if (typeof value !== "string" || value.trim().length === 0) {
1541
1559
  throw new Error(`Invalid "${field}": expected non-empty string.`);
@@ -1560,13 +1578,181 @@ function asPositiveInteger2(value, field) {
1560
1578
  }
1561
1579
  return n;
1562
1580
  }
1581
+ function asNonNegativeInteger(value, field) {
1582
+ const n = asFiniteNumber2(value, field);
1583
+ if (n < 0 || !Number.isInteger(n)) {
1584
+ throw new Error(`Invalid "${field}": expected non-negative integer.`);
1585
+ }
1586
+ return n;
1587
+ }
1588
+ function assertEnum2(value, field, allowed) {
1589
+ if (!allowed.includes(value)) {
1590
+ throw new Error(`Invalid "${field}": expected one of ${allowed.join(", ")}.`);
1591
+ }
1592
+ }
1593
+ function asPositiveDecimalStringLoose2(value, field) {
1594
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
1595
+ return String(value);
1596
+ }
1597
+ if (typeof value !== "string" || value.trim().length === 0) {
1598
+ throw new Error(`Invalid "${field}": expected positive decimal string.`);
1599
+ }
1600
+ const s = value.trim();
1601
+ if (!/^\d+(\.\d+)?$/.test(s)) {
1602
+ throw new Error(`Invalid "${field}": expected positive decimal string.`);
1603
+ }
1604
+ const n = Number(s);
1605
+ if (!Number.isFinite(n) || n <= 0) {
1606
+ throw new Error(`Invalid "${field}": expected positive decimal string.`);
1607
+ }
1608
+ return s;
1609
+ }
1610
+ function asOptionalString2(value, field) {
1611
+ if (typeof value !== "string") {
1612
+ throw new Error(`Invalid "${field}": expected string.`);
1613
+ }
1614
+ return value;
1615
+ }
1616
+ function parseAndValidateCreateSpotGridBuOrderData(raw) {
1617
+ const data = { ...raw };
1618
+ for (const k of Object.keys(data)) {
1619
+ if (!ORDER_DATA_KEY_SET2.has(k)) {
1620
+ throw new Error(`Unknown buOrderData property "${k}". Allowed keys: ${CREATE_SPOT_GRID_ORDER_DATA_KEYS.join(", ")}.`);
1621
+ }
1622
+ }
1623
+ const top = asPositiveDecimalStringLoose2(data.top, "buOrderData.top");
1624
+ const bottom = asPositiveDecimalStringLoose2(data.bottom, "buOrderData.bottom");
1625
+ if (Number(top) <= Number(bottom)) {
1626
+ throw new Error('Invalid "buOrderData.top": expected top > bottom.');
1627
+ }
1628
+ const row = asPositiveInteger2(data.row, "buOrderData.row");
1629
+ if (row < 2 || row > 200) {
1630
+ throw new Error('Invalid "buOrderData.row": expected integer between 2 and 200.');
1631
+ }
1632
+ const gridType = asNonEmptyString2(data.gridType, "buOrderData.gridType");
1633
+ assertEnum2(gridType, "buOrderData.gridType", ["arithmetic", "geometric"]);
1634
+ const quoteTotalInvestment = asPositiveDecimalStringLoose2(data.quoteTotalInvestment, "buOrderData.quoteTotalInvestment");
1635
+ const out = {
1636
+ top,
1637
+ bottom,
1638
+ row,
1639
+ gridType,
1640
+ quoteTotalInvestment
1641
+ };
1642
+ if (data.lossStopType != null) {
1643
+ const v = asNonEmptyString2(data.lossStopType, "buOrderData.lossStopType");
1644
+ assertEnum2(v, "buOrderData.lossStopType", ["price", "profit_amount", "profit_ratio"]);
1645
+ out.lossStopType = v;
1646
+ }
1647
+ if (data.lossStop != null) out.lossStop = asOptionalString2(data.lossStop, "buOrderData.lossStop");
1648
+ if (data.lossStopDelay != null) out.lossStopDelay = asNonNegativeInteger(data.lossStopDelay, "buOrderData.lossStopDelay");
1649
+ if (data.profitStopType != null) {
1650
+ const v = asNonEmptyString2(data.profitStopType, "buOrderData.profitStopType");
1651
+ assertEnum2(v, "buOrderData.profitStopType", ["price", "profit_amount", "profit_ratio"]);
1652
+ out.profitStopType = v;
1653
+ }
1654
+ if (data.profitStop != null) out.profitStop = asOptionalString2(data.profitStop, "buOrderData.profitStop");
1655
+ if (data.profitStopDelay != null) out.profitStopDelay = asNonNegativeInteger(data.profitStopDelay, "buOrderData.profitStopDelay");
1656
+ if (data.condition != null) out.condition = asOptionalString2(data.condition, "buOrderData.condition");
1657
+ if (data.conditionDirection != null) {
1658
+ const v = asNonEmptyString2(data.conditionDirection, "buOrderData.conditionDirection");
1659
+ assertEnum2(v, "buOrderData.conditionDirection", ["-1", "1"]);
1660
+ out.conditionDirection = v;
1661
+ }
1662
+ if (data.slippage != null) out.slippage = asOptionalString2(data.slippage, "buOrderData.slippage");
1663
+ if (data.closeSellModel != null) {
1664
+ const v = asNonEmptyString2(data.closeSellModel, "buOrderData.closeSellModel");
1665
+ assertEnum2(v, "buOrderData.closeSellModel", ["NOT_SELL", "TO_QUOTE", "TO_USDT"]);
1666
+ out.closeSellModel = v;
1667
+ }
1668
+ return out;
1669
+ }
1670
+ var createSpotGridOrderDataJsonSchema = {
1671
+ type: "object",
1672
+ additionalProperties: false,
1673
+ description: "CreateSpotGridOrderData (openapi_bot.yaml PR #7). Required: top, bottom, row, gridType, quoteTotalInvestment.",
1674
+ required: ["top", "bottom", "row", "gridType", "quoteTotalInvestment"],
1675
+ properties: {
1676
+ top: { type: "string", description: "Grid upper price" },
1677
+ bottom: { type: "string", description: "Grid lower price" },
1678
+ row: { type: "number", description: "Number of grid levels (2\u2013200)" },
1679
+ gridType: {
1680
+ type: "string",
1681
+ enum: ["arithmetic", "geometric"],
1682
+ description: "Grid spacing: arithmetic (equal difference) or geometric (equal ratio)"
1683
+ },
1684
+ quoteTotalInvestment: { type: "string", description: "Total quote currency investment amount" },
1685
+ lossStopType: {
1686
+ type: "string",
1687
+ enum: ["price", "profit_amount", "profit_ratio"],
1688
+ description: "Stop loss type"
1689
+ },
1690
+ lossStop: { type: "string", description: "Stop loss threshold value" },
1691
+ lossStopDelay: { type: "number", description: "Seconds before executing stop loss (0=immediate)" },
1692
+ profitStopType: {
1693
+ type: "string",
1694
+ enum: ["price", "profit_amount", "profit_ratio"],
1695
+ description: "Take profit type"
1696
+ },
1697
+ profitStop: { type: "string", description: "Take profit threshold value" },
1698
+ profitStopDelay: { type: "number", description: "Seconds before executing take profit (0=immediate)" },
1699
+ condition: { type: "string", description: "Trigger price for conditional start" },
1700
+ conditionDirection: {
1701
+ type: "string",
1702
+ enum: ["-1", "1"],
1703
+ description: 'Trigger direction: "-1" drop below, "1" rise above'
1704
+ },
1705
+ slippage: { type: "string", description: "Slippage tolerance e.g. 0.01 = 1%" },
1706
+ closeSellModel: {
1707
+ type: "string",
1708
+ enum: ["NOT_SELL", "TO_QUOTE", "TO_USDT"],
1709
+ description: "Close sell model (default: NOT_SELL)"
1710
+ }
1711
+ }
1712
+ };
1713
+ var createSpotGridCreateToolInputSchema = {
1714
+ type: "object",
1715
+ additionalProperties: false,
1716
+ required: ["base", "quote", "buOrderData"],
1717
+ properties: {
1718
+ base: { type: "string", description: "Base currency (e.g. BTC)" },
1719
+ quote: { type: "string", description: "Quote currency (e.g. USDT)" },
1720
+ note: { type: "string", description: "Optional order note" },
1721
+ buOrderData: createSpotGridOrderDataJsonSchema,
1722
+ __dryRun: { type: "boolean", description: "Internal: when true, return resolved body without POST" }
1723
+ }
1724
+ };
1725
+ function asNonEmptyString3(value, field) {
1726
+ if (typeof value !== "string" || value.trim().length === 0) {
1727
+ throw new Error(`Invalid "${field}": expected non-empty string.`);
1728
+ }
1729
+ return value.trim();
1730
+ }
1731
+ function asFiniteNumber3(value, field) {
1732
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1733
+ throw new Error(`Invalid "${field}": expected finite number.`);
1734
+ }
1735
+ return value;
1736
+ }
1737
+ function asPositiveNumber3(value, field) {
1738
+ const n = asFiniteNumber3(value, field);
1739
+ if (n <= 0) throw new Error(`Invalid "${field}": expected number > 0.`);
1740
+ return n;
1741
+ }
1742
+ function asPositiveInteger3(value, field) {
1743
+ const n = asPositiveNumber3(value, field);
1744
+ if (!Number.isInteger(n)) {
1745
+ throw new Error(`Invalid "${field}": expected positive integer.`);
1746
+ }
1747
+ return n;
1748
+ }
1563
1749
  function asBoolean2(value, field) {
1564
1750
  if (typeof value !== "boolean") {
1565
1751
  throw new Error(`Invalid "${field}": expected boolean.`);
1566
1752
  }
1567
1753
  return value;
1568
1754
  }
1569
- function assertEnum2(value, field, allowed) {
1755
+ function assertEnum3(value, field, allowed) {
1570
1756
  if (!allowed.includes(value)) {
1571
1757
  throw new Error(`Invalid "${field}": expected one of ${allowed.join(", ")}.`);
1572
1758
  }
@@ -1578,7 +1764,7 @@ function asObject(value, field) {
1578
1764
  return value;
1579
1765
  }
1580
1766
  function asPositiveDecimalString2(value, field) {
1581
- const s = asNonEmptyString2(value, field);
1767
+ const s = asNonEmptyString3(value, field);
1582
1768
  if (!/^\d+(\.\d+)?$/.test(s)) {
1583
1769
  throw new Error(`Invalid "${field}": expected positive decimal string.`);
1584
1770
  }
@@ -1624,9 +1810,9 @@ function registerBotTools() {
1624
1810
  if (config.readOnly) {
1625
1811
  throw new Error("Server is running in --read-only mode; bot futures_grid create is disabled.");
1626
1812
  }
1627
- const rawBase = asNonEmptyString2(args.base, "base");
1813
+ const rawBase = asNonEmptyString3(args.base, "base");
1628
1814
  const base = normalizePerpBase(rawBase);
1629
- const quote = asNonEmptyString2(args.quote, "quote");
1815
+ const quote = asNonEmptyString3(args.quote, "quote");
1630
1816
  const buOrderDataOut = parseAndValidateCreateFuturesGridBuOrderData(asObject(args.buOrderData, "buOrderData"));
1631
1817
  const row = buOrderDataOut.row;
1632
1818
  const gridType = buOrderDataOut.grid_type;
@@ -1686,12 +1872,12 @@ function registerBotTools() {
1686
1872
  if (config.readOnly) {
1687
1873
  throw new Error("Server is running in --read-only mode; bot futures_grid adjust_params is disabled.");
1688
1874
  }
1689
- const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
1690
- const type = asNonEmptyString2(args.type, "type");
1691
- assertEnum2(type, "type", ["invest_in", "adjust_params", "invest_in_trigger"]);
1875
+ const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
1876
+ const type = asNonEmptyString3(args.type, "type");
1877
+ assertEnum3(type, "type", ["invest_in", "adjust_params", "invest_in_trigger"]);
1692
1878
  const extraMargin = asBoolean2(args.extraMargin, "extraMargin");
1693
1879
  if (type === "invest_in" && args.quoteInvestment != null) {
1694
- asPositiveNumber2(args.quoteInvestment, "quoteInvestment");
1880
+ asPositiveNumber3(args.quoteInvestment, "quoteInvestment");
1695
1881
  }
1696
1882
  if (type === "adjust_params") {
1697
1883
  const bottom = asPositiveDecimalString2(args.bottom, "bottom");
@@ -1699,35 +1885,35 @@ function registerBotTools() {
1699
1885
  if (Number(top) <= Number(bottom)) {
1700
1886
  throw new Error('Invalid "top": expected top > bottom.');
1701
1887
  }
1702
- asPositiveInteger2(args.row, "row");
1888
+ asPositiveInteger3(args.row, "row");
1703
1889
  }
1704
1890
  if (type === "invest_in_trigger") {
1705
1891
  asPositiveDecimalString2(args.condition, "condition");
1706
- const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
1707
- assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
1892
+ const conditionDirection = asNonEmptyString3(args.conditionDirection, "conditionDirection");
1893
+ assertEnum3(conditionDirection, "conditionDirection", ["1", "-1"]);
1708
1894
  }
1709
1895
  const body = {
1710
1896
  buOrderId,
1711
1897
  type,
1712
1898
  extraMargin
1713
1899
  };
1714
- if (args.quoteInvestment != null) body.quoteInvestment = asFiniteNumber2(args.quoteInvestment, "quoteInvestment");
1900
+ if (args.quoteInvestment != null) body.quoteInvestment = asFiniteNumber3(args.quoteInvestment, "quoteInvestment");
1715
1901
  if (args.bottom != null) body.bottom = asPositiveDecimalString2(args.bottom, "bottom");
1716
1902
  if (args.top != null) body.top = asPositiveDecimalString2(args.top, "top");
1717
- if (args.row != null) body.row = asPositiveInteger2(args.row, "row");
1718
- if (args.extraMarginAmount != null) body.extraMarginAmount = asFiniteNumber2(args.extraMarginAmount, "extraMarginAmount");
1903
+ if (args.row != null) body.row = asPositiveInteger3(args.row, "row");
1904
+ if (args.extraMarginAmount != null) body.extraMarginAmount = asFiniteNumber3(args.extraMarginAmount, "extraMarginAmount");
1719
1905
  if (args.isRecommend != null) body.isRecommend = asBoolean2(args.isRecommend, "isRecommend");
1720
1906
  if (args.isReinvest != null) body.isReinvest = asBoolean2(args.isReinvest, "isReinvest");
1721
1907
  if (args.investCoin != null) body.investCoin = String(args.investCoin);
1722
1908
  if (args.investmentFrom != null) {
1723
- const investmentFrom = asNonEmptyString2(args.investmentFrom, "investmentFrom");
1724
- assertEnum2(investmentFrom, "investmentFrom", ["USER", "LOCK_ACTIVITY"]);
1909
+ const investmentFrom = asNonEmptyString3(args.investmentFrom, "investmentFrom");
1910
+ assertEnum3(investmentFrom, "investmentFrom", ["USER", "LOCK_ACTIVITY"]);
1725
1911
  body.investmentFrom = investmentFrom;
1726
1912
  }
1727
1913
  if (args.condition != null) body.condition = asPositiveDecimalString2(args.condition, "condition");
1728
1914
  if (args.conditionDirection != null) {
1729
- const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
1730
- assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
1915
+ const conditionDirection = asNonEmptyString3(args.conditionDirection, "conditionDirection");
1916
+ assertEnum3(conditionDirection, "conditionDirection", ["1", "-1"]);
1731
1917
  body.conditionDirection = conditionDirection;
1732
1918
  }
1733
1919
  if (args.slippage != null) body.slippage = String(args.slippage);
@@ -1756,8 +1942,8 @@ function registerBotTools() {
1756
1942
  if (config.readOnly) {
1757
1943
  throw new Error("Server is running in --read-only mode; bot futures_grid reduce is disabled.");
1758
1944
  }
1759
- const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
1760
- const reduceNum = asPositiveInteger2(args.reduceNum, "reduceNum");
1945
+ const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
1946
+ const reduceNum = asPositiveInteger3(args.reduceNum, "reduceNum");
1761
1947
  const body = {
1762
1948
  buOrderId,
1763
1949
  reduceNum
@@ -1765,8 +1951,8 @@ function registerBotTools() {
1765
1951
  if (args.slippage != null) body.slippage = String(args.slippage);
1766
1952
  if (args.condition != null) body.condition = String(args.condition);
1767
1953
  if (args.conditionDirection != null) {
1768
- const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
1769
- assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
1954
+ const conditionDirection = asNonEmptyString3(args.conditionDirection, "conditionDirection");
1955
+ assertEnum3(conditionDirection, "conditionDirection", ["1", "-1"]);
1770
1956
  body.conditionDirection = conditionDirection;
1771
1957
  }
1772
1958
  return (await client.signedPost("/api/v1/bot/orders/futuresGrid/reduce", body)).data;
@@ -1830,18 +2016,188 @@ function registerBotTools() {
1830
2016
  if (config.readOnly) {
1831
2017
  throw new Error("Server is running in --read-only mode; bot futures_grid cancel is disabled.");
1832
2018
  }
1833
- const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
2019
+ const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
1834
2020
  const body = { buOrderId };
1835
2021
  if (args.closeNote != null) body.closeNote = String(args.closeNote);
1836
2022
  if (args.closeSellModel != null) {
1837
- const closeSellModel = asNonEmptyString2(args.closeSellModel, "closeSellModel");
1838
- assertEnum2(closeSellModel, "closeSellModel", ["TO_QUOTE", "TO_USDT"]);
2023
+ const closeSellModel = asNonEmptyString3(args.closeSellModel, "closeSellModel");
2024
+ assertEnum3(closeSellModel, "closeSellModel", ["TO_QUOTE", "TO_USDT"]);
1839
2025
  body.closeSellModel = closeSellModel;
1840
2026
  }
1841
2027
  if (args.immediate != null) body.immediate = asBoolean2(args.immediate, "immediate");
1842
2028
  if (args.closeSlippage != null) body.closeSlippage = String(args.closeSlippage);
1843
2029
  return (await client.signedPost("/api/v1/bot/orders/futuresGrid/cancel", body)).data;
1844
2030
  }
2031
+ },
2032
+ {
2033
+ name: "pionex_bot_spot_grid_get_order",
2034
+ module: "bot",
2035
+ isWrite: false,
2036
+ description: "Get one spot grid bot order by buOrderId.",
2037
+ inputSchema: {
2038
+ type: "object",
2039
+ additionalProperties: false,
2040
+ properties: {
2041
+ buOrderId: { type: "string", description: "Spot grid bot order id." }
2042
+ },
2043
+ required: ["buOrderId"]
2044
+ },
2045
+ async handler(args, { client }) {
2046
+ const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
2047
+ const q = { buOrderId };
2048
+ return (await client.signedGet("/api/v1/bot/orders/spotGrid/order", q)).data;
2049
+ }
2050
+ },
2051
+ {
2052
+ name: "pionex_bot_spot_grid_get_ai_strategy",
2053
+ module: "bot",
2054
+ isWrite: false,
2055
+ description: "Retrieve AI-recommended spot grid strategy parameters for a trading pair.",
2056
+ inputSchema: {
2057
+ type: "object",
2058
+ additionalProperties: false,
2059
+ properties: {
2060
+ base: { type: "string", description: "Base currency (e.g. BTC)" },
2061
+ quote: { type: "string", description: "Quote currency (e.g. USDT)" }
2062
+ },
2063
+ required: ["base", "quote"]
2064
+ },
2065
+ async handler(args, { client }) {
2066
+ const base = asNonEmptyString3(args.base, "base");
2067
+ const quote = asNonEmptyString3(args.quote, "quote");
2068
+ return (await client.signedGet("/api/v1/bot/orders/spotGrid/aiStrategy", { base, quote })).data;
2069
+ }
2070
+ },
2071
+ {
2072
+ name: "pionex_bot_spot_grid_create",
2073
+ module: "bot",
2074
+ isWrite: true,
2075
+ description: "Create a spot grid bot order (openapi_bot.yaml CreateSpotGridRequest / CreateSpotGridOrderData). Required: base, quote, buOrderData. Optional: note. buOrderData required: top, bottom, row, gridType, quoteTotalInvestment; unknown keys rejected.",
2076
+ inputSchema: createSpotGridCreateToolInputSchema,
2077
+ async handler(args, { client, config }) {
2078
+ if (config.readOnly) {
2079
+ throw new Error("Server is running in --read-only mode; bot spot_grid create is disabled.");
2080
+ }
2081
+ const base = asNonEmptyString3(args.base, "base");
2082
+ const quote = asNonEmptyString3(args.quote, "quote");
2083
+ const buOrderDataOut = parseAndValidateCreateSpotGridBuOrderData(asObject(args.buOrderData, "buOrderData"));
2084
+ const body = { base, quote, buOrderData: buOrderDataOut };
2085
+ if (args.note != null) body.note = String(args.note);
2086
+ if (args.__dryRun === true) {
2087
+ return {
2088
+ dryRun: true,
2089
+ note: "No order was sent. Body matches openapi_bot.yaml CreateSpotGridRequest.",
2090
+ resolvedBody: body
2091
+ };
2092
+ }
2093
+ return (await client.signedPost("/api/v1/bot/orders/spotGrid/create", body)).data;
2094
+ }
2095
+ },
2096
+ {
2097
+ name: "pionex_bot_spot_grid_adjust_params",
2098
+ module: "bot",
2099
+ isWrite: true,
2100
+ description: "Adjust spot grid bot range or investment parameters.",
2101
+ inputSchema: {
2102
+ type: "object",
2103
+ additionalProperties: false,
2104
+ properties: {
2105
+ buOrderId: { type: "string" },
2106
+ top: { type: "string", description: "New upper price" },
2107
+ bottom: { type: "string", description: "New lower price" },
2108
+ row: { type: "number", description: "New number of grid levels" },
2109
+ quoteInvest: { type: "string", description: "Additional quote investment amount" }
2110
+ },
2111
+ required: ["buOrderId"]
2112
+ },
2113
+ async handler(args, { client, config }) {
2114
+ if (config.readOnly) {
2115
+ throw new Error("Server is running in --read-only mode; bot spot_grid adjust_params is disabled.");
2116
+ }
2117
+ const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
2118
+ const body = { buOrderId };
2119
+ if (args.top != null) body.top = asPositiveDecimalString2(args.top, "top");
2120
+ if (args.bottom != null) body.bottom = asPositiveDecimalString2(args.bottom, "bottom");
2121
+ if (args.row != null) body.row = asPositiveInteger3(args.row, "row");
2122
+ if (args.quoteInvest != null) body.quoteInvest = asPositiveDecimalString2(args.quoteInvest, "quoteInvest");
2123
+ return (await client.signedPost("/api/v1/bot/orders/spotGrid/adjustParams", body)).data;
2124
+ }
2125
+ },
2126
+ {
2127
+ name: "pionex_bot_spot_grid_invest_in",
2128
+ module: "bot",
2129
+ isWrite: true,
2130
+ description: "Add additional quote investment to a running spot grid bot.",
2131
+ inputSchema: {
2132
+ type: "object",
2133
+ additionalProperties: false,
2134
+ properties: {
2135
+ buOrderId: { type: "string" },
2136
+ quoteInvest: { type: "string", description: "Quote amount to invest" }
2137
+ },
2138
+ required: ["buOrderId", "quoteInvest"]
2139
+ },
2140
+ async handler(args, { client, config }) {
2141
+ if (config.readOnly) {
2142
+ throw new Error("Server is running in --read-only mode; bot spot_grid invest_in is disabled.");
2143
+ }
2144
+ const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
2145
+ const quoteInvest = asPositiveDecimalString2(args.quoteInvest, "quoteInvest");
2146
+ return (await client.signedPost("/api/v1/bot/orders/spotGrid/investIn", { buOrderId, quoteInvest })).data;
2147
+ }
2148
+ },
2149
+ {
2150
+ name: "pionex_bot_spot_grid_cancel",
2151
+ module: "bot",
2152
+ isWrite: true,
2153
+ description: "Cancel and close a spot grid bot order.",
2154
+ inputSchema: {
2155
+ type: "object",
2156
+ additionalProperties: false,
2157
+ properties: {
2158
+ buOrderId: { type: "string" },
2159
+ closeSellModel: { type: "string", enum: ["NOT_SELL", "TO_QUOTE", "TO_USDT"] },
2160
+ slippage: { type: "string" }
2161
+ },
2162
+ required: ["buOrderId"]
2163
+ },
2164
+ async handler(args, { client, config }) {
2165
+ if (config.readOnly) {
2166
+ throw new Error("Server is running in --read-only mode; bot spot_grid cancel is disabled.");
2167
+ }
2168
+ const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
2169
+ const body = { buOrderId };
2170
+ if (args.closeSellModel != null) {
2171
+ const closeSellModel = asNonEmptyString3(args.closeSellModel, "closeSellModel");
2172
+ assertEnum3(closeSellModel, "closeSellModel", ["NOT_SELL", "TO_QUOTE", "TO_USDT"]);
2173
+ body.closeSellModel = closeSellModel;
2174
+ }
2175
+ if (args.slippage != null) body.slippage = String(args.slippage);
2176
+ return (await client.signedPost("/api/v1/bot/orders/spotGrid/cancel", body)).data;
2177
+ }
2178
+ },
2179
+ {
2180
+ name: "pionex_bot_spot_grid_profit",
2181
+ module: "bot",
2182
+ isWrite: true,
2183
+ description: "Extract accumulated grid profit from a spot grid bot order.",
2184
+ inputSchema: {
2185
+ type: "object",
2186
+ additionalProperties: false,
2187
+ properties: {
2188
+ buOrderId: { type: "string" },
2189
+ amount: { type: "string", description: "Amount of profit to extract" }
2190
+ },
2191
+ required: ["buOrderId", "amount"]
2192
+ },
2193
+ async handler(args, { client, config }) {
2194
+ if (config.readOnly) {
2195
+ throw new Error("Server is running in --read-only mode; bot spot_grid profit is disabled.");
2196
+ }
2197
+ const buOrderId = asNonEmptyString3(args.buOrderId, "buOrderId");
2198
+ const amount = asPositiveDecimalString2(args.amount, "amount");
2199
+ return (await client.signedPost("/api/v1/bot/orders/spotGrid/profit", { buOrderId, amount })).data;
2200
+ }
1845
2201
  }
1846
2202
  ];
1847
2203
  }