@pionex/pionex-ai-kit 0.2.27 → 0.2.28
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 +325 -222
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1480,6 +1480,44 @@ function registerOrdersTools() {
|
|
|
1480
1480
|
}
|
|
1481
1481
|
];
|
|
1482
1482
|
}
|
|
1483
|
+
var CREATE_FUTURES_GRID_ORDER_DATA_KEYS = [
|
|
1484
|
+
"top",
|
|
1485
|
+
"bottom",
|
|
1486
|
+
"row",
|
|
1487
|
+
"grid_type",
|
|
1488
|
+
"trend",
|
|
1489
|
+
"leverage",
|
|
1490
|
+
"extraMargin",
|
|
1491
|
+
"quoteInvestment",
|
|
1492
|
+
"condition",
|
|
1493
|
+
"conditionDirection",
|
|
1494
|
+
"lossStopType",
|
|
1495
|
+
"lossStop",
|
|
1496
|
+
"lossStopDelay",
|
|
1497
|
+
"profitStopType",
|
|
1498
|
+
"profitStop",
|
|
1499
|
+
"profitStopDelay",
|
|
1500
|
+
"lossStopHigh",
|
|
1501
|
+
"shareRatio",
|
|
1502
|
+
"investCoin",
|
|
1503
|
+
"investmentFrom",
|
|
1504
|
+
"uiInvestCoin",
|
|
1505
|
+
"lossStopLimitPrice",
|
|
1506
|
+
"lossStopLimitHighPrice",
|
|
1507
|
+
"profitStopLimitPrice",
|
|
1508
|
+
"slippage",
|
|
1509
|
+
"bonusId",
|
|
1510
|
+
"uiExtraData",
|
|
1511
|
+
"movingIndicatorType",
|
|
1512
|
+
"movingIndicatorInterval",
|
|
1513
|
+
"movingIndicatorParam",
|
|
1514
|
+
"movingTrailingUpParam",
|
|
1515
|
+
"cateType",
|
|
1516
|
+
"movingTop",
|
|
1517
|
+
"movingBottom",
|
|
1518
|
+
"enableFollowClosed"
|
|
1519
|
+
];
|
|
1520
|
+
var ORDER_DATA_KEY_SET = new Set(CREATE_FUTURES_GRID_ORDER_DATA_KEYS);
|
|
1483
1521
|
function asNonEmptyString(value, field) {
|
|
1484
1522
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1485
1523
|
throw new Error(`Invalid "${field}": expected non-empty string.`);
|
|
@@ -1515,12 +1553,6 @@ function assertEnum(value, field, allowed) {
|
|
|
1515
1553
|
throw new Error(`Invalid "${field}": expected one of ${allowed.join(", ")}.`);
|
|
1516
1554
|
}
|
|
1517
1555
|
}
|
|
1518
|
-
function asObject(value, field) {
|
|
1519
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1520
|
-
throw new Error(`Invalid "${field}": expected JSON object.`);
|
|
1521
|
-
}
|
|
1522
|
-
return value;
|
|
1523
|
-
}
|
|
1524
1556
|
function asPositiveDecimalString(value, field) {
|
|
1525
1557
|
const s = asNonEmptyString(value, field);
|
|
1526
1558
|
if (!/^\d+(\.\d+)?$/.test(s)) {
|
|
@@ -1532,6 +1564,12 @@ function asPositiveDecimalString(value, field) {
|
|
|
1532
1564
|
}
|
|
1533
1565
|
return s;
|
|
1534
1566
|
}
|
|
1567
|
+
function asPositiveDecimalStringLoose(value, field) {
|
|
1568
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
1569
|
+
return String(value);
|
|
1570
|
+
}
|
|
1571
|
+
return asPositiveDecimalString(value, field);
|
|
1572
|
+
}
|
|
1535
1573
|
function asNonNegativeDecimalString(value, field) {
|
|
1536
1574
|
const s = asNonEmptyString(value, field);
|
|
1537
1575
|
if (!/^\d+(\.\d+)?$/.test(s)) {
|
|
@@ -1543,82 +1581,235 @@ function asNonNegativeDecimalString(value, field) {
|
|
|
1543
1581
|
}
|
|
1544
1582
|
return s;
|
|
1545
1583
|
}
|
|
1546
|
-
function
|
|
1547
|
-
|
|
1584
|
+
function asOptionalString(value, field) {
|
|
1585
|
+
if (typeof value !== "string") {
|
|
1586
|
+
throw new Error(`Invalid "${field}": expected string.`);
|
|
1587
|
+
}
|
|
1588
|
+
return value;
|
|
1548
1589
|
}
|
|
1549
|
-
function
|
|
1550
|
-
const
|
|
1551
|
-
|
|
1590
|
+
function asOptionalNonNegativeNumber(value, field) {
|
|
1591
|
+
const n = asFiniteNumber(value, field);
|
|
1592
|
+
if (n < 0) throw new Error(`Invalid "${field}": expected number >= 0.`);
|
|
1593
|
+
return n;
|
|
1552
1594
|
}
|
|
1553
|
-
function
|
|
1554
|
-
|
|
1555
|
-
|
|
1595
|
+
function parseAndValidateCreateFuturesGridBuOrderData(raw) {
|
|
1596
|
+
const data = { ...raw };
|
|
1597
|
+
delete data.openPrice;
|
|
1598
|
+
delete data.keyId;
|
|
1599
|
+
delete data.key_id;
|
|
1600
|
+
for (const k of Object.keys(data)) {
|
|
1601
|
+
if (!ORDER_DATA_KEY_SET.has(k)) {
|
|
1602
|
+
throw new Error(`Unknown buOrderData property "${k}". Allowed keys: ${CREATE_FUTURES_GRID_ORDER_DATA_KEYS.join(", ")}.`);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
const top = asPositiveDecimalStringLoose(data.top, "buOrderData.top");
|
|
1606
|
+
const bottom = asPositiveDecimalStringLoose(data.bottom, "buOrderData.bottom");
|
|
1607
|
+
if (Number(top) <= Number(bottom)) {
|
|
1608
|
+
throw new Error('Invalid "buOrderData.top": expected top > bottom.');
|
|
1609
|
+
}
|
|
1610
|
+
const row = asPositiveInteger(data.row, "buOrderData.row");
|
|
1611
|
+
const gridType = asNonEmptyString(data.grid_type, "buOrderData.grid_type");
|
|
1612
|
+
assertEnum(gridType, "buOrderData.grid_type", ["arithmetic", "geometric"]);
|
|
1613
|
+
const trend = asNonEmptyString(data.trend, "buOrderData.trend");
|
|
1614
|
+
assertEnum(trend, "buOrderData.trend", ["long", "short", "no_trend"]);
|
|
1615
|
+
const leverage2 = asPositiveNumber(data.leverage, "buOrderData.leverage");
|
|
1616
|
+
const quoteInvestment = asPositiveDecimalStringLoose(data.quoteInvestment, "buOrderData.quoteInvestment");
|
|
1617
|
+
const out = {
|
|
1618
|
+
top,
|
|
1619
|
+
bottom,
|
|
1620
|
+
row,
|
|
1621
|
+
grid_type: gridType,
|
|
1622
|
+
trend,
|
|
1623
|
+
leverage: leverage2,
|
|
1624
|
+
quoteInvestment
|
|
1625
|
+
};
|
|
1626
|
+
if (data.extraMargin != null) {
|
|
1627
|
+
out.extraMargin = asNonNegativeDecimalString(data.extraMargin, "buOrderData.extraMargin");
|
|
1628
|
+
}
|
|
1629
|
+
if (data.condition != null) out.condition = asOptionalString(data.condition, "buOrderData.condition");
|
|
1630
|
+
if (data.conditionDirection != null) {
|
|
1631
|
+
const v = asNonEmptyString(data.conditionDirection, "buOrderData.conditionDirection");
|
|
1632
|
+
assertEnum(v, "buOrderData.conditionDirection", ["-1", "1"]);
|
|
1633
|
+
out.conditionDirection = v;
|
|
1634
|
+
}
|
|
1635
|
+
if (data.lossStopType != null) {
|
|
1636
|
+
const v = asNonEmptyString(data.lossStopType, "buOrderData.lossStopType");
|
|
1637
|
+
assertEnum(v, "buOrderData.lossStopType", ["price", "profit_amount", "profit_ratio", "price_limit"]);
|
|
1638
|
+
out.lossStopType = v;
|
|
1639
|
+
}
|
|
1640
|
+
if (data.lossStop != null) out.lossStop = asOptionalString(data.lossStop, "buOrderData.lossStop");
|
|
1641
|
+
if (data.lossStopDelay != null) out.lossStopDelay = asOptionalNonNegativeNumber(data.lossStopDelay, "buOrderData.lossStopDelay");
|
|
1642
|
+
if (data.profitStopType != null) {
|
|
1643
|
+
const v = asNonEmptyString(data.profitStopType, "buOrderData.profitStopType");
|
|
1644
|
+
assertEnum(v, "buOrderData.profitStopType", ["price", "profit_amount", "profit_ratio", "price_limit"]);
|
|
1645
|
+
out.profitStopType = v;
|
|
1646
|
+
}
|
|
1647
|
+
if (data.profitStop != null) out.profitStop = asOptionalString(data.profitStop, "buOrderData.profitStop");
|
|
1648
|
+
if (data.profitStopDelay != null) out.profitStopDelay = asOptionalNonNegativeNumber(data.profitStopDelay, "buOrderData.profitStopDelay");
|
|
1649
|
+
if (data.lossStopHigh != null) out.lossStopHigh = asOptionalString(data.lossStopHigh, "buOrderData.lossStopHigh");
|
|
1650
|
+
if (data.shareRatio != null) out.shareRatio = asOptionalString(data.shareRatio, "buOrderData.shareRatio");
|
|
1651
|
+
if (data.investCoin != null) out.investCoin = asOptionalString(data.investCoin, "buOrderData.investCoin");
|
|
1652
|
+
if (data.investmentFrom != null) {
|
|
1653
|
+
const v = asNonEmptyString(data.investmentFrom, "buOrderData.investmentFrom");
|
|
1654
|
+
assertEnum(v, "buOrderData.investmentFrom", ["USER", "LOCK_ACTIVITY", "FUTURE_GRID_BONUS"]);
|
|
1655
|
+
out.investmentFrom = v;
|
|
1656
|
+
}
|
|
1657
|
+
if (data.uiInvestCoin != null) out.uiInvestCoin = asOptionalString(data.uiInvestCoin, "buOrderData.uiInvestCoin");
|
|
1658
|
+
if (data.lossStopLimitPrice != null) out.lossStopLimitPrice = asOptionalString(data.lossStopLimitPrice, "buOrderData.lossStopLimitPrice");
|
|
1659
|
+
if (data.lossStopLimitHighPrice != null) out.lossStopLimitHighPrice = asOptionalString(data.lossStopLimitHighPrice, "buOrderData.lossStopLimitHighPrice");
|
|
1660
|
+
if (data.profitStopLimitPrice != null) out.profitStopLimitPrice = asOptionalString(data.profitStopLimitPrice, "buOrderData.profitStopLimitPrice");
|
|
1661
|
+
if (data.slippage != null) out.slippage = asOptionalString(data.slippage, "buOrderData.slippage");
|
|
1662
|
+
if (data.bonusId != null) out.bonusId = asOptionalString(data.bonusId, "buOrderData.bonusId");
|
|
1663
|
+
if (data.uiExtraData != null) out.uiExtraData = asOptionalString(data.uiExtraData, "buOrderData.uiExtraData");
|
|
1664
|
+
if (data.movingIndicatorType != null) out.movingIndicatorType = asOptionalString(data.movingIndicatorType, "buOrderData.movingIndicatorType");
|
|
1665
|
+
if (data.movingIndicatorInterval != null) out.movingIndicatorInterval = asOptionalString(data.movingIndicatorInterval, "buOrderData.movingIndicatorInterval");
|
|
1666
|
+
if (data.movingIndicatorParam != null) out.movingIndicatorParam = asOptionalString(data.movingIndicatorParam, "buOrderData.movingIndicatorParam");
|
|
1667
|
+
if (data.movingTrailingUpParam != null) out.movingTrailingUpParam = asOptionalString(data.movingTrailingUpParam, "buOrderData.movingTrailingUpParam");
|
|
1668
|
+
if (data.cateType != null) {
|
|
1669
|
+
const v = asNonEmptyString(data.cateType, "buOrderData.cateType");
|
|
1670
|
+
assertEnum(v, "buOrderData.cateType", ["FULLY_HEDGING", "LOAN_GRID", "LEVERAGE_GRID", "FUTURE_GRID_COIN_MARGINED"]);
|
|
1671
|
+
out.cateType = v;
|
|
1672
|
+
}
|
|
1673
|
+
if (data.movingTop != null) out.movingTop = asOptionalString(data.movingTop, "buOrderData.movingTop");
|
|
1674
|
+
if (data.movingBottom != null) out.movingBottom = asOptionalString(data.movingBottom, "buOrderData.movingBottom");
|
|
1675
|
+
if (data.enableFollowClosed != null) out.enableFollowClosed = asBoolean(data.enableFollowClosed, "buOrderData.enableFollowClosed");
|
|
1556
1676
|
return out;
|
|
1557
1677
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1678
|
+
var createFuturesGridOrderDataJsonSchema = {
|
|
1679
|
+
type: "object",
|
|
1680
|
+
additionalProperties: false,
|
|
1681
|
+
description: "CreateFuturesGridOrderData (openapi_bot.yaml). Required: top, bottom, row, grid_type, trend, leverage, quoteInvestment.",
|
|
1682
|
+
required: ["top", "bottom", "row", "grid_type", "trend", "leverage", "quoteInvestment"],
|
|
1683
|
+
properties: {
|
|
1684
|
+
top: { type: "string", description: "Grid upper price" },
|
|
1685
|
+
bottom: { type: "string", description: "Grid lower price" },
|
|
1686
|
+
row: { type: "number", description: "Number of grid levels" },
|
|
1687
|
+
grid_type: {
|
|
1688
|
+
type: "string",
|
|
1689
|
+
enum: ["arithmetic", "geometric"],
|
|
1690
|
+
description: "Grid spacing: arithmetic (equal difference) or geometric (equal ratio)"
|
|
1691
|
+
},
|
|
1692
|
+
trend: {
|
|
1693
|
+
type: "string",
|
|
1694
|
+
enum: ["long", "short", "no_trend"],
|
|
1695
|
+
description: "Grid direction"
|
|
1696
|
+
},
|
|
1697
|
+
leverage: { type: "number", description: "Leverage multiplier" },
|
|
1698
|
+
extraMargin: { type: "string", description: "Extra margin amount (optional)" },
|
|
1699
|
+
quoteInvestment: { type: "string", description: "Investment amount" },
|
|
1700
|
+
condition: { type: "string", description: "Trigger price (conditional orders)" },
|
|
1701
|
+
conditionDirection: { type: "string", enum: ["-1", "1"], description: "Trigger direction" },
|
|
1702
|
+
lossStopType: {
|
|
1703
|
+
type: "string",
|
|
1704
|
+
enum: ["price", "profit_amount", "profit_ratio", "price_limit"],
|
|
1705
|
+
description: "Stop loss type"
|
|
1706
|
+
},
|
|
1707
|
+
lossStop: { type: "string", description: "Stop loss value" },
|
|
1708
|
+
lossStopDelay: { type: "number", description: "Stop loss delay (seconds)" },
|
|
1709
|
+
profitStopType: {
|
|
1710
|
+
type: "string",
|
|
1711
|
+
enum: ["price", "profit_amount", "profit_ratio", "price_limit"],
|
|
1712
|
+
description: "Take profit type"
|
|
1713
|
+
},
|
|
1714
|
+
profitStop: { type: "string", description: "Take profit value" },
|
|
1715
|
+
profitStopDelay: { type: "number", description: "Take profit delay (seconds)" },
|
|
1716
|
+
lossStopHigh: { type: "string", description: "Upper stop loss price for neutral grid" },
|
|
1717
|
+
shareRatio: { type: "string", description: "Profit sharing ratio" },
|
|
1718
|
+
investCoin: { type: "string", description: "Investment currency" },
|
|
1719
|
+
investmentFrom: {
|
|
1720
|
+
type: "string",
|
|
1721
|
+
enum: ["USER", "LOCK_ACTIVITY", "FUTURE_GRID_BONUS"],
|
|
1722
|
+
description: "Funding source"
|
|
1723
|
+
},
|
|
1724
|
+
uiInvestCoin: { type: "string", description: "Frontend-recorded investment currency" },
|
|
1725
|
+
lossStopLimitPrice: { type: "string", description: "Limit SL price (lossStopType=price_limit)" },
|
|
1726
|
+
lossStopLimitHighPrice: { type: "string", description: "Upper limit SL for neutral grid" },
|
|
1727
|
+
profitStopLimitPrice: { type: "string", description: "Limit TP price (profitStopType=price_limit)" },
|
|
1728
|
+
slippage: { type: "string", description: "Open slippage e.g. 0.01 = 1%" },
|
|
1729
|
+
bonusId: { type: "string", description: "Bonus UUID" },
|
|
1730
|
+
uiExtraData: { type: "string", description: "Frontend extra (coin-margined)" },
|
|
1731
|
+
movingIndicatorType: { type: "string", description: "e.g. sma" },
|
|
1732
|
+
movingIndicatorInterval: { type: "string", description: "e.g. 1m, 15m" },
|
|
1733
|
+
movingIndicatorParam: { type: "string", description: "JSON params e.g. length" },
|
|
1734
|
+
movingTrailingUpParam: { type: "string", description: "SMA trailing up ratio" },
|
|
1735
|
+
cateType: {
|
|
1736
|
+
type: "string",
|
|
1737
|
+
enum: ["FULLY_HEDGING", "LOAN_GRID", "LEVERAGE_GRID", "FUTURE_GRID_COIN_MARGINED"],
|
|
1738
|
+
description: "Category type"
|
|
1739
|
+
},
|
|
1740
|
+
movingTop: { type: "string", description: "Moving grid upper limit" },
|
|
1741
|
+
movingBottom: { type: "string", description: "Moving grid lower limit" },
|
|
1742
|
+
enableFollowClosed: { type: "boolean", description: "Follow close" }
|
|
1585
1743
|
}
|
|
1586
|
-
|
|
1587
|
-
|
|
1744
|
+
};
|
|
1745
|
+
var createFuturesGridCreateToolInputSchema = {
|
|
1746
|
+
type: "object",
|
|
1747
|
+
additionalProperties: false,
|
|
1748
|
+
required: ["base", "quote", "buOrderData"],
|
|
1749
|
+
properties: {
|
|
1750
|
+
base: { type: "string", description: "Base currency (e.g. BTC); *.PERP normalized in handler" },
|
|
1751
|
+
quote: { type: "string", description: "Quote currency (e.g. USDT)" },
|
|
1752
|
+
copyFrom: { type: "string", description: "Optional. Copy source order ID" },
|
|
1753
|
+
copyType: { type: "string", description: "Optional. Copy type" },
|
|
1754
|
+
copyBotOrderId: { type: "string", description: "Optional. Copy bot order ID" },
|
|
1755
|
+
buOrderData: createFuturesGridOrderDataJsonSchema,
|
|
1756
|
+
__dryRun: { type: "boolean", description: "Internal: when true, return resolved body without POST" }
|
|
1757
|
+
}
|
|
1758
|
+
};
|
|
1759
|
+
function asNonEmptyString2(value, field) {
|
|
1760
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1761
|
+
throw new Error(`Invalid "${field}": expected non-empty string.`);
|
|
1588
1762
|
}
|
|
1589
|
-
return
|
|
1763
|
+
return value.trim();
|
|
1590
1764
|
}
|
|
1591
|
-
function
|
|
1592
|
-
|
|
1765
|
+
function asFiniteNumber2(value, field) {
|
|
1766
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
1767
|
+
throw new Error(`Invalid "${field}": expected finite number.`);
|
|
1768
|
+
}
|
|
1769
|
+
return value;
|
|
1593
1770
|
}
|
|
1594
|
-
function
|
|
1595
|
-
const
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1771
|
+
function asPositiveNumber2(value, field) {
|
|
1772
|
+
const n = asFiniteNumber2(value, field);
|
|
1773
|
+
if (n <= 0) throw new Error(`Invalid "${field}": expected number > 0.`);
|
|
1774
|
+
return n;
|
|
1775
|
+
}
|
|
1776
|
+
function asPositiveInteger2(value, field) {
|
|
1777
|
+
const n = asPositiveNumber2(value, field);
|
|
1778
|
+
if (!Number.isInteger(n)) {
|
|
1779
|
+
throw new Error(`Invalid "${field}": expected positive integer.`);
|
|
1780
|
+
}
|
|
1781
|
+
return n;
|
|
1782
|
+
}
|
|
1783
|
+
function asBoolean2(value, field) {
|
|
1784
|
+
if (typeof value !== "boolean") {
|
|
1785
|
+
throw new Error(`Invalid "${field}": expected boolean.`);
|
|
1786
|
+
}
|
|
1787
|
+
return value;
|
|
1788
|
+
}
|
|
1789
|
+
function assertEnum2(value, field, allowed) {
|
|
1790
|
+
if (!allowed.includes(value)) {
|
|
1791
|
+
throw new Error(`Invalid "${field}": expected one of ${allowed.join(", ")}.`);
|
|
1612
1792
|
}
|
|
1613
|
-
return void 0;
|
|
1614
1793
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1794
|
+
function asObject(value, field) {
|
|
1795
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1796
|
+
throw new Error(`Invalid "${field}": expected JSON object.`);
|
|
1797
|
+
}
|
|
1798
|
+
return value;
|
|
1799
|
+
}
|
|
1800
|
+
function asPositiveDecimalString2(value, field) {
|
|
1801
|
+
const s = asNonEmptyString2(value, field);
|
|
1802
|
+
if (!/^\d+(\.\d+)?$/.test(s)) {
|
|
1803
|
+
throw new Error(`Invalid "${field}": expected positive decimal string.`);
|
|
1804
|
+
}
|
|
1805
|
+
const n = Number(s);
|
|
1806
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
1807
|
+
throw new Error(`Invalid "${field}": expected positive decimal string.`);
|
|
1620
1808
|
}
|
|
1621
|
-
return
|
|
1809
|
+
return s;
|
|
1810
|
+
}
|
|
1811
|
+
function normalizePerpBase(base) {
|
|
1812
|
+
return base.endsWith(".PERP") ? base : `${base}.PERP`;
|
|
1622
1813
|
}
|
|
1623
1814
|
function registerBotTools() {
|
|
1624
1815
|
return [
|
|
@@ -1647,121 +1838,35 @@ function registerBotTools() {
|
|
|
1647
1838
|
name: "pionex_bot_create_futures_grid_order",
|
|
1648
1839
|
module: "bot",
|
|
1649
1840
|
isWrite: true,
|
|
1650
|
-
description: "Create a futures grid
|
|
1651
|
-
inputSchema:
|
|
1652
|
-
type: "object",
|
|
1653
|
-
additionalProperties: false,
|
|
1654
|
-
properties: {
|
|
1655
|
-
keyId: { type: "string" },
|
|
1656
|
-
exchange: { type: "string", description: "e.g. pionex.v2" },
|
|
1657
|
-
base: { type: "string", description: "e.g. BTC" },
|
|
1658
|
-
quote: { type: "string", description: "e.g. USDT" },
|
|
1659
|
-
copyFrom: { type: "string" },
|
|
1660
|
-
copyType: { type: "string" },
|
|
1661
|
-
groupId: { type: "string" },
|
|
1662
|
-
copyBotOrderId: { type: "string" },
|
|
1663
|
-
lang: { type: "string" },
|
|
1664
|
-
buOrderData: {
|
|
1665
|
-
type: "object",
|
|
1666
|
-
additionalProperties: true,
|
|
1667
|
-
description: "CreateFuturesGridOrderData payload from openapi_bot.yaml."
|
|
1668
|
-
}
|
|
1669
|
-
},
|
|
1670
|
-
required: ["base", "buOrderData"]
|
|
1671
|
-
},
|
|
1841
|
+
description: "Create a futures grid order (openapi_bot.yaml CreateFuturesGridRequest / CreateFuturesGridOrderData). https://github.com/pionex-official/pionex-open-api/blob/main/openapi_bot.yaml \u2014 Required: base, quote, buOrderData. Optional: copyFrom, copyType, copyBotOrderId. buOrderData required: top, bottom, row, grid_type, trend, leverage, quoteInvestment; openPrice/keyId stripped if present.",
|
|
1842
|
+
inputSchema: createFuturesGridCreateToolInputSchema,
|
|
1672
1843
|
async handler(args, { client, config }) {
|
|
1673
1844
|
if (config.readOnly) {
|
|
1674
1845
|
throw new Error("Server is running in --read-only mode; bot create is disabled.");
|
|
1675
1846
|
}
|
|
1676
|
-
const
|
|
1677
|
-
const exchange = asNonEmptyString(args.exchange ?? "pionex.v2", "exchange");
|
|
1678
|
-
if (args.exchange == null) defaultsApplied.exchange = exchange;
|
|
1679
|
-
const rawBase = asNonEmptyString(args.base, "base");
|
|
1847
|
+
const rawBase = asNonEmptyString2(args.base, "base");
|
|
1680
1848
|
const base = normalizePerpBase(rawBase);
|
|
1681
|
-
|
|
1682
|
-
const
|
|
1683
|
-
|
|
1684
|
-
const
|
|
1685
|
-
const symbol = `${base}_${quote}`;
|
|
1686
|
-
const needsTickerForTopBottom = buOrderData.top == null || buOrderData.bottom == null;
|
|
1687
|
-
const shouldTryTicker = needsTickerForTopBottom;
|
|
1688
|
-
let currentPrice;
|
|
1689
|
-
if (shouldTryTicker) {
|
|
1690
|
-
try {
|
|
1691
|
-
currentPrice = asPositiveDecimalString(await getCurrentSymbolPrice(client, symbol), "currentPrice");
|
|
1692
|
-
} catch {
|
|
1693
|
-
currentPrice = void 0;
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
|
-
if (needsTickerForTopBottom && currentPrice == null) {
|
|
1697
|
-
throw new Error(`Unable to infer current market price for ${symbol} from ticker response. Please provide buOrderData.top and buOrderData.bottom explicitly.`);
|
|
1698
|
-
}
|
|
1699
|
-
const autoPriceScale = currentPrice == null ? void 0 : Math.min(8, Math.max(2, decimalPlaces(currentPrice) + 2));
|
|
1700
|
-
const top = asPositiveDecimalString(
|
|
1701
|
-
buOrderData.top ?? multiplyDecimalByRatio(currentPrice, 105, 100, autoPriceScale),
|
|
1702
|
-
"buOrderData.top"
|
|
1703
|
-
);
|
|
1704
|
-
if (buOrderData.top == null) defaultsApplied.top = top;
|
|
1705
|
-
const bottom = asPositiveDecimalString(
|
|
1706
|
-
buOrderData.bottom ?? multiplyDecimalByRatio(currentPrice, 95, 100, autoPriceScale),
|
|
1707
|
-
"buOrderData.bottom"
|
|
1708
|
-
);
|
|
1709
|
-
if (buOrderData.bottom == null) defaultsApplied.bottom = bottom;
|
|
1710
|
-
if (Number(top) <= Number(bottom)) {
|
|
1711
|
-
throw new Error('Invalid "buOrderData.top": expected top > bottom.');
|
|
1712
|
-
}
|
|
1713
|
-
const row = asPositiveInteger(buOrderData.row ?? 10, "buOrderData.row");
|
|
1714
|
-
if (buOrderData.row == null) defaultsApplied.row = row;
|
|
1715
|
-
const gridType = asNonEmptyString(buOrderData.grid_type ?? "arithmetic", "buOrderData.grid_type");
|
|
1716
|
-
assertEnum(gridType, "buOrderData.grid_type", ["arithmetic", "geometric"]);
|
|
1717
|
-
if (buOrderData.grid_type == null) defaultsApplied.grid_type = gridType;
|
|
1718
|
-
const openPrice = buOrderData.openPrice == null ? void 0 : asPositiveDecimalString(buOrderData.openPrice, "buOrderData.openPrice");
|
|
1719
|
-
const trend = asNonEmptyString(buOrderData.trend, "buOrderData.trend");
|
|
1720
|
-
assertEnum(trend, "buOrderData.trend", ["long", "short", "no_trend"]);
|
|
1721
|
-
const leverage = asPositiveNumber(buOrderData.leverage ?? 2, "buOrderData.leverage");
|
|
1722
|
-
if (buOrderData.leverage == null) defaultsApplied.leverage = leverage;
|
|
1723
|
-
const extraMargin = asNonNegativeDecimalString(buOrderData.extraMargin ?? "0", "buOrderData.extraMargin");
|
|
1724
|
-
if (buOrderData.extraMargin == null) defaultsApplied.extraMargin = extraMargin;
|
|
1725
|
-
const quoteInvestment = asPositiveDecimalString(buOrderData.quoteInvestment, "buOrderData.quoteInvestment");
|
|
1849
|
+
const quote = asNonEmptyString2(args.quote, "quote");
|
|
1850
|
+
const buOrderDataOut = parseAndValidateCreateFuturesGridBuOrderData(asObject(args.buOrderData, "buOrderData"));
|
|
1851
|
+
const row = buOrderDataOut.row;
|
|
1852
|
+
const gridType = buOrderDataOut.grid_type;
|
|
1726
1853
|
const body = {
|
|
1727
|
-
exchange,
|
|
1728
1854
|
base,
|
|
1729
1855
|
quote,
|
|
1730
|
-
buOrderData:
|
|
1731
|
-
...buOrderData,
|
|
1732
|
-
top,
|
|
1733
|
-
bottom,
|
|
1734
|
-
row,
|
|
1735
|
-
grid_type: gridType,
|
|
1736
|
-
trend,
|
|
1737
|
-
leverage,
|
|
1738
|
-
extraMargin,
|
|
1739
|
-
quoteInvestment
|
|
1740
|
-
}
|
|
1856
|
+
buOrderData: buOrderDataOut
|
|
1741
1857
|
};
|
|
1742
|
-
if (openPrice != null) {
|
|
1743
|
-
body.buOrderData.openPrice = openPrice;
|
|
1744
|
-
}
|
|
1745
|
-
if (args.keyId != null) body.keyId = asNonEmptyString(args.keyId, "keyId");
|
|
1746
1858
|
if (args.copyFrom != null) body.copyFrom = String(args.copyFrom);
|
|
1747
1859
|
if (args.copyType != null) body.copyType = String(args.copyType);
|
|
1748
|
-
if (args.groupId != null) body.groupId = String(args.groupId);
|
|
1749
1860
|
if (args.copyBotOrderId != null) body.copyBotOrderId = String(args.copyBotOrderId);
|
|
1750
|
-
if (args.lang != null) body.lang = String(args.lang);
|
|
1751
1861
|
if (args.__dryRun === true) {
|
|
1752
|
-
const rowSource = buOrderData.row == null ? "default" : "user";
|
|
1753
1862
|
return {
|
|
1754
1863
|
dryRun: true,
|
|
1755
|
-
note: "No order was sent.
|
|
1756
|
-
marketSymbol: symbol,
|
|
1757
|
-
marketPriceUsed: currentPrice,
|
|
1864
|
+
note: "No order was sent. Body matches openapi_bot.yaml CreateFuturesGridRequest (no keyId/openPrice/exchange; groupId/lang not in create schema).",
|
|
1758
1865
|
resolvedParams: {
|
|
1759
1866
|
row,
|
|
1760
|
-
rowSource,
|
|
1761
1867
|
grid_type: gridType,
|
|
1762
1868
|
leverage
|
|
1763
1869
|
},
|
|
1764
|
-
defaultsApplied,
|
|
1765
1870
|
resolvedBody: body
|
|
1766
1871
|
};
|
|
1767
1872
|
}
|
|
@@ -1801,26 +1906,26 @@ function registerBotTools() {
|
|
|
1801
1906
|
if (config.readOnly) {
|
|
1802
1907
|
throw new Error("Server is running in --read-only mode; bot adjust is disabled.");
|
|
1803
1908
|
}
|
|
1804
|
-
const buOrderId =
|
|
1805
|
-
const type =
|
|
1806
|
-
|
|
1807
|
-
const extraMargin =
|
|
1808
|
-
const openPrice =
|
|
1909
|
+
const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
|
|
1910
|
+
const type = asNonEmptyString2(args.type, "type");
|
|
1911
|
+
assertEnum2(type, "type", ["invest_in", "adjust_params", "invest_in_trigger"]);
|
|
1912
|
+
const extraMargin = asBoolean2(args.extraMargin, "extraMargin");
|
|
1913
|
+
const openPrice = asFiniteNumber2(args.openPrice, "openPrice");
|
|
1809
1914
|
if (type === "invest_in" && args.quoteInvestment != null) {
|
|
1810
|
-
|
|
1915
|
+
asPositiveNumber2(args.quoteInvestment, "quoteInvestment");
|
|
1811
1916
|
}
|
|
1812
1917
|
if (type === "adjust_params") {
|
|
1813
|
-
const bottom =
|
|
1814
|
-
const top =
|
|
1918
|
+
const bottom = asPositiveDecimalString2(args.bottom, "bottom");
|
|
1919
|
+
const top = asPositiveDecimalString2(args.top, "top");
|
|
1815
1920
|
if (Number(top) <= Number(bottom)) {
|
|
1816
1921
|
throw new Error('Invalid "top": expected top > bottom.');
|
|
1817
1922
|
}
|
|
1818
|
-
|
|
1923
|
+
asPositiveInteger2(args.row, "row");
|
|
1819
1924
|
}
|
|
1820
1925
|
if (type === "invest_in_trigger") {
|
|
1821
|
-
|
|
1822
|
-
const conditionDirection =
|
|
1823
|
-
|
|
1926
|
+
asPositiveDecimalString2(args.condition, "condition");
|
|
1927
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1928
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1824
1929
|
}
|
|
1825
1930
|
const body = {
|
|
1826
1931
|
buOrderId,
|
|
@@ -1828,23 +1933,23 @@ function registerBotTools() {
|
|
|
1828
1933
|
extraMargin,
|
|
1829
1934
|
openPrice
|
|
1830
1935
|
};
|
|
1831
|
-
if (args.quoteInvestment != null) body.quoteInvestment =
|
|
1832
|
-
if (args.bottom != null) body.bottom =
|
|
1833
|
-
if (args.top != null) body.top =
|
|
1834
|
-
if (args.row != null) body.row =
|
|
1835
|
-
if (args.extraMarginAmount != null) body.extraMarginAmount =
|
|
1836
|
-
if (args.isRecommend != null) body.isRecommend =
|
|
1837
|
-
if (args.isReinvest != null) body.isReinvest =
|
|
1936
|
+
if (args.quoteInvestment != null) body.quoteInvestment = asFiniteNumber2(args.quoteInvestment, "quoteInvestment");
|
|
1937
|
+
if (args.bottom != null) body.bottom = asPositiveDecimalString2(args.bottom, "bottom");
|
|
1938
|
+
if (args.top != null) body.top = asPositiveDecimalString2(args.top, "top");
|
|
1939
|
+
if (args.row != null) body.row = asPositiveInteger2(args.row, "row");
|
|
1940
|
+
if (args.extraMarginAmount != null) body.extraMarginAmount = asFiniteNumber2(args.extraMarginAmount, "extraMarginAmount");
|
|
1941
|
+
if (args.isRecommend != null) body.isRecommend = asBoolean2(args.isRecommend, "isRecommend");
|
|
1942
|
+
if (args.isReinvest != null) body.isReinvest = asBoolean2(args.isReinvest, "isReinvest");
|
|
1838
1943
|
if (args.investCoin != null) body.investCoin = String(args.investCoin);
|
|
1839
1944
|
if (args.investmentFrom != null) {
|
|
1840
|
-
const investmentFrom =
|
|
1841
|
-
|
|
1945
|
+
const investmentFrom = asNonEmptyString2(args.investmentFrom, "investmentFrom");
|
|
1946
|
+
assertEnum2(investmentFrom, "investmentFrom", ["USER", "LOCK_ACTIVITY"]);
|
|
1842
1947
|
body.investmentFrom = investmentFrom;
|
|
1843
1948
|
}
|
|
1844
|
-
if (args.condition != null) body.condition =
|
|
1949
|
+
if (args.condition != null) body.condition = asPositiveDecimalString2(args.condition, "condition");
|
|
1845
1950
|
if (args.conditionDirection != null) {
|
|
1846
|
-
const conditionDirection =
|
|
1847
|
-
|
|
1951
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1952
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1848
1953
|
body.conditionDirection = conditionDirection;
|
|
1849
1954
|
}
|
|
1850
1955
|
if (args.slippage != null) body.slippage = String(args.slippage);
|
|
@@ -1874,9 +1979,9 @@ function registerBotTools() {
|
|
|
1874
1979
|
if (config.readOnly) {
|
|
1875
1980
|
throw new Error("Server is running in --read-only mode; bot reduce is disabled.");
|
|
1876
1981
|
}
|
|
1877
|
-
const buOrderId =
|
|
1878
|
-
const openPrice =
|
|
1879
|
-
const reduceNum =
|
|
1982
|
+
const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
|
|
1983
|
+
const openPrice = asPositiveDecimalString2(args.openPrice, "openPrice");
|
|
1984
|
+
const reduceNum = asPositiveInteger2(args.reduceNum, "reduceNum");
|
|
1880
1985
|
const body = {
|
|
1881
1986
|
buOrderId,
|
|
1882
1987
|
openPrice,
|
|
@@ -1885,8 +1990,8 @@ function registerBotTools() {
|
|
|
1885
1990
|
if (args.slippage != null) body.slippage = String(args.slippage);
|
|
1886
1991
|
if (args.condition != null) body.condition = String(args.condition);
|
|
1887
1992
|
if (args.conditionDirection != null) {
|
|
1888
|
-
const conditionDirection =
|
|
1889
|
-
|
|
1993
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1994
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1890
1995
|
body.conditionDirection = conditionDirection;
|
|
1891
1996
|
}
|
|
1892
1997
|
return (await client.signedPost("/api/v1/bot/orders/futuresGrid/reduce", body)).data;
|
|
@@ -1913,15 +2018,15 @@ function registerBotTools() {
|
|
|
1913
2018
|
if (config.readOnly) {
|
|
1914
2019
|
throw new Error("Server is running in --read-only mode; bot cancel is disabled.");
|
|
1915
2020
|
}
|
|
1916
|
-
const buOrderId =
|
|
2021
|
+
const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
|
|
1917
2022
|
const body = { buOrderId };
|
|
1918
2023
|
if (args.closeNote != null) body.closeNote = String(args.closeNote);
|
|
1919
2024
|
if (args.closeSellModel != null) {
|
|
1920
|
-
const closeSellModel =
|
|
1921
|
-
|
|
2025
|
+
const closeSellModel = asNonEmptyString2(args.closeSellModel, "closeSellModel");
|
|
2026
|
+
assertEnum2(closeSellModel, "closeSellModel", ["TO_QUOTE", "TO_USDT"]);
|
|
1922
2027
|
body.closeSellModel = closeSellModel;
|
|
1923
2028
|
}
|
|
1924
|
-
if (args.immediate != null) body.immediate =
|
|
2029
|
+
if (args.immediate != null) body.immediate = asBoolean2(args.immediate, "immediate");
|
|
1925
2030
|
if (args.closeSlippage != null) body.closeSlippage = String(args.closeSlippage);
|
|
1926
2031
|
return (await client.signedPost("/api/v1/bot/orders/futuresGrid/cancel", body)).data;
|
|
1927
2032
|
}
|
|
@@ -2100,27 +2205,29 @@ Examples:
|
|
|
2100
2205
|
pionex orders new --symbol BTC_USDT --side BUY --type MARKET --amount 10
|
|
2101
2206
|
pionex orders cancel --symbol BTC_USDT --order-id 123
|
|
2102
2207
|
pionex bot get --bu-order-id <id>
|
|
2103
|
-
pionex bot create --base BTC --bu-order-data-json '{"top":"110000","bottom":"90000","row":100,"grid_type":"arithmetic","
|
|
2208
|
+
pionex bot create --base BTC --quote USDT --bu-order-data-json '{"top":"110000","bottom":"90000","row":100,"grid_type":"arithmetic","trend":"long","leverage":5,"quoteInvestment":"100"}'
|
|
2104
2209
|
|
|
2105
2210
|
Global flags:
|
|
2106
2211
|
--profile <name> Profile in ~/.pionex/config.toml
|
|
2107
2212
|
--modules <list> Comma-separated modules (market,account,orders or all)
|
|
2108
2213
|
--base-url <url> Override API base URL
|
|
2109
2214
|
--read-only Disable write operations (orders new/cancel)
|
|
2110
|
-
--dry-run Print
|
|
2215
|
+
--dry-run Print resolved futures-grid create body without executing (bot create only)
|
|
2111
2216
|
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
quote
|
|
2115
|
-
|
|
2116
|
-
--
|
|
2117
|
-
buOrderData
|
|
2118
|
-
buOrderData
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2217
|
+
Futures grid create (pionex bot create) \u2014 strict OpenAPI (same validation as MCP):
|
|
2218
|
+
--base Required; normalized to <BASE>.PERP if suffix missing
|
|
2219
|
+
--quote Required (e.g. USDT)
|
|
2220
|
+
--bu-order-data-json Required JSON object \u2014 ONLY keys from CreateFuturesGridOrderData in openapi_bot.yaml
|
|
2221
|
+
Optional: --copy-from, --copy-type, --copy-bot-order-id
|
|
2222
|
+
buOrderData required: top, bottom, row, grid_type, trend, leverage, quoteInvestment
|
|
2223
|
+
buOrderData optional (names only): extraMargin, condition, conditionDirection, lossStopType, lossStop,
|
|
2224
|
+
lossStopDelay, profitStopType, profitStop, profitStopDelay, lossStopHigh, shareRatio, investCoin,
|
|
2225
|
+
investmentFrom, uiInvestCoin, lossStopLimitPrice, lossStopLimitHighPrice, profitStopLimitPrice,
|
|
2226
|
+
slippage, bonusId, uiExtraData, movingIndicatorType, movingIndicatorInterval, movingIndicatorParam,
|
|
2227
|
+
movingTrailingUpParam, cateType, movingTop, movingBottom, enableFollowClosed
|
|
2228
|
+
Unknown keys or openPrice/keyId \u2192 error (keyId/openPrice stripped before check if present)
|
|
2229
|
+
YAML: https://github.com/pionex-official/pionex-open-api/blob/main/openapi_bot.yaml
|
|
2230
|
+
Docs: https://www.pionex.com/docs/api-docs/bot-api/futures-grid
|
|
2124
2231
|
`);
|
|
2125
2232
|
}
|
|
2126
2233
|
function parseJsonFlag(raw, flagName) {
|
|
@@ -2295,21 +2402,17 @@ async function runPionexCommand(argv) {
|
|
|
2295
2402
|
return;
|
|
2296
2403
|
}
|
|
2297
2404
|
if (command === "create") {
|
|
2298
|
-
const keyId = typeof flags["key-id"] === "string" ? flags["key-id"] : typeof flags.keyId === "string" ? flags.keyId : void 0;
|
|
2299
|
-
const exchange = typeof flags.exchange === "string" ? flags.exchange : void 0;
|
|
2300
2405
|
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2301
2406
|
const quote = typeof flags.quote === "string" ? flags.quote : void 0;
|
|
2302
2407
|
const copyFrom = typeof flags["copy-from"] === "string" ? flags["copy-from"] : typeof flags.copyFrom === "string" ? flags.copyFrom : void 0;
|
|
2303
2408
|
const copyType = typeof flags["copy-type"] === "string" ? flags["copy-type"] : typeof flags.copyType === "string" ? flags.copyType : void 0;
|
|
2304
|
-
const groupId = typeof flags["group-id"] === "string" ? flags["group-id"] : typeof flags.groupId === "string" ? flags.groupId : void 0;
|
|
2305
2409
|
const copyBotOrderId = typeof flags["copy-bot-order-id"] === "string" ? flags["copy-bot-order-id"] : typeof flags.copyBotOrderId === "string" ? flags.copyBotOrderId : void 0;
|
|
2306
|
-
const
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
throw new Error("Missing required flags: --base --bu-order-data-json");
|
|
2410
|
+
const buOrderDataRaw = parseJsonFlag(flags["bu-order-data-json"] ?? flags.buOrderDataJson, "bu-order-data-json");
|
|
2411
|
+
if (!base || !quote) {
|
|
2412
|
+
throw new Error("Missing required flags: --base --quote --bu-order-data-json");
|
|
2310
2413
|
}
|
|
2311
|
-
const
|
|
2312
|
-
|
|
2414
|
+
const buOrderData = parseAndValidateCreateFuturesGridBuOrderData(buOrderDataRaw);
|
|
2415
|
+
const payload = { base, quote, copyFrom, copyType, copyBotOrderId, buOrderData };
|
|
2313
2416
|
if (dryRun) {
|
|
2314
2417
|
const out2 = await runTool("pionex_bot_create_futures_grid_order", { ...payload, __dryRun: true });
|
|
2315
2418
|
process.stdout.write(JSON.stringify(out2.data, null, 2) + "\n");
|