@pionex/pionex-ai-kit 0.2.27 → 0.2.29
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 +330 -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,236 @@ 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 leverage = 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,
|
|
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
|
+
exchange: { type: "string", description: "Optional. Futures exchange identifier (temporary compatibility)." },
|
|
1753
|
+
copyFrom: { type: "string", description: "Optional. Copy source order ID" },
|
|
1754
|
+
copyType: { type: "string", description: "Optional. Copy type" },
|
|
1755
|
+
copyBotOrderId: { type: "string", description: "Optional. Copy bot order ID" },
|
|
1756
|
+
buOrderData: createFuturesGridOrderDataJsonSchema,
|
|
1757
|
+
__dryRun: { type: "boolean", description: "Internal: when true, return resolved body without POST" }
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
function asNonEmptyString2(value, field) {
|
|
1761
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1762
|
+
throw new Error(`Invalid "${field}": expected non-empty string.`);
|
|
1588
1763
|
}
|
|
1589
|
-
return
|
|
1764
|
+
return value.trim();
|
|
1590
1765
|
}
|
|
1591
|
-
function
|
|
1592
|
-
|
|
1766
|
+
function asFiniteNumber2(value, field) {
|
|
1767
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
1768
|
+
throw new Error(`Invalid "${field}": expected finite number.`);
|
|
1769
|
+
}
|
|
1770
|
+
return value;
|
|
1593
1771
|
}
|
|
1594
|
-
function
|
|
1595
|
-
const
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
return candidateClose;
|
|
1604
|
-
}
|
|
1605
|
-
for (const v of Object.values(obj)) {
|
|
1606
|
-
if (Array.isArray(v)) {
|
|
1607
|
-
for (const item of v) stacks.push(item);
|
|
1608
|
-
} else if (v && typeof v === "object") {
|
|
1609
|
-
stacks.push(v);
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1772
|
+
function asPositiveNumber2(value, field) {
|
|
1773
|
+
const n = asFiniteNumber2(value, field);
|
|
1774
|
+
if (n <= 0) throw new Error(`Invalid "${field}": expected number > 0.`);
|
|
1775
|
+
return n;
|
|
1776
|
+
}
|
|
1777
|
+
function asPositiveInteger2(value, field) {
|
|
1778
|
+
const n = asPositiveNumber2(value, field);
|
|
1779
|
+
if (!Number.isInteger(n)) {
|
|
1780
|
+
throw new Error(`Invalid "${field}": expected positive integer.`);
|
|
1612
1781
|
}
|
|
1613
|
-
return
|
|
1782
|
+
return n;
|
|
1614
1783
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
if (!extracted) {
|
|
1619
|
-
throw new Error(`Unable to infer current market price for ${symbol} from ticker response. Please provide buOrderData.top and buOrderData.bottom explicitly.`);
|
|
1784
|
+
function asBoolean2(value, field) {
|
|
1785
|
+
if (typeof value !== "boolean") {
|
|
1786
|
+
throw new Error(`Invalid "${field}": expected boolean.`);
|
|
1620
1787
|
}
|
|
1621
|
-
return
|
|
1788
|
+
return value;
|
|
1789
|
+
}
|
|
1790
|
+
function assertEnum2(value, field, allowed) {
|
|
1791
|
+
if (!allowed.includes(value)) {
|
|
1792
|
+
throw new Error(`Invalid "${field}": expected one of ${allowed.join(", ")}.`);
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
function asObject(value, field) {
|
|
1796
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1797
|
+
throw new Error(`Invalid "${field}": expected JSON object.`);
|
|
1798
|
+
}
|
|
1799
|
+
return value;
|
|
1800
|
+
}
|
|
1801
|
+
function asPositiveDecimalString2(value, field) {
|
|
1802
|
+
const s = asNonEmptyString2(value, field);
|
|
1803
|
+
if (!/^\d+(\.\d+)?$/.test(s)) {
|
|
1804
|
+
throw new Error(`Invalid "${field}": expected positive decimal string.`);
|
|
1805
|
+
}
|
|
1806
|
+
const n = Number(s);
|
|
1807
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
1808
|
+
throw new Error(`Invalid "${field}": expected positive decimal string.`);
|
|
1809
|
+
}
|
|
1810
|
+
return s;
|
|
1811
|
+
}
|
|
1812
|
+
function normalizePerpBase(base) {
|
|
1813
|
+
return base.endsWith(".PERP") ? base : `${base}.PERP`;
|
|
1622
1814
|
}
|
|
1623
1815
|
function registerBotTools() {
|
|
1624
1816
|
return [
|
|
@@ -1647,121 +1839,38 @@ function registerBotTools() {
|
|
|
1647
1839
|
name: "pionex_bot_create_futures_grid_order",
|
|
1648
1840
|
module: "bot",
|
|
1649
1841
|
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
|
-
},
|
|
1842
|
+
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; unknown keys rejected.",
|
|
1843
|
+
inputSchema: createFuturesGridCreateToolInputSchema,
|
|
1672
1844
|
async handler(args, { client, config }) {
|
|
1673
1845
|
if (config.readOnly) {
|
|
1674
1846
|
throw new Error("Server is running in --read-only mode; bot create is disabled.");
|
|
1675
1847
|
}
|
|
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");
|
|
1848
|
+
const rawBase = asNonEmptyString2(args.base, "base");
|
|
1680
1849
|
const base = normalizePerpBase(rawBase);
|
|
1681
|
-
|
|
1682
|
-
const
|
|
1683
|
-
|
|
1684
|
-
const
|
|
1685
|
-
const
|
|
1686
|
-
const
|
|
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");
|
|
1850
|
+
const quote = asNonEmptyString2(args.quote, "quote");
|
|
1851
|
+
const exchange = args.exchange != null ? asNonEmptyString2(args.exchange, "exchange") : void 0;
|
|
1852
|
+
const buOrderDataOut = parseAndValidateCreateFuturesGridBuOrderData(asObject(args.buOrderData, "buOrderData"));
|
|
1853
|
+
const row = buOrderDataOut.row;
|
|
1854
|
+
const gridType = buOrderDataOut.grid_type;
|
|
1855
|
+
const leverage = buOrderDataOut.leverage;
|
|
1726
1856
|
const body = {
|
|
1727
|
-
exchange,
|
|
1728
1857
|
base,
|
|
1729
1858
|
quote,
|
|
1730
|
-
buOrderData:
|
|
1731
|
-
...buOrderData,
|
|
1732
|
-
top,
|
|
1733
|
-
bottom,
|
|
1734
|
-
row,
|
|
1735
|
-
grid_type: gridType,
|
|
1736
|
-
trend,
|
|
1737
|
-
leverage,
|
|
1738
|
-
extraMargin,
|
|
1739
|
-
quoteInvestment
|
|
1740
|
-
}
|
|
1859
|
+
buOrderData: buOrderDataOut
|
|
1741
1860
|
};
|
|
1742
|
-
if (
|
|
1743
|
-
body.buOrderData.openPrice = openPrice;
|
|
1744
|
-
}
|
|
1745
|
-
if (args.keyId != null) body.keyId = asNonEmptyString(args.keyId, "keyId");
|
|
1861
|
+
if (exchange != null) body.exchange = exchange;
|
|
1746
1862
|
if (args.copyFrom != null) body.copyFrom = String(args.copyFrom);
|
|
1747
1863
|
if (args.copyType != null) body.copyType = String(args.copyType);
|
|
1748
|
-
if (args.groupId != null) body.groupId = String(args.groupId);
|
|
1749
1864
|
if (args.copyBotOrderId != null) body.copyBotOrderId = String(args.copyBotOrderId);
|
|
1750
|
-
if (args.lang != null) body.lang = String(args.lang);
|
|
1751
1865
|
if (args.__dryRun === true) {
|
|
1752
|
-
const rowSource = buOrderData.row == null ? "default" : "user";
|
|
1753
1866
|
return {
|
|
1754
1867
|
dryRun: true,
|
|
1755
|
-
note: "No order was sent.
|
|
1756
|
-
marketSymbol: symbol,
|
|
1757
|
-
marketPriceUsed: currentPrice,
|
|
1868
|
+
note: "No order was sent. Body matches openapi_bot.yaml CreateFuturesGridRequest.",
|
|
1758
1869
|
resolvedParams: {
|
|
1759
1870
|
row,
|
|
1760
|
-
rowSource,
|
|
1761
1871
|
grid_type: gridType,
|
|
1762
1872
|
leverage
|
|
1763
1873
|
},
|
|
1764
|
-
defaultsApplied,
|
|
1765
1874
|
resolvedBody: body
|
|
1766
1875
|
};
|
|
1767
1876
|
}
|
|
@@ -1801,26 +1910,26 @@ function registerBotTools() {
|
|
|
1801
1910
|
if (config.readOnly) {
|
|
1802
1911
|
throw new Error("Server is running in --read-only mode; bot adjust is disabled.");
|
|
1803
1912
|
}
|
|
1804
|
-
const buOrderId =
|
|
1805
|
-
const type =
|
|
1806
|
-
|
|
1807
|
-
const extraMargin =
|
|
1808
|
-
const openPrice =
|
|
1913
|
+
const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
|
|
1914
|
+
const type = asNonEmptyString2(args.type, "type");
|
|
1915
|
+
assertEnum2(type, "type", ["invest_in", "adjust_params", "invest_in_trigger"]);
|
|
1916
|
+
const extraMargin = asBoolean2(args.extraMargin, "extraMargin");
|
|
1917
|
+
const openPrice = asFiniteNumber2(args.openPrice, "openPrice");
|
|
1809
1918
|
if (type === "invest_in" && args.quoteInvestment != null) {
|
|
1810
|
-
|
|
1919
|
+
asPositiveNumber2(args.quoteInvestment, "quoteInvestment");
|
|
1811
1920
|
}
|
|
1812
1921
|
if (type === "adjust_params") {
|
|
1813
|
-
const bottom =
|
|
1814
|
-
const top =
|
|
1922
|
+
const bottom = asPositiveDecimalString2(args.bottom, "bottom");
|
|
1923
|
+
const top = asPositiveDecimalString2(args.top, "top");
|
|
1815
1924
|
if (Number(top) <= Number(bottom)) {
|
|
1816
1925
|
throw new Error('Invalid "top": expected top > bottom.');
|
|
1817
1926
|
}
|
|
1818
|
-
|
|
1927
|
+
asPositiveInteger2(args.row, "row");
|
|
1819
1928
|
}
|
|
1820
1929
|
if (type === "invest_in_trigger") {
|
|
1821
|
-
|
|
1822
|
-
const conditionDirection =
|
|
1823
|
-
|
|
1930
|
+
asPositiveDecimalString2(args.condition, "condition");
|
|
1931
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1932
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1824
1933
|
}
|
|
1825
1934
|
const body = {
|
|
1826
1935
|
buOrderId,
|
|
@@ -1828,23 +1937,23 @@ function registerBotTools() {
|
|
|
1828
1937
|
extraMargin,
|
|
1829
1938
|
openPrice
|
|
1830
1939
|
};
|
|
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 =
|
|
1940
|
+
if (args.quoteInvestment != null) body.quoteInvestment = asFiniteNumber2(args.quoteInvestment, "quoteInvestment");
|
|
1941
|
+
if (args.bottom != null) body.bottom = asPositiveDecimalString2(args.bottom, "bottom");
|
|
1942
|
+
if (args.top != null) body.top = asPositiveDecimalString2(args.top, "top");
|
|
1943
|
+
if (args.row != null) body.row = asPositiveInteger2(args.row, "row");
|
|
1944
|
+
if (args.extraMarginAmount != null) body.extraMarginAmount = asFiniteNumber2(args.extraMarginAmount, "extraMarginAmount");
|
|
1945
|
+
if (args.isRecommend != null) body.isRecommend = asBoolean2(args.isRecommend, "isRecommend");
|
|
1946
|
+
if (args.isReinvest != null) body.isReinvest = asBoolean2(args.isReinvest, "isReinvest");
|
|
1838
1947
|
if (args.investCoin != null) body.investCoin = String(args.investCoin);
|
|
1839
1948
|
if (args.investmentFrom != null) {
|
|
1840
|
-
const investmentFrom =
|
|
1841
|
-
|
|
1949
|
+
const investmentFrom = asNonEmptyString2(args.investmentFrom, "investmentFrom");
|
|
1950
|
+
assertEnum2(investmentFrom, "investmentFrom", ["USER", "LOCK_ACTIVITY"]);
|
|
1842
1951
|
body.investmentFrom = investmentFrom;
|
|
1843
1952
|
}
|
|
1844
|
-
if (args.condition != null) body.condition =
|
|
1953
|
+
if (args.condition != null) body.condition = asPositiveDecimalString2(args.condition, "condition");
|
|
1845
1954
|
if (args.conditionDirection != null) {
|
|
1846
|
-
const conditionDirection =
|
|
1847
|
-
|
|
1955
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1956
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1848
1957
|
body.conditionDirection = conditionDirection;
|
|
1849
1958
|
}
|
|
1850
1959
|
if (args.slippage != null) body.slippage = String(args.slippage);
|
|
@@ -1874,9 +1983,9 @@ function registerBotTools() {
|
|
|
1874
1983
|
if (config.readOnly) {
|
|
1875
1984
|
throw new Error("Server is running in --read-only mode; bot reduce is disabled.");
|
|
1876
1985
|
}
|
|
1877
|
-
const buOrderId =
|
|
1878
|
-
const openPrice =
|
|
1879
|
-
const reduceNum =
|
|
1986
|
+
const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
|
|
1987
|
+
const openPrice = asPositiveDecimalString2(args.openPrice, "openPrice");
|
|
1988
|
+
const reduceNum = asPositiveInteger2(args.reduceNum, "reduceNum");
|
|
1880
1989
|
const body = {
|
|
1881
1990
|
buOrderId,
|
|
1882
1991
|
openPrice,
|
|
@@ -1885,8 +1994,8 @@ function registerBotTools() {
|
|
|
1885
1994
|
if (args.slippage != null) body.slippage = String(args.slippage);
|
|
1886
1995
|
if (args.condition != null) body.condition = String(args.condition);
|
|
1887
1996
|
if (args.conditionDirection != null) {
|
|
1888
|
-
const conditionDirection =
|
|
1889
|
-
|
|
1997
|
+
const conditionDirection = asNonEmptyString2(args.conditionDirection, "conditionDirection");
|
|
1998
|
+
assertEnum2(conditionDirection, "conditionDirection", ["1", "-1"]);
|
|
1890
1999
|
body.conditionDirection = conditionDirection;
|
|
1891
2000
|
}
|
|
1892
2001
|
return (await client.signedPost("/api/v1/bot/orders/futuresGrid/reduce", body)).data;
|
|
@@ -1913,15 +2022,15 @@ function registerBotTools() {
|
|
|
1913
2022
|
if (config.readOnly) {
|
|
1914
2023
|
throw new Error("Server is running in --read-only mode; bot cancel is disabled.");
|
|
1915
2024
|
}
|
|
1916
|
-
const buOrderId =
|
|
2025
|
+
const buOrderId = asNonEmptyString2(args.buOrderId, "buOrderId");
|
|
1917
2026
|
const body = { buOrderId };
|
|
1918
2027
|
if (args.closeNote != null) body.closeNote = String(args.closeNote);
|
|
1919
2028
|
if (args.closeSellModel != null) {
|
|
1920
|
-
const closeSellModel =
|
|
1921
|
-
|
|
2029
|
+
const closeSellModel = asNonEmptyString2(args.closeSellModel, "closeSellModel");
|
|
2030
|
+
assertEnum2(closeSellModel, "closeSellModel", ["TO_QUOTE", "TO_USDT"]);
|
|
1922
2031
|
body.closeSellModel = closeSellModel;
|
|
1923
2032
|
}
|
|
1924
|
-
if (args.immediate != null) body.immediate =
|
|
2033
|
+
if (args.immediate != null) body.immediate = asBoolean2(args.immediate, "immediate");
|
|
1925
2034
|
if (args.closeSlippage != null) body.closeSlippage = String(args.closeSlippage);
|
|
1926
2035
|
return (await client.signedPost("/api/v1/bot/orders/futuresGrid/cancel", body)).data;
|
|
1927
2036
|
}
|
|
@@ -2100,27 +2209,29 @@ Examples:
|
|
|
2100
2209
|
pionex orders new --symbol BTC_USDT --side BUY --type MARKET --amount 10
|
|
2101
2210
|
pionex orders cancel --symbol BTC_USDT --order-id 123
|
|
2102
2211
|
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","
|
|
2212
|
+
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
2213
|
|
|
2105
2214
|
Global flags:
|
|
2106
2215
|
--profile <name> Profile in ~/.pionex/config.toml
|
|
2107
2216
|
--modules <list> Comma-separated modules (market,account,orders or all)
|
|
2108
2217
|
--base-url <url> Override API base URL
|
|
2109
2218
|
--read-only Disable write operations (orders new/cancel)
|
|
2110
|
-
--dry-run Print
|
|
2219
|
+
--dry-run Print resolved futures-grid create body without executing (bot create only)
|
|
2111
2220
|
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
quote
|
|
2115
|
-
|
|
2116
|
-
--
|
|
2117
|
-
buOrderData
|
|
2118
|
-
buOrderData
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2221
|
+
Futures grid create (pionex bot create) \u2014 strict OpenAPI (same validation as MCP):
|
|
2222
|
+
--base Required; normalized to <BASE>.PERP if suffix missing
|
|
2223
|
+
--quote Required (e.g. USDT)
|
|
2224
|
+
--bu-order-data-json Required JSON object \u2014 ONLY keys from CreateFuturesGridOrderData in openapi_bot.yaml
|
|
2225
|
+
Optional: --copy-from, --copy-type, --copy-bot-order-id
|
|
2226
|
+
buOrderData required: top, bottom, row, grid_type, trend, leverage, quoteInvestment
|
|
2227
|
+
buOrderData optional (names only): extraMargin, condition, conditionDirection, lossStopType, lossStop,
|
|
2228
|
+
lossStopDelay, profitStopType, profitStop, profitStopDelay, lossStopHigh, shareRatio, investCoin,
|
|
2229
|
+
investmentFrom, uiInvestCoin, lossStopLimitPrice, lossStopLimitHighPrice, profitStopLimitPrice,
|
|
2230
|
+
slippage, bonusId, uiExtraData, movingIndicatorType, movingIndicatorInterval, movingIndicatorParam,
|
|
2231
|
+
movingTrailingUpParam, cateType, movingTop, movingBottom, enableFollowClosed
|
|
2232
|
+
Unknown keys \u2192 error
|
|
2233
|
+
YAML: https://github.com/pionex-official/pionex-open-api/blob/main/openapi_bot.yaml
|
|
2234
|
+
Docs: https://www.pionex.com/docs/api-docs/bot-api/futures-grid
|
|
2124
2235
|
`);
|
|
2125
2236
|
}
|
|
2126
2237
|
function parseJsonFlag(raw, flagName) {
|
|
@@ -2295,21 +2406,18 @@ async function runPionexCommand(argv) {
|
|
|
2295
2406
|
return;
|
|
2296
2407
|
}
|
|
2297
2408
|
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
2409
|
const base = typeof flags.base === "string" ? flags.base : void 0;
|
|
2301
2410
|
const quote = typeof flags.quote === "string" ? flags.quote : void 0;
|
|
2411
|
+
const exchange = typeof flags.exchange === "string" ? flags.exchange : void 0;
|
|
2302
2412
|
const copyFrom = typeof flags["copy-from"] === "string" ? flags["copy-from"] : typeof flags.copyFrom === "string" ? flags.copyFrom : void 0;
|
|
2303
2413
|
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
2414
|
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");
|
|
2415
|
+
const buOrderDataRaw = parseJsonFlag(flags["bu-order-data-json"] ?? flags.buOrderDataJson, "bu-order-data-json");
|
|
2416
|
+
if (!base || !quote) {
|
|
2417
|
+
throw new Error("Missing required flags: --base --quote --bu-order-data-json");
|
|
2310
2418
|
}
|
|
2311
|
-
const
|
|
2312
|
-
|
|
2419
|
+
const buOrderData = parseAndValidateCreateFuturesGridBuOrderData(buOrderDataRaw);
|
|
2420
|
+
const payload = { base, quote, exchange, copyFrom, copyType, copyBotOrderId, buOrderData };
|
|
2313
2421
|
if (dryRun) {
|
|
2314
2422
|
const out2 = await runTool("pionex_bot_create_futures_grid_order", { ...payload, __dryRun: true });
|
|
2315
2423
|
process.stdout.write(JSON.stringify(out2.data, null, 2) + "\n");
|