@pionex/pionex-ai-kit 0.2.26 → 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 +333 -190
- 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,50 +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
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
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;
|
|
1594
|
+
}
|
|
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");
|
|
1676
|
+
return out;
|
|
1677
|
+
}
|
|
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" }
|
|
1553
1743
|
}
|
|
1554
|
-
|
|
1555
|
-
|
|
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.`);
|
|
1556
1762
|
}
|
|
1557
|
-
return
|
|
1763
|
+
return value.trim();
|
|
1558
1764
|
}
|
|
1559
|
-
function
|
|
1560
|
-
|
|
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;
|
|
1561
1770
|
}
|
|
1562
|
-
function
|
|
1563
|
-
const
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
return candidateClose;
|
|
1572
|
-
}
|
|
1573
|
-
for (const v of Object.values(obj)) {
|
|
1574
|
-
if (Array.isArray(v)) {
|
|
1575
|
-
for (const item of v) stacks.push(item);
|
|
1576
|
-
} else if (v && typeof v === "object") {
|
|
1577
|
-
stacks.push(v);
|
|
1578
|
-
}
|
|
1579
|
-
}
|
|
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.`);
|
|
1580
1780
|
}
|
|
1581
|
-
return
|
|
1781
|
+
return n;
|
|
1582
1782
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
if (!extracted) {
|
|
1587
|
-
throw new Error(`Unable to infer current market price for ${symbol} from ticker response. Please provide buOrderData.top and buOrderData.bottom explicitly.`);
|
|
1783
|
+
function asBoolean2(value, field) {
|
|
1784
|
+
if (typeof value !== "boolean") {
|
|
1785
|
+
throw new Error(`Invalid "${field}": expected boolean.`);
|
|
1588
1786
|
}
|
|
1589
|
-
return
|
|
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(", ")}.`);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
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.`);
|
|
1808
|
+
}
|
|
1809
|
+
return s;
|
|
1810
|
+
}
|
|
1811
|
+
function normalizePerpBase(base) {
|
|
1812
|
+
return base.endsWith(".PERP") ? base : `${base}.PERP`;
|
|
1590
1813
|
}
|
|
1591
1814
|
function registerBotTools() {
|
|
1592
1815
|
return [
|
|
@@ -1615,113 +1838,35 @@ function registerBotTools() {
|
|
|
1615
1838
|
name: "pionex_bot_create_futures_grid_order",
|
|
1616
1839
|
module: "bot",
|
|
1617
1840
|
isWrite: true,
|
|
1618
|
-
description: "Create a futures grid
|
|
1619
|
-
inputSchema:
|
|
1620
|
-
type: "object",
|
|
1621
|
-
additionalProperties: false,
|
|
1622
|
-
properties: {
|
|
1623
|
-
keyId: { type: "string" },
|
|
1624
|
-
exchange: { type: "string", description: "e.g. pionex.v2" },
|
|
1625
|
-
base: { type: "string", description: "e.g. BTC" },
|
|
1626
|
-
quote: { type: "string", description: "e.g. USDT" },
|
|
1627
|
-
copyFrom: { type: "string" },
|
|
1628
|
-
copyType: { type: "string" },
|
|
1629
|
-
groupId: { type: "string" },
|
|
1630
|
-
copyBotOrderId: { type: "string" },
|
|
1631
|
-
lang: { type: "string" },
|
|
1632
|
-
buOrderData: {
|
|
1633
|
-
type: "object",
|
|
1634
|
-
additionalProperties: true,
|
|
1635
|
-
description: "CreateFuturesGridOrderData payload from openapi_bot.yaml."
|
|
1636
|
-
}
|
|
1637
|
-
},
|
|
1638
|
-
required: ["base", "buOrderData"]
|
|
1639
|
-
},
|
|
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,
|
|
1640
1843
|
async handler(args, { client, config }) {
|
|
1641
1844
|
if (config.readOnly) {
|
|
1642
1845
|
throw new Error("Server is running in --read-only mode; bot create is disabled.");
|
|
1643
1846
|
}
|
|
1644
|
-
const
|
|
1645
|
-
const exchange = asNonEmptyString(args.exchange ?? "pionex.v2", "exchange");
|
|
1646
|
-
if (args.exchange == null) defaultsApplied.exchange = exchange;
|
|
1647
|
-
const rawBase = asNonEmptyString(args.base, "base");
|
|
1847
|
+
const rawBase = asNonEmptyString2(args.base, "base");
|
|
1648
1848
|
const base = normalizePerpBase(rawBase);
|
|
1649
|
-
|
|
1650
|
-
const
|
|
1651
|
-
|
|
1652
|
-
const
|
|
1653
|
-
const symbol = `${base}_${quote}`;
|
|
1654
|
-
const needsTickerForTopBottom = buOrderData.top == null || buOrderData.bottom == null;
|
|
1655
|
-
const shouldTryTicker = needsTickerForTopBottom;
|
|
1656
|
-
let currentPrice;
|
|
1657
|
-
if (shouldTryTicker) {
|
|
1658
|
-
try {
|
|
1659
|
-
currentPrice = Number(await getCurrentSymbolPrice(client, symbol));
|
|
1660
|
-
} catch {
|
|
1661
|
-
currentPrice = void 0;
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
if (needsTickerForTopBottom && (currentPrice == null || !Number.isFinite(currentPrice) || currentPrice <= 0)) {
|
|
1665
|
-
throw new Error(`Unable to infer current market price for ${symbol} from ticker response. Please provide buOrderData.top and buOrderData.bottom explicitly.`);
|
|
1666
|
-
}
|
|
1667
|
-
const top = asPositiveDecimalString(
|
|
1668
|
-
buOrderData.top ?? toTrimmedDecimal(currentPrice * 1.05),
|
|
1669
|
-
"buOrderData.top"
|
|
1670
|
-
);
|
|
1671
|
-
if (buOrderData.top == null) defaultsApplied.top = top;
|
|
1672
|
-
const bottom = asPositiveDecimalString(
|
|
1673
|
-
buOrderData.bottom ?? toTrimmedDecimal(currentPrice * 0.95),
|
|
1674
|
-
"buOrderData.bottom"
|
|
1675
|
-
);
|
|
1676
|
-
if (buOrderData.bottom == null) defaultsApplied.bottom = bottom;
|
|
1677
|
-
if (Number(top) <= Number(bottom)) {
|
|
1678
|
-
throw new Error('Invalid "buOrderData.top": expected top > bottom.');
|
|
1679
|
-
}
|
|
1680
|
-
const row = asPositiveInteger(buOrderData.row ?? 10, "buOrderData.row");
|
|
1681
|
-
if (buOrderData.row == null) defaultsApplied.row = row;
|
|
1682
|
-
const gridType = asNonEmptyString(buOrderData.grid_type ?? "arithmetic", "buOrderData.grid_type");
|
|
1683
|
-
assertEnum(gridType, "buOrderData.grid_type", ["arithmetic", "geometric"]);
|
|
1684
|
-
if (buOrderData.grid_type == null) defaultsApplied.grid_type = gridType;
|
|
1685
|
-
const openPrice = buOrderData.openPrice == null ? void 0 : asPositiveDecimalString(buOrderData.openPrice, "buOrderData.openPrice");
|
|
1686
|
-
const trend = asNonEmptyString(buOrderData.trend, "buOrderData.trend");
|
|
1687
|
-
assertEnum(trend, "buOrderData.trend", ["long", "short", "no_trend"]);
|
|
1688
|
-
const leverage = asPositiveNumber(buOrderData.leverage ?? 2, "buOrderData.leverage");
|
|
1689
|
-
if (buOrderData.leverage == null) defaultsApplied.leverage = leverage;
|
|
1690
|
-
const extraMargin = asNonNegativeDecimalString(buOrderData.extraMargin ?? "0", "buOrderData.extraMargin");
|
|
1691
|
-
if (buOrderData.extraMargin == null) defaultsApplied.extraMargin = extraMargin;
|
|
1692
|
-
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;
|
|
1693
1853
|
const body = {
|
|
1694
|
-
exchange,
|
|
1695
1854
|
base,
|
|
1696
1855
|
quote,
|
|
1697
|
-
buOrderData:
|
|
1698
|
-
...buOrderData,
|
|
1699
|
-
top,
|
|
1700
|
-
bottom,
|
|
1701
|
-
row,
|
|
1702
|
-
grid_type: gridType,
|
|
1703
|
-
trend,
|
|
1704
|
-
leverage,
|
|
1705
|
-
extraMargin,
|
|
1706
|
-
quoteInvestment
|
|
1707
|
-
}
|
|
1856
|
+
buOrderData: buOrderDataOut
|
|
1708
1857
|
};
|
|
1709
|
-
if (openPrice != null) {
|
|
1710
|
-
body.buOrderData.openPrice = openPrice;
|
|
1711
|
-
}
|
|
1712
|
-
if (args.keyId != null) body.keyId = asNonEmptyString(args.keyId, "keyId");
|
|
1713
1858
|
if (args.copyFrom != null) body.copyFrom = String(args.copyFrom);
|
|
1714
1859
|
if (args.copyType != null) body.copyType = String(args.copyType);
|
|
1715
|
-
if (args.groupId != null) body.groupId = String(args.groupId);
|
|
1716
1860
|
if (args.copyBotOrderId != null) body.copyBotOrderId = String(args.copyBotOrderId);
|
|
1717
|
-
if (args.lang != null) body.lang = String(args.lang);
|
|
1718
1861
|
if (args.__dryRun === true) {
|
|
1719
1862
|
return {
|
|
1720
1863
|
dryRun: true,
|
|
1721
|
-
note: "No order was sent.
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1864
|
+
note: "No order was sent. Body matches openapi_bot.yaml CreateFuturesGridRequest (no keyId/openPrice/exchange; groupId/lang not in create schema).",
|
|
1865
|
+
resolvedParams: {
|
|
1866
|
+
row,
|
|
1867
|
+
grid_type: gridType,
|
|
1868
|
+
leverage
|
|
1869
|
+
},
|
|
1725
1870
|
resolvedBody: body
|
|
1726
1871
|
};
|
|
1727
1872
|
}
|
|
@@ -1761,26 +1906,26 @@ function registerBotTools() {
|
|
|
1761
1906
|
if (config.readOnly) {
|
|
1762
1907
|
throw new Error("Server is running in --read-only mode; bot adjust is disabled.");
|
|
1763
1908
|
}
|
|
1764
|
-
const buOrderId =
|
|
1765
|
-
const type =
|
|
1766
|
-
|
|
1767
|
-
const extraMargin =
|
|
1768
|
-
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");
|
|
1769
1914
|
if (type === "invest_in" && args.quoteInvestment != null) {
|
|
1770
|
-
|
|
1915
|
+
asPositiveNumber2(args.quoteInvestment, "quoteInvestment");
|
|
1771
1916
|
}
|
|
1772
1917
|
if (type === "adjust_params") {
|
|
1773
|
-
const bottom =
|
|
1774
|
-
const top =
|
|
1918
|
+
const bottom = asPositiveDecimalString2(args.bottom, "bottom");
|
|
1919
|
+
const top = asPositiveDecimalString2(args.top, "top");
|
|
1775
1920
|
if (Number(top) <= Number(bottom)) {
|
|
1776
1921
|
throw new Error('Invalid "top": expected top > bottom.');
|
|
1777
1922
|
}
|
|
1778
|
-
|
|
1923
|
+
asPositiveInteger2(args.row, "row");
|
|
1779
1924
|
}
|
|
1780
1925
|
if (type === "invest_in_trigger") {
|
|
1781
|
-
|
|
1782
|
-
const conditionDirection =
|
|
1783
|
-
|
|
1926
|
+
asPositiveDecimalString2(args.condition, "condition");
|
|
1927
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1928
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1784
1929
|
}
|
|
1785
1930
|
const body = {
|
|
1786
1931
|
buOrderId,
|
|
@@ -1788,23 +1933,23 @@ function registerBotTools() {
|
|
|
1788
1933
|
extraMargin,
|
|
1789
1934
|
openPrice
|
|
1790
1935
|
};
|
|
1791
|
-
if (args.quoteInvestment != null) body.quoteInvestment =
|
|
1792
|
-
if (args.bottom != null) body.bottom =
|
|
1793
|
-
if (args.top != null) body.top =
|
|
1794
|
-
if (args.row != null) body.row =
|
|
1795
|
-
if (args.extraMarginAmount != null) body.extraMarginAmount =
|
|
1796
|
-
if (args.isRecommend != null) body.isRecommend =
|
|
1797
|
-
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");
|
|
1798
1943
|
if (args.investCoin != null) body.investCoin = String(args.investCoin);
|
|
1799
1944
|
if (args.investmentFrom != null) {
|
|
1800
|
-
const investmentFrom =
|
|
1801
|
-
|
|
1945
|
+
const investmentFrom = asNonEmptyString2(args.investmentFrom, "investmentFrom");
|
|
1946
|
+
assertEnum2(investmentFrom, "investmentFrom", ["USER", "LOCK_ACTIVITY"]);
|
|
1802
1947
|
body.investmentFrom = investmentFrom;
|
|
1803
1948
|
}
|
|
1804
|
-
if (args.condition != null) body.condition =
|
|
1949
|
+
if (args.condition != null) body.condition = asPositiveDecimalString2(args.condition, "condition");
|
|
1805
1950
|
if (args.conditionDirection != null) {
|
|
1806
|
-
const conditionDirection =
|
|
1807
|
-
|
|
1951
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1952
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1808
1953
|
body.conditionDirection = conditionDirection;
|
|
1809
1954
|
}
|
|
1810
1955
|
if (args.slippage != null) body.slippage = String(args.slippage);
|
|
@@ -1834,9 +1979,9 @@ function registerBotTools() {
|
|
|
1834
1979
|
if (config.readOnly) {
|
|
1835
1980
|
throw new Error("Server is running in --read-only mode; bot reduce is disabled.");
|
|
1836
1981
|
}
|
|
1837
|
-
const buOrderId =
|
|
1838
|
-
const openPrice =
|
|
1839
|
-
const reduceNum =
|
|
1982
|
+
const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
|
|
1983
|
+
const openPrice = asPositiveDecimalString2(args.openPrice, "openPrice");
|
|
1984
|
+
const reduceNum = asPositiveInteger2(args.reduceNum, "reduceNum");
|
|
1840
1985
|
const body = {
|
|
1841
1986
|
buOrderId,
|
|
1842
1987
|
openPrice,
|
|
@@ -1845,8 +1990,8 @@ function registerBotTools() {
|
|
|
1845
1990
|
if (args.slippage != null) body.slippage = String(args.slippage);
|
|
1846
1991
|
if (args.condition != null) body.condition = String(args.condition);
|
|
1847
1992
|
if (args.conditionDirection != null) {
|
|
1848
|
-
const conditionDirection =
|
|
1849
|
-
|
|
1993
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1994
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1850
1995
|
body.conditionDirection = conditionDirection;
|
|
1851
1996
|
}
|
|
1852
1997
|
return (await client.signedPost("/api/v1/bot/orders/futuresGrid/reduce", body)).data;
|
|
@@ -1873,15 +2018,15 @@ function registerBotTools() {
|
|
|
1873
2018
|
if (config.readOnly) {
|
|
1874
2019
|
throw new Error("Server is running in --read-only mode; bot cancel is disabled.");
|
|
1875
2020
|
}
|
|
1876
|
-
const buOrderId =
|
|
2021
|
+
const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
|
|
1877
2022
|
const body = { buOrderId };
|
|
1878
2023
|
if (args.closeNote != null) body.closeNote = String(args.closeNote);
|
|
1879
2024
|
if (args.closeSellModel != null) {
|
|
1880
|
-
const closeSellModel =
|
|
1881
|
-
|
|
2025
|
+
const closeSellModel = asNonEmptyString2(args.closeSellModel, "closeSellModel");
|
|
2026
|
+
assertEnum2(closeSellModel, "closeSellModel", ["TO_QUOTE", "TO_USDT"]);
|
|
1882
2027
|
body.closeSellModel = closeSellModel;
|
|
1883
2028
|
}
|
|
1884
|
-
if (args.immediate != null) body.immediate =
|
|
2029
|
+
if (args.immediate != null) body.immediate = asBoolean2(args.immediate, "immediate");
|
|
1885
2030
|
if (args.closeSlippage != null) body.closeSlippage = String(args.closeSlippage);
|
|
1886
2031
|
return (await client.signedPost("/api/v1/bot/orders/futuresGrid/cancel", body)).data;
|
|
1887
2032
|
}
|
|
@@ -2060,27 +2205,29 @@ Examples:
|
|
|
2060
2205
|
pionex orders new --symbol BTC_USDT --side BUY --type MARKET --amount 10
|
|
2061
2206
|
pionex orders cancel --symbol BTC_USDT --order-id 123
|
|
2062
2207
|
pionex bot get --bu-order-id <id>
|
|
2063
|
-
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"}'
|
|
2064
2209
|
|
|
2065
2210
|
Global flags:
|
|
2066
2211
|
--profile <name> Profile in ~/.pionex/config.toml
|
|
2067
2212
|
--modules <list> Comma-separated modules (market,account,orders or all)
|
|
2068
2213
|
--base-url <url> Override API base URL
|
|
2069
2214
|
--read-only Disable write operations (orders new/cancel)
|
|
2070
|
-
--dry-run Print
|
|
2215
|
+
--dry-run Print resolved futures-grid create body without executing (bot create only)
|
|
2071
2216
|
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
quote
|
|
2075
|
-
|
|
2076
|
-
--
|
|
2077
|
-
buOrderData
|
|
2078
|
-
buOrderData
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
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
|
|
2084
2231
|
`);
|
|
2085
2232
|
}
|
|
2086
2233
|
function parseJsonFlag(raw, flagName) {
|
|
@@ -2255,21 +2402,17 @@ async function runPionexCommand(argv) {
|
|
|
2255
2402
|
return;
|
|
2256
2403
|
}
|
|
2257
2404
|
if (command === "create") {
|
|
2258
|
-
const keyId = typeof flags["key-id"] === "string" ? flags["key-id"] : typeof flags.keyId === "string" ? flags.keyId : void 0;
|
|
2259
|
-
const exchange = typeof flags.exchange === "string" ? flags.exchange : void 0;
|
|
2260
2405
|
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2261
2406
|
const quote = typeof flags.quote === "string" ? flags.quote : void 0;
|
|
2262
2407
|
const copyFrom = typeof flags["copy-from"] === "string" ? flags["copy-from"] : typeof flags.copyFrom === "string" ? flags.copyFrom : void 0;
|
|
2263
2408
|
const copyType = typeof flags["copy-type"] === "string" ? flags["copy-type"] : typeof flags.copyType === "string" ? flags.copyType : void 0;
|
|
2264
|
-
const groupId = typeof flags["group-id"] === "string" ? flags["group-id"] : typeof flags.groupId === "string" ? flags.groupId : void 0;
|
|
2265
2409
|
const copyBotOrderId = typeof flags["copy-bot-order-id"] === "string" ? flags["copy-bot-order-id"] : typeof flags.copyBotOrderId === "string" ? flags.copyBotOrderId : void 0;
|
|
2266
|
-
const
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
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");
|
|
2270
2413
|
}
|
|
2271
|
-
const
|
|
2272
|
-
|
|
2414
|
+
const buOrderData = parseAndValidateCreateFuturesGridBuOrderData(buOrderDataRaw);
|
|
2415
|
+
const payload = { base, quote, copyFrom, copyType, copyBotOrderId, buOrderData };
|
|
2273
2416
|
if (dryRun) {
|
|
2274
2417
|
const out2 = await runTool("pionex_bot_create_futures_grid_order", { ...payload, __dryRun: true });
|
|
2275
2418
|
process.stdout.write(JSON.stringify(out2.data, null, 2) + "\n");
|