toobit-trade-cli 1.0.1 → 1.0.2
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 +125 -49
- package/package.json +1 -1
- package/src/commands/market.ts +10 -1
- package/src/formatter.ts +39 -1
package/dist/index.js
CHANGED
|
@@ -167,7 +167,9 @@ var TOOBIT_CODE_BEHAVIORS = {
|
|
|
167
167
|
"-2013": { retry: false, suggestion: "Order does not exist." },
|
|
168
168
|
"-2014": { retry: false, suggestion: "Bad API key format." },
|
|
169
169
|
"-2015": { retry: false, suggestion: "Invalid API key, IP, or permission." },
|
|
170
|
-
"-2017": { retry: false, suggestion: "API key expired. Generate a new one." }
|
|
170
|
+
"-2017": { retry: false, suggestion: "API key expired. Generate a new one." },
|
|
171
|
+
"-1130": { retry: false, suggestion: "Invalid symbol format. Futures endpoints require BTC-SWAP-USDT format; spot endpoints use BTCUSDT." },
|
|
172
|
+
"-1107": { retry: false, suggestion: "API key is missing or malformed. Check X-BB-APIKEY header." }
|
|
171
173
|
};
|
|
172
174
|
function isDefined(value) {
|
|
173
175
|
return value !== void 0 && value !== null;
|
|
@@ -285,34 +287,42 @@ var ToobitRestClient = class {
|
|
|
285
287
|
`${config.method} ${config.path}`
|
|
286
288
|
);
|
|
287
289
|
}
|
|
288
|
-
if (!response.ok) {
|
|
289
|
-
throw new ToobitApiError(
|
|
290
|
-
`HTTP ${response.status} from Toobit: ${parsed.msg ?? "Unknown error"}`,
|
|
291
|
-
{ code: String(response.status), endpoint: `${config.method} ${config.path}` }
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
290
|
const responseCode = parsed.code;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
291
|
+
const responseMsg = parsed.msg || void 0;
|
|
292
|
+
const endpoint = `${config.method} ${config.path}`;
|
|
293
|
+
const hasBusinessCode = responseCode !== void 0 && responseCode !== 0;
|
|
294
|
+
if (hasBusinessCode) {
|
|
298
295
|
const codeStr = String(responseCode);
|
|
299
|
-
|
|
296
|
+
const message = responseMsg || "Toobit API request failed.";
|
|
297
|
+
const behavior = TOOBIT_CODE_BEHAVIORS[codeStr];
|
|
298
|
+
if (codeStr === "-1002" || codeStr === "-1022" || codeStr === "-1107" || codeStr === "-2014" || codeStr === "-2015" || codeStr === "-2017") {
|
|
300
299
|
throw new AuthenticationError(
|
|
301
300
|
message,
|
|
302
|
-
"Check API key, secret key and permissions.",
|
|
301
|
+
behavior?.suggestion ?? "Check API key, secret key and permissions.",
|
|
303
302
|
endpoint
|
|
304
303
|
);
|
|
305
304
|
}
|
|
306
305
|
if (codeStr === "-1003") {
|
|
307
306
|
throw new RateLimitError(message, "Too many requests. Back off.", endpoint);
|
|
308
307
|
}
|
|
309
|
-
const behavior = TOOBIT_CODE_BEHAVIORS[codeStr];
|
|
310
308
|
throw new ToobitApiError(message, {
|
|
311
309
|
code: codeStr,
|
|
312
310
|
endpoint,
|
|
313
311
|
suggestion: behavior?.suggestion
|
|
314
312
|
});
|
|
315
313
|
}
|
|
314
|
+
if (!response.ok) {
|
|
315
|
+
const rawMsg = responseMsg ?? "Unknown error";
|
|
316
|
+
let suggestion;
|
|
317
|
+
if (/symbol|paramter|parameter/i.test(rawMsg)) {
|
|
318
|
+
const isFuturesPath = /futures|fundingRate|openInterest|markPrice|contract|longShort|insurance|riskLimit/i.test(config.path);
|
|
319
|
+
suggestion = isFuturesPath ? "Futures endpoints require contract symbol format, e.g. BTC-SWAP-USDT instead of BTCUSDT." : "Spot endpoints require symbol format like BTCUSDT.";
|
|
320
|
+
}
|
|
321
|
+
throw new ToobitApiError(
|
|
322
|
+
`HTTP ${response.status} from Toobit: ${rawMsg}`,
|
|
323
|
+
{ code: String(response.status), endpoint, suggestion }
|
|
324
|
+
);
|
|
325
|
+
}
|
|
316
326
|
return {
|
|
317
327
|
endpoint: `${config.method} ${config.path}`,
|
|
318
328
|
requestTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1298,6 +1308,13 @@ function registerFuturesTools() {
|
|
|
1298
1308
|
}
|
|
1299
1309
|
];
|
|
1300
1310
|
}
|
|
1311
|
+
function readPositiveInt(args, key) {
|
|
1312
|
+
const value = readNumber(args, key);
|
|
1313
|
+
if (value !== void 0 && value < 1) {
|
|
1314
|
+
throw new ValidationError(`Parameter "${key}" must be a positive integer.`);
|
|
1315
|
+
}
|
|
1316
|
+
return value;
|
|
1317
|
+
}
|
|
1301
1318
|
function normalize3(response) {
|
|
1302
1319
|
return { endpoint: response.endpoint, requestTime: response.requestTime, data: response.data };
|
|
1303
1320
|
}
|
|
@@ -1342,7 +1359,7 @@ function registerMarketTools() {
|
|
|
1342
1359
|
const args = asRecord(rawArgs);
|
|
1343
1360
|
const response = await context.client.publicGet(
|
|
1344
1361
|
"/quote/v1/depth",
|
|
1345
|
-
compactObject({ symbol: requireString(args, "symbol"), limit:
|
|
1362
|
+
compactObject({ symbol: requireString(args, "symbol"), limit: readPositiveInt(args, "limit") }),
|
|
1346
1363
|
publicRateLimit("market_get_depth", 20)
|
|
1347
1364
|
);
|
|
1348
1365
|
return normalize3(response);
|
|
@@ -1366,7 +1383,7 @@ function registerMarketTools() {
|
|
|
1366
1383
|
const args = asRecord(rawArgs);
|
|
1367
1384
|
const response = await context.client.publicGet(
|
|
1368
1385
|
"/quote/v1/depth/merged",
|
|
1369
|
-
compactObject({ symbol: requireString(args, "symbol"), scale: readNumber(args, "scale"), limit:
|
|
1386
|
+
compactObject({ symbol: requireString(args, "symbol"), scale: readNumber(args, "scale"), limit: readPositiveInt(args, "limit") }),
|
|
1370
1387
|
publicRateLimit("market_get_merged_depth", 20)
|
|
1371
1388
|
);
|
|
1372
1389
|
return normalize3(response);
|
|
@@ -1389,7 +1406,7 @@ function registerMarketTools() {
|
|
|
1389
1406
|
const args = asRecord(rawArgs);
|
|
1390
1407
|
const response = await context.client.publicGet(
|
|
1391
1408
|
"/quote/v1/trades",
|
|
1392
|
-
compactObject({ symbol: requireString(args, "symbol"), limit:
|
|
1409
|
+
compactObject({ symbol: requireString(args, "symbol"), limit: readPositiveInt(args, "limit") }),
|
|
1393
1410
|
publicRateLimit("market_get_trades", 20)
|
|
1394
1411
|
);
|
|
1395
1412
|
return normalize3(response);
|
|
@@ -1420,7 +1437,7 @@ function registerMarketTools() {
|
|
|
1420
1437
|
interval: requireString(args, "interval"),
|
|
1421
1438
|
startTime: readNumber(args, "startTime"),
|
|
1422
1439
|
endTime: readNumber(args, "endTime"),
|
|
1423
|
-
limit:
|
|
1440
|
+
limit: readPositiveInt(args, "limit")
|
|
1424
1441
|
}),
|
|
1425
1442
|
publicRateLimit("market_get_klines", 20)
|
|
1426
1443
|
);
|
|
@@ -1430,12 +1447,12 @@ function registerMarketTools() {
|
|
|
1430
1447
|
{
|
|
1431
1448
|
name: "market_get_ticker_24hr",
|
|
1432
1449
|
module: "market",
|
|
1433
|
-
description: "Get 24h price change statistics for a spot symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1450
|
+
description: "Get 24h price change statistics for a spot symbol. Omitting symbol returns ALL symbols (900+). Always specify a symbol unless you need the full list. Public endpoint. Rate limit: 20 req/s.",
|
|
1434
1451
|
isWrite: false,
|
|
1435
1452
|
inputSchema: {
|
|
1436
1453
|
type: "object",
|
|
1437
1454
|
properties: {
|
|
1438
|
-
symbol: { type: "string", description: "e.g. BTCUSDT. Omit for all symbols." }
|
|
1455
|
+
symbol: { type: "string", description: "e.g. BTCUSDT. Omit for all symbols (warning: 900+ results)." }
|
|
1439
1456
|
}
|
|
1440
1457
|
},
|
|
1441
1458
|
handler: async (rawArgs, context) => {
|
|
@@ -1451,12 +1468,12 @@ function registerMarketTools() {
|
|
|
1451
1468
|
{
|
|
1452
1469
|
name: "market_get_ticker_price",
|
|
1453
1470
|
module: "market",
|
|
1454
|
-
description: "Get latest price for a spot symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1471
|
+
description: "Get latest price for a spot symbol. Omitting symbol returns ALL symbols (900+), which may consume many tokens. Always specify a symbol unless you need the full list. Public endpoint. Rate limit: 20 req/s.",
|
|
1455
1472
|
isWrite: false,
|
|
1456
1473
|
inputSchema: {
|
|
1457
1474
|
type: "object",
|
|
1458
1475
|
properties: {
|
|
1459
|
-
symbol: { type: "string", description: "e.g. BTCUSDT. Omit for all symbols." }
|
|
1476
|
+
symbol: { type: "string", description: "e.g. BTCUSDT. Omit for all symbols (warning: 900+ results)." }
|
|
1460
1477
|
}
|
|
1461
1478
|
},
|
|
1462
1479
|
handler: async (rawArgs, context) => {
|
|
@@ -1472,12 +1489,12 @@ function registerMarketTools() {
|
|
|
1472
1489
|
{
|
|
1473
1490
|
name: "market_get_book_ticker",
|
|
1474
1491
|
module: "market",
|
|
1475
|
-
description: "Get best bid/ask price for a spot symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1492
|
+
description: "Get best bid/ask price for a spot symbol. Omitting symbol returns ALL symbols. Always specify a symbol unless you need the full list. Public endpoint. Rate limit: 20 req/s.",
|
|
1476
1493
|
isWrite: false,
|
|
1477
1494
|
inputSchema: {
|
|
1478
1495
|
type: "object",
|
|
1479
1496
|
properties: {
|
|
1480
|
-
symbol: { type: "string", description: "e.g. BTCUSDT. Omit for all symbols." }
|
|
1497
|
+
symbol: { type: "string", description: "e.g. BTCUSDT. Omit for all symbols (warning: 900+ results)." }
|
|
1481
1498
|
}
|
|
1482
1499
|
},
|
|
1483
1500
|
handler: async (rawArgs, context) => {
|
|
@@ -1515,7 +1532,7 @@ function registerMarketTools() {
|
|
|
1515
1532
|
interval: requireString(args, "interval"),
|
|
1516
1533
|
startTime: readNumber(args, "startTime"),
|
|
1517
1534
|
endTime: readNumber(args, "endTime"),
|
|
1518
|
-
limit:
|
|
1535
|
+
limit: readPositiveInt(args, "limit")
|
|
1519
1536
|
}),
|
|
1520
1537
|
publicRateLimit("market_get_index_klines", 20)
|
|
1521
1538
|
);
|
|
@@ -1525,12 +1542,12 @@ function registerMarketTools() {
|
|
|
1525
1542
|
{
|
|
1526
1543
|
name: "market_get_mark_price",
|
|
1527
1544
|
module: "market",
|
|
1528
|
-
description: "Get latest mark price for a futures symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1545
|
+
description: "Get latest mark price for a futures symbol. Requires contract symbol format. Public endpoint. Rate limit: 20 req/s.",
|
|
1529
1546
|
isWrite: false,
|
|
1530
1547
|
inputSchema: {
|
|
1531
1548
|
type: "object",
|
|
1532
1549
|
properties: {
|
|
1533
|
-
symbol: { type: "string", description: "e.g.
|
|
1550
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT. Omit for all." }
|
|
1534
1551
|
}
|
|
1535
1552
|
},
|
|
1536
1553
|
handler: async (rawArgs, context) => {
|
|
@@ -1546,12 +1563,12 @@ function registerMarketTools() {
|
|
|
1546
1563
|
{
|
|
1547
1564
|
name: "market_get_mark_price_klines",
|
|
1548
1565
|
module: "market",
|
|
1549
|
-
description: "Get mark price K-line data. Public endpoint. Rate limit: 20 req/s.",
|
|
1566
|
+
description: "Get mark price K-line data. Requires contract symbol format. Public endpoint. Rate limit: 20 req/s.",
|
|
1550
1567
|
isWrite: false,
|
|
1551
1568
|
inputSchema: {
|
|
1552
1569
|
type: "object",
|
|
1553
1570
|
properties: {
|
|
1554
|
-
symbol: { type: "string", description: "e.g.
|
|
1571
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT" },
|
|
1555
1572
|
interval: { type: "string", enum: [...TOOBIT_CANDLE_BARS] },
|
|
1556
1573
|
startTime: { type: "number" },
|
|
1557
1574
|
endTime: { type: "number" },
|
|
@@ -1568,7 +1585,7 @@ function registerMarketTools() {
|
|
|
1568
1585
|
interval: requireString(args, "interval"),
|
|
1569
1586
|
startTime: readNumber(args, "startTime"),
|
|
1570
1587
|
endTime: readNumber(args, "endTime"),
|
|
1571
|
-
limit:
|
|
1588
|
+
limit: readPositiveInt(args, "limit")
|
|
1572
1589
|
}),
|
|
1573
1590
|
publicRateLimit("market_get_mark_price_klines", 20)
|
|
1574
1591
|
);
|
|
@@ -1578,12 +1595,12 @@ function registerMarketTools() {
|
|
|
1578
1595
|
{
|
|
1579
1596
|
name: "market_get_funding_rate",
|
|
1580
1597
|
module: "market",
|
|
1581
|
-
description: "Get current funding rate for a futures symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1598
|
+
description: "Get current funding rate for a futures symbol. Requires contract symbol format. Public endpoint. Rate limit: 20 req/s.",
|
|
1582
1599
|
isWrite: false,
|
|
1583
1600
|
inputSchema: {
|
|
1584
1601
|
type: "object",
|
|
1585
1602
|
properties: {
|
|
1586
|
-
symbol: { type: "string", description: "e.g.
|
|
1603
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT. Omit for all." }
|
|
1587
1604
|
}
|
|
1588
1605
|
},
|
|
1589
1606
|
handler: async (rawArgs, context) => {
|
|
@@ -1599,12 +1616,12 @@ function registerMarketTools() {
|
|
|
1599
1616
|
{
|
|
1600
1617
|
name: "market_get_funding_rate_history",
|
|
1601
1618
|
module: "market",
|
|
1602
|
-
description: "Get historical funding rates for a futures symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1619
|
+
description: "Get historical funding rates for a futures symbol. Requires contract symbol format. Public endpoint. Rate limit: 20 req/s.",
|
|
1603
1620
|
isWrite: false,
|
|
1604
1621
|
inputSchema: {
|
|
1605
1622
|
type: "object",
|
|
1606
1623
|
properties: {
|
|
1607
|
-
symbol: { type: "string", description: "e.g.
|
|
1624
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT" },
|
|
1608
1625
|
startTime: { type: "number" },
|
|
1609
1626
|
endTime: { type: "number" },
|
|
1610
1627
|
limit: { type: "number", description: "Default 100, max 1000" }
|
|
@@ -1619,7 +1636,7 @@ function registerMarketTools() {
|
|
|
1619
1636
|
symbol: requireString(args, "symbol"),
|
|
1620
1637
|
startTime: readNumber(args, "startTime"),
|
|
1621
1638
|
endTime: readNumber(args, "endTime"),
|
|
1622
|
-
limit:
|
|
1639
|
+
limit: readPositiveInt(args, "limit")
|
|
1623
1640
|
}),
|
|
1624
1641
|
publicRateLimit("market_get_funding_rate_history", 20)
|
|
1625
1642
|
);
|
|
@@ -1629,12 +1646,12 @@ function registerMarketTools() {
|
|
|
1629
1646
|
{
|
|
1630
1647
|
name: "market_get_open_interest",
|
|
1631
1648
|
module: "market",
|
|
1632
|
-
description: "Get total open interest for a futures symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1649
|
+
description: "Get total open interest for a futures symbol. Requires contract symbol format. Public endpoint. Rate limit: 20 req/s.",
|
|
1633
1650
|
isWrite: false,
|
|
1634
1651
|
inputSchema: {
|
|
1635
1652
|
type: "object",
|
|
1636
1653
|
properties: {
|
|
1637
|
-
symbol: { type: "string", description: "e.g.
|
|
1654
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT. Omit for all." }
|
|
1638
1655
|
}
|
|
1639
1656
|
},
|
|
1640
1657
|
handler: async (rawArgs, context) => {
|
|
@@ -1655,7 +1672,7 @@ function registerMarketTools() {
|
|
|
1655
1672
|
inputSchema: {
|
|
1656
1673
|
type: "object",
|
|
1657
1674
|
properties: {
|
|
1658
|
-
symbol: { type: "string", description: "e.g.
|
|
1675
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT" },
|
|
1659
1676
|
period: { type: "string", description: "e.g. 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d" },
|
|
1660
1677
|
startTime: { type: "number" },
|
|
1661
1678
|
endTime: { type: "number" },
|
|
@@ -1672,7 +1689,7 @@ function registerMarketTools() {
|
|
|
1672
1689
|
period: requireString(args, "period"),
|
|
1673
1690
|
startTime: readNumber(args, "startTime"),
|
|
1674
1691
|
endTime: readNumber(args, "endTime"),
|
|
1675
|
-
limit:
|
|
1692
|
+
limit: readPositiveInt(args, "limit")
|
|
1676
1693
|
}),
|
|
1677
1694
|
publicRateLimit("market_get_long_short_ratio", 20)
|
|
1678
1695
|
);
|
|
@@ -1682,12 +1699,12 @@ function registerMarketTools() {
|
|
|
1682
1699
|
{
|
|
1683
1700
|
name: "market_get_contract_ticker_24hr",
|
|
1684
1701
|
module: "market",
|
|
1685
|
-
description: "Get 24h price change statistics for a futures contract. Public endpoint. Rate limit: 20 req/s.",
|
|
1702
|
+
description: "Get 24h price change statistics for a futures contract. Requires contract symbol format. Public endpoint. Rate limit: 20 req/s.",
|
|
1686
1703
|
isWrite: false,
|
|
1687
1704
|
inputSchema: {
|
|
1688
1705
|
type: "object",
|
|
1689
1706
|
properties: {
|
|
1690
|
-
symbol: { type: "string", description: "e.g.
|
|
1707
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT. Omit for all." }
|
|
1691
1708
|
}
|
|
1692
1709
|
},
|
|
1693
1710
|
handler: async (rawArgs, context) => {
|
|
@@ -1703,12 +1720,12 @@ function registerMarketTools() {
|
|
|
1703
1720
|
{
|
|
1704
1721
|
name: "market_get_contract_ticker_price",
|
|
1705
1722
|
module: "market",
|
|
1706
|
-
description: "Get latest price for a futures contract. Public endpoint. Rate limit: 20 req/s.",
|
|
1723
|
+
description: "Get latest price for a futures contract. Supports both spot (BTCUSDT) and contract (BTC-SWAP-USDT) symbol formats. Public endpoint. Rate limit: 20 req/s.",
|
|
1707
1724
|
isWrite: false,
|
|
1708
1725
|
inputSchema: {
|
|
1709
1726
|
type: "object",
|
|
1710
1727
|
properties: {
|
|
1711
|
-
symbol: { type: "string", description: "e.g. BTCUSDT. Omit for all." }
|
|
1728
|
+
symbol: { type: "string", description: "e.g. BTC-SWAP-USDT or BTCUSDT. Omit for all." }
|
|
1712
1729
|
}
|
|
1713
1730
|
},
|
|
1714
1731
|
handler: async (rawArgs, context) => {
|
|
@@ -1745,12 +1762,12 @@ function registerMarketTools() {
|
|
|
1745
1762
|
{
|
|
1746
1763
|
name: "market_get_insurance_fund",
|
|
1747
1764
|
module: "market",
|
|
1748
|
-
description: "Get insurance fund balance for a symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1765
|
+
description: "Get insurance fund balance for a futures symbol. Requires contract symbol format. Public endpoint. Rate limit: 20 req/s.",
|
|
1749
1766
|
isWrite: false,
|
|
1750
1767
|
inputSchema: {
|
|
1751
1768
|
type: "object",
|
|
1752
1769
|
properties: {
|
|
1753
|
-
symbol: { type: "string", description: "e.g.
|
|
1770
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT" }
|
|
1754
1771
|
},
|
|
1755
1772
|
required: ["symbol"]
|
|
1756
1773
|
},
|
|
@@ -1767,12 +1784,12 @@ function registerMarketTools() {
|
|
|
1767
1784
|
{
|
|
1768
1785
|
name: "market_get_risk_limits",
|
|
1769
1786
|
module: "market",
|
|
1770
|
-
description: "Get risk limits configuration for a futures symbol. Public endpoint. Rate limit: 20 req/s.",
|
|
1787
|
+
description: "Get risk limits configuration for a futures symbol. Requires contract symbol format. Public endpoint. Rate limit: 20 req/s.",
|
|
1771
1788
|
isWrite: false,
|
|
1772
1789
|
inputSchema: {
|
|
1773
1790
|
type: "object",
|
|
1774
1791
|
properties: {
|
|
1775
|
-
symbol: { type: "string", description: "e.g.
|
|
1792
|
+
symbol: { type: "string", description: "Futures contract symbol, e.g. BTC-SWAP-USDT" }
|
|
1776
1793
|
},
|
|
1777
1794
|
required: ["symbol"]
|
|
1778
1795
|
},
|
|
@@ -2078,12 +2095,15 @@ function allToolSpecs() {
|
|
|
2078
2095
|
];
|
|
2079
2096
|
}
|
|
2080
2097
|
function createToolRunner(client, config) {
|
|
2081
|
-
const fullConfig = { ...config, modules: [...MODULES]
|
|
2098
|
+
const fullConfig = { ...config, modules: [...MODULES] };
|
|
2082
2099
|
const tools = allToolSpecs();
|
|
2083
2100
|
const toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
2084
2101
|
return async (toolName, args) => {
|
|
2085
2102
|
const tool = toolMap.get(toolName);
|
|
2086
2103
|
if (!tool) throw new Error(`Unknown tool: ${toolName}`);
|
|
2104
|
+
if (config.readOnly && tool.isWrite) {
|
|
2105
|
+
throw new Error(`Tool "${toolName}" is a write operation and is blocked in read-only mode.`);
|
|
2106
|
+
}
|
|
2087
2107
|
const result = await tool.handler(args, { config: fullConfig, client });
|
|
2088
2108
|
return result;
|
|
2089
2109
|
};
|
|
@@ -2264,11 +2284,58 @@ function parseCli(argv = process.argv.slice(2)) {
|
|
|
2264
2284
|
}
|
|
2265
2285
|
|
|
2266
2286
|
// src/formatter.ts
|
|
2287
|
+
function extractRows(value) {
|
|
2288
|
+
if (Array.isArray(value)) return value;
|
|
2289
|
+
if (typeof value === "object" && value !== null) {
|
|
2290
|
+
const entries = Object.values(value);
|
|
2291
|
+
for (const v of entries) {
|
|
2292
|
+
if (Array.isArray(v)) return v;
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
return null;
|
|
2296
|
+
}
|
|
2267
2297
|
function formatJson(data, json) {
|
|
2268
2298
|
if (json) return JSON.stringify(data, null, 2);
|
|
2269
2299
|
if (data === null || data === void 0) return "No data.";
|
|
2270
2300
|
if (typeof data !== "object") return String(data);
|
|
2271
|
-
|
|
2301
|
+
const record = data;
|
|
2302
|
+
const inner = record.data ?? record;
|
|
2303
|
+
const rows = extractRows(inner);
|
|
2304
|
+
if (rows) {
|
|
2305
|
+
if (rows.length === 0) return "No data.";
|
|
2306
|
+
if (typeof rows[0] === "object" && rows[0] !== null) {
|
|
2307
|
+
return formatTable(rows);
|
|
2308
|
+
}
|
|
2309
|
+
return rows.map(String).join("\n");
|
|
2310
|
+
}
|
|
2311
|
+
if (typeof inner === "object" && inner !== null) {
|
|
2312
|
+
return formatKv(inner);
|
|
2313
|
+
}
|
|
2314
|
+
return String(inner);
|
|
2315
|
+
}
|
|
2316
|
+
function formatKv(data) {
|
|
2317
|
+
const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null);
|
|
2318
|
+
if (entries.length === 0) return "No data.";
|
|
2319
|
+
const maxKey = Math.max(...entries.map(([k]) => k.length));
|
|
2320
|
+
return entries.map(([k, v]) => {
|
|
2321
|
+
if (typeof v === "object") return `${k.padEnd(maxKey)} ${JSON.stringify(v)}`;
|
|
2322
|
+
return `${k.padEnd(maxKey)} ${String(v)}`;
|
|
2323
|
+
}).join("\n");
|
|
2324
|
+
}
|
|
2325
|
+
function formatTable(rows, columns) {
|
|
2326
|
+
if (rows.length === 0) return "No data.";
|
|
2327
|
+
const keys = columns ?? Object.keys(rows[0]);
|
|
2328
|
+
const widths = keys.map(
|
|
2329
|
+
(k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? "").length))
|
|
2330
|
+
);
|
|
2331
|
+
const header = keys.map((k, i) => k.padEnd(widths[i])).join(" ");
|
|
2332
|
+
const separator = widths.map((w) => "-".repeat(w)).join(" ");
|
|
2333
|
+
const body = rows.map(
|
|
2334
|
+
(row) => keys.map((k, i) => String(row[k] ?? "").padEnd(widths[i])).join(" ")
|
|
2335
|
+
).join("\n");
|
|
2336
|
+
return `${header}
|
|
2337
|
+
${separator}
|
|
2338
|
+
${body}`;
|
|
2272
2339
|
}
|
|
2273
2340
|
|
|
2274
2341
|
// src/commands/market.ts
|
|
@@ -2331,9 +2398,18 @@ async function handleMarketCommand(cli, run) {
|
|
|
2331
2398
|
case "long-short-ratio":
|
|
2332
2399
|
result = await run("market_get_long_short_ratio", { symbol: f.symbol, period: f.period ?? "1h" });
|
|
2333
2400
|
break;
|
|
2401
|
+
case "contract-ticker-price":
|
|
2402
|
+
result = await run("market_get_contract_ticker_price", { symbol: f.symbol });
|
|
2403
|
+
break;
|
|
2404
|
+
case "insurance-fund":
|
|
2405
|
+
result = await run("market_get_insurance_fund", { symbol: f.symbol });
|
|
2406
|
+
break;
|
|
2407
|
+
case "risk-limits":
|
|
2408
|
+
result = await run("market_get_risk_limits", { symbol: f.symbol });
|
|
2409
|
+
break;
|
|
2334
2410
|
default:
|
|
2335
2411
|
process.stdout.write(`Unknown market subcommand: ${cli.subcommand}
|
|
2336
|
-
Available: time, info, ticker, ticker-24hr, depth, trades, klines, candles, book-ticker, mark-price, funding-rate, funding-rate-history, open-interest, index, contract-ticker, long-short-ratio
|
|
2412
|
+
Available: time, info, ticker, ticker-24hr, depth, trades, klines, candles, book-ticker, mark-price, funding-rate, funding-rate-history, open-interest, index, contract-ticker, contract-ticker-price, long-short-ratio, insurance-fund, risk-limits
|
|
2337
2413
|
`);
|
|
2338
2414
|
return;
|
|
2339
2415
|
}
|
package/package.json
CHANGED
package/src/commands/market.ts
CHANGED
|
@@ -62,8 +62,17 @@ export async function handleMarketCommand(cli: CliParsed, run: ToolRunner): Prom
|
|
|
62
62
|
case "long-short-ratio":
|
|
63
63
|
result = await run("market_get_long_short_ratio", { symbol: f.symbol, period: f.period ?? "1h" });
|
|
64
64
|
break;
|
|
65
|
+
case "contract-ticker-price":
|
|
66
|
+
result = await run("market_get_contract_ticker_price", { symbol: f.symbol });
|
|
67
|
+
break;
|
|
68
|
+
case "insurance-fund":
|
|
69
|
+
result = await run("market_get_insurance_fund", { symbol: f.symbol });
|
|
70
|
+
break;
|
|
71
|
+
case "risk-limits":
|
|
72
|
+
result = await run("market_get_risk_limits", { symbol: f.symbol });
|
|
73
|
+
break;
|
|
65
74
|
default:
|
|
66
|
-
process.stdout.write(`Unknown market subcommand: ${cli.subcommand}\nAvailable: time, info, ticker, ticker-24hr, depth, trades, klines, candles, book-ticker, mark-price, funding-rate, funding-rate-history, open-interest, index, contract-ticker, long-short-ratio\n`);
|
|
75
|
+
process.stdout.write(`Unknown market subcommand: ${cli.subcommand}\nAvailable: time, info, ticker, ticker-24hr, depth, trades, klines, candles, book-ticker, mark-price, funding-rate, funding-rate-history, open-interest, index, contract-ticker, contract-ticker-price, long-short-ratio, insurance-fund, risk-limits\n`);
|
|
67
76
|
return;
|
|
68
77
|
}
|
|
69
78
|
|
package/src/formatter.ts
CHANGED
|
@@ -1,8 +1,46 @@
|
|
|
1
|
+
function extractRows(value: unknown): unknown[] | null {
|
|
2
|
+
if (Array.isArray(value)) return value;
|
|
3
|
+
if (typeof value === "object" && value !== null) {
|
|
4
|
+
const entries = Object.values(value as Record<string, unknown>);
|
|
5
|
+
for (const v of entries) {
|
|
6
|
+
if (Array.isArray(v)) return v;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
|
|
1
12
|
export function formatJson(data: unknown, json: boolean): string {
|
|
2
13
|
if (json) return JSON.stringify(data, null, 2);
|
|
3
14
|
if (data === null || data === undefined) return "No data.";
|
|
4
15
|
if (typeof data !== "object") return String(data);
|
|
5
|
-
|
|
16
|
+
|
|
17
|
+
const record = data as Record<string, unknown>;
|
|
18
|
+
const inner = record.data ?? record;
|
|
19
|
+
|
|
20
|
+
const rows = extractRows(inner);
|
|
21
|
+
if (rows) {
|
|
22
|
+
if (rows.length === 0) return "No data.";
|
|
23
|
+
if (typeof rows[0] === "object" && rows[0] !== null) {
|
|
24
|
+
return formatTable(rows as Record<string, unknown>[]);
|
|
25
|
+
}
|
|
26
|
+
return rows.map(String).join("\n");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (typeof inner === "object" && inner !== null) {
|
|
30
|
+
return formatKv(inner as Record<string, unknown>);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return String(inner);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function formatKv(data: Record<string, unknown>): string {
|
|
37
|
+
const entries = Object.entries(data).filter(([, v]) => v !== undefined && v !== null);
|
|
38
|
+
if (entries.length === 0) return "No data.";
|
|
39
|
+
const maxKey = Math.max(...entries.map(([k]) => k.length));
|
|
40
|
+
return entries.map(([k, v]) => {
|
|
41
|
+
if (typeof v === "object") return `${k.padEnd(maxKey)} ${JSON.stringify(v)}`;
|
|
42
|
+
return `${k.padEnd(maxKey)} ${String(v)}`;
|
|
43
|
+
}).join("\n");
|
|
6
44
|
}
|
|
7
45
|
|
|
8
46
|
export function formatTable(rows: Record<string, unknown>[], columns?: string[]): string {
|