@michaleffffff/mcp-trading-server 3.0.4 → 3.0.7
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/CHANGELOG.md +42 -6
- package/README.md +49 -414
- package/TOOL_EXAMPLES.md +63 -559
- package/dist/auth/resolveClient.js +19 -2
- package/dist/prompts/tradingGuide.js +16 -23
- package/dist/server.js +20 -2
- package/dist/services/balanceService.js +4 -4
- package/dist/services/marketService.js +48 -12
- package/dist/services/poolService.js +45 -44
- package/dist/services/tradeService.js +51 -23
- package/dist/tools/accountInfo.js +5 -134
- package/dist/tools/accountTransfer.js +7 -12
- package/dist/tools/adjustMargin.js +1 -1
- package/dist/tools/cancelOrders.js +71 -0
- package/dist/tools/checkAccountReady.js +75 -0
- package/dist/tools/checkApproval.js +1 -1
- package/dist/tools/closeAllPositions.js +9 -7
- package/dist/tools/closePosition.js +18 -11
- package/dist/tools/createPerpMarket.js +1 -1
- package/dist/tools/executeTrade.js +6 -6
- package/dist/tools/findPool.js +26 -0
- package/dist/tools/getAccountSnapshot.js +47 -0
- package/dist/tools/getAllTickers.js +5 -4
- package/dist/tools/getBaseDetail.js +1 -1
- package/dist/tools/getKline.js +7 -4
- package/dist/tools/getMyLpHoldings.js +3 -2
- package/dist/tools/getNetworkFee.js +1 -1
- package/dist/tools/getOrders.js +46 -0
- package/dist/tools/getPoolMetadata.js +95 -0
- package/dist/tools/getPositionsAll.js +80 -0
- package/dist/tools/{getMarketPrice.js → getPrice.js} +8 -5
- package/dist/tools/getUserTradingFeeRate.js +66 -3
- package/dist/tools/index.js +15 -19
- package/dist/tools/listPools.js +53 -0
- package/dist/tools/manageLiquidity.js +4 -4
- package/dist/tools/manageTpSl.js +234 -0
- package/dist/tools/openPositionSimple.js +27 -8
- package/dist/tools/searchTools.js +35 -0
- package/dist/utils/mappings.js +10 -7
- package/package.json +2 -2
- package/dist/tools/cancelAllOrders.js +0 -57
- package/dist/tools/cancelOrder.js +0 -22
- package/dist/tools/getAccountVipInfo.js +0 -20
- package/dist/tools/getKlineLatestBar.js +0 -28
- package/dist/tools/getOraclePrice.js +0 -22
- package/dist/tools/getPoolList.js +0 -17
- package/dist/tools/getPoolSymbolAll.js +0 -16
- package/dist/tools/getPositions.js +0 -77
- package/dist/tools/marketInfo.js +0 -88
- package/dist/tools/orderQueries.js +0 -51
- package/dist/tools/poolConfig.js +0 -22
- package/dist/tools/positionHistory.js +0 -28
- package/dist/tools/searchMarket.js +0 -21
- package/dist/tools/setTpSl.js +0 -50
- package/dist/tools/updateOrderTpSl.js +0 -34
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { resolveClient } from "../auth/resolveClient.js";
|
|
2
|
-
import { getPositions } from "../services/positionService.js";
|
|
3
|
-
import { getDirectionDesc } from "../utils/mappings.js";
|
|
4
|
-
export const getPositionsTool = {
|
|
5
|
-
name: "get_positions",
|
|
6
|
-
description: "Get all open positions for the current account.",
|
|
7
|
-
schema: {},
|
|
8
|
-
handler: async () => {
|
|
9
|
-
try {
|
|
10
|
-
const { client, address, chainId } = await resolveClient();
|
|
11
|
-
const data = await getPositions(client, address);
|
|
12
|
-
const positions = Array.isArray(data) ? data : (Array.isArray(data?.data) ? data.data : []);
|
|
13
|
-
if (positions.length === 0) {
|
|
14
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: [] }) }] };
|
|
15
|
-
}
|
|
16
|
-
// 1. Fetch Tickers for all relevant pools
|
|
17
|
-
const poolIds = [...new Set(positions.map((p) => p.poolId))];
|
|
18
|
-
const tickersRes = await client.markets.getTickerList({ chainId, poolIds });
|
|
19
|
-
const tickers = Array.isArray(tickersRes) ? tickersRes : (tickersRes?.data ?? []);
|
|
20
|
-
// 2. Fetch Pool Level Configs to get MM (Maintenance Margin Rate)
|
|
21
|
-
const configs = await Promise.all(poolIds.map(async (pid) => {
|
|
22
|
-
try {
|
|
23
|
-
const res = await client.markets.getPoolLevelConfig(pid, chainId);
|
|
24
|
-
return { poolId: pid, config: res?.levelConfig || res?.data?.levelConfig };
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return { poolId: pid, config: null };
|
|
28
|
-
}
|
|
29
|
-
}));
|
|
30
|
-
const enhancedData = positions.map((pos) => {
|
|
31
|
-
const ticker = tickers.find((t) => t.poolId === pos.poolId);
|
|
32
|
-
const currentPrice = Number(ticker?.price || 0);
|
|
33
|
-
const entryPrice = Number(pos.entryPrice || 0);
|
|
34
|
-
const size = Number(pos.size || 0);
|
|
35
|
-
const collateral = Number(pos.collateralAmount || 0);
|
|
36
|
-
const direction = pos.direction; // 0 = LONG, 1 = SHORT
|
|
37
|
-
const mm = configs.find(c => c.poolId === pos.poolId)?.config?.maintainCollateralRate || 0.02;
|
|
38
|
-
// Estimated PnL
|
|
39
|
-
let estimatedPnl = 0;
|
|
40
|
-
if (direction === 0) { // LONG
|
|
41
|
-
estimatedPnl = (currentPrice - entryPrice) * size;
|
|
42
|
-
}
|
|
43
|
-
else { // SHORT
|
|
44
|
-
estimatedPnl = (entryPrice - currentPrice) * size;
|
|
45
|
-
}
|
|
46
|
-
// ROI
|
|
47
|
-
const roi = collateral > 0 ? (estimatedPnl / collateral) * 100 : 0;
|
|
48
|
-
// Liquidation Price
|
|
49
|
-
// Long: (Entry * Size - Collateral) / (Size * (1 - MM))
|
|
50
|
-
// Short: (Entry * Size + Collateral) / (Size * (1 + MM))
|
|
51
|
-
let liqPrice = 0;
|
|
52
|
-
if (size > 0) {
|
|
53
|
-
if (direction === 0) {
|
|
54
|
-
liqPrice = (entryPrice * size - collateral) / (size * (1 - mm));
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
liqPrice = (entryPrice * size + collateral) / (size * (1 + mm));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
if (liqPrice < 0)
|
|
61
|
-
liqPrice = 0;
|
|
62
|
-
return {
|
|
63
|
-
...pos,
|
|
64
|
-
directionDesc: getDirectionDesc(pos.direction),
|
|
65
|
-
currentPrice: currentPrice.toString(),
|
|
66
|
-
estimatedPnl: estimatedPnl.toFixed(4),
|
|
67
|
-
roi: roi.toFixed(2) + "%",
|
|
68
|
-
liquidationPrice: liqPrice.toFixed(4)
|
|
69
|
-
};
|
|
70
|
-
});
|
|
71
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: enhancedData }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
};
|
package/dist/tools/marketInfo.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
|
-
import { getMarketDetail, resolvePool } from "../services/marketService.js";
|
|
4
|
-
import { getPoolInfo, getLiquidityInfo } from "../services/poolService.js";
|
|
5
|
-
import { extractErrorMessage } from "../utils/errorMessage.js";
|
|
6
|
-
import { parseUserPrice30 } from "../utils/units.js";
|
|
7
|
-
const INTEGER_RE = /^\d+$/;
|
|
8
|
-
const DECIMAL_RE = /^\d+(\.\d+)?$/;
|
|
9
|
-
function normalizeMarketPrice30Input(value) {
|
|
10
|
-
const text = String(value ?? "").trim();
|
|
11
|
-
if (!text)
|
|
12
|
-
throw new Error("marketPrice is required.");
|
|
13
|
-
// Keep backward compatibility: plain integers are treated as already-raw 30-dec units.
|
|
14
|
-
if (INTEGER_RE.test(text))
|
|
15
|
-
return text;
|
|
16
|
-
if (!DECIMAL_RE.test(text) && !/^raw:/i.test(text) && !/^human:/i.test(text)) {
|
|
17
|
-
throw new Error("marketPrice must be numeric, or prefixed with raw:/human:.");
|
|
18
|
-
}
|
|
19
|
-
return parseUserPrice30(text, "marketPrice");
|
|
20
|
-
}
|
|
21
|
-
export const getMarketDetailTool = {
|
|
22
|
-
name: "get_market_detail",
|
|
23
|
-
description: "Get detailed information for a specific trading pool (fee rates, open interest, etc.). Supports PoolId, Token Address, or Keywords.",
|
|
24
|
-
schema: {
|
|
25
|
-
poolId: z.string().describe("Pool ID, Token Address, or Keyword"),
|
|
26
|
-
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
27
|
-
},
|
|
28
|
-
handler: async (args) => {
|
|
29
|
-
try {
|
|
30
|
-
const { client } = await resolveClient();
|
|
31
|
-
const poolId = await resolvePool(client, args.poolId);
|
|
32
|
-
const chainId = args.chainId ?? getChainId();
|
|
33
|
-
const data = await getMarketDetail(client, poolId, chainId);
|
|
34
|
-
if (!data)
|
|
35
|
-
throw new Error(`Market detail for ${poolId} not found.`);
|
|
36
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
return { content: [{ type: "text", text: `Error: ${extractErrorMessage(error)}` }], isError: true };
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
export const getPoolInfoTool = {
|
|
44
|
-
name: "get_pool_info",
|
|
45
|
-
description: "Get pool on-chain information (reserves, utilization, etc.). Supports PoolId, Token Address, or Keywords.",
|
|
46
|
-
schema: {
|
|
47
|
-
poolId: z.string().describe("Pool ID, Token Address, or Keyword"),
|
|
48
|
-
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
49
|
-
},
|
|
50
|
-
handler: async (args) => {
|
|
51
|
-
try {
|
|
52
|
-
const { client } = await resolveClient();
|
|
53
|
-
const poolId = await resolvePool(client, args.poolId);
|
|
54
|
-
const chainId = args.chainId ?? getChainId();
|
|
55
|
-
const data = await getPoolInfo(poolId, chainId, client);
|
|
56
|
-
if (!data)
|
|
57
|
-
throw new Error(`Pool info for ${poolId} returned undefined. The pool may not exist on chainId ${chainId}.`);
|
|
58
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
return { content: [{ type: "text", text: `Error: ${extractErrorMessage(error)}` }], isError: true };
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
export const getLiquidityInfoTool = {
|
|
66
|
-
name: "get_liquidity_info",
|
|
67
|
-
description: "Get pool liquidity utilization and depth information. Supports PoolId, Token Address, or Keywords.",
|
|
68
|
-
schema: {
|
|
69
|
-
poolId: z.string().describe("Pool ID, Token Address, or Keyword"),
|
|
70
|
-
marketPrice: z.union([z.string(), z.number()]).describe("Current market price. Supports raw 30-dec integer, raw:..., or human price like 2172.5 / human:2172.5."),
|
|
71
|
-
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
72
|
-
},
|
|
73
|
-
handler: async (args) => {
|
|
74
|
-
try {
|
|
75
|
-
const { client } = await resolveClient();
|
|
76
|
-
const poolId = await resolvePool(client, args.poolId);
|
|
77
|
-
const chainId = args.chainId ?? getChainId();
|
|
78
|
-
const marketPrice = normalizeMarketPrice30Input(args.marketPrice);
|
|
79
|
-
const data = await getLiquidityInfo(client, poolId, marketPrice, chainId);
|
|
80
|
-
if (!data)
|
|
81
|
-
throw new Error(`Liquidity info for ${poolId} not available.`);
|
|
82
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
return { content: [{ type: "text", text: `Error: ${extractErrorMessage(error)}` }], isError: true };
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
|
-
import { getOrderTypeDesc, getOrderStatusDesc, getDirectionDesc, getHistoryOrderStatusDesc, getExecTypeDesc } from "../utils/mappings.js";
|
|
4
|
-
export const getOpenOrdersTool = {
|
|
5
|
-
name: "get_open_orders",
|
|
6
|
-
description: "List all currently open/pending orders.",
|
|
7
|
-
schema: {},
|
|
8
|
-
handler: async () => {
|
|
9
|
-
try {
|
|
10
|
-
const { client, address } = await resolveClient();
|
|
11
|
-
const result = await client.order.getOrders(address);
|
|
12
|
-
const enhancedData = (result?.data || []).map((order) => ({
|
|
13
|
-
...order,
|
|
14
|
-
orderTypeDesc: getOrderTypeDesc(order.orderType),
|
|
15
|
-
statusDesc: getOrderStatusDesc(order.status),
|
|
16
|
-
directionDesc: getDirectionDesc(order.direction)
|
|
17
|
-
}));
|
|
18
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: enhancedData }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
19
|
-
}
|
|
20
|
-
catch (error) {
|
|
21
|
-
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
export const getOrderHistoryTool = {
|
|
26
|
-
name: "get_order_history",
|
|
27
|
-
description: "Get historical orders with optional pool filter.",
|
|
28
|
-
schema: {
|
|
29
|
-
poolId: z.string().optional().describe("Filter by pool ID"),
|
|
30
|
-
limit: z.number().int().positive().optional().describe("Results per page (default 20)"),
|
|
31
|
-
},
|
|
32
|
-
handler: async (args) => {
|
|
33
|
-
try {
|
|
34
|
-
const { client, address } = await resolveClient();
|
|
35
|
-
const chainId = getChainId();
|
|
36
|
-
const query = { chainId, poolId: args.poolId, limit: args.limit ?? 20 };
|
|
37
|
-
const result = await client.order.getOrderHistory(query, address);
|
|
38
|
-
const enhancedData = (result?.data || []).map((order) => ({
|
|
39
|
-
...order,
|
|
40
|
-
orderTypeDesc: getOrderTypeDesc(order.orderType),
|
|
41
|
-
orderStatusDesc: getHistoryOrderStatusDesc(order.orderStatus),
|
|
42
|
-
directionDesc: getDirectionDesc(order.direction),
|
|
43
|
-
execTypeDesc: getExecTypeDesc(order.execType)
|
|
44
|
-
}));
|
|
45
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: { ...result, data: enhancedData } }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
};
|
package/dist/tools/poolConfig.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
|
-
import { getPoolLevelConfig } from "../services/marketService.js";
|
|
4
|
-
export const getPoolLevelConfigTool = {
|
|
5
|
-
name: "get_pool_level_config",
|
|
6
|
-
description: "Get the level configuration and trading limits for a specific pool.",
|
|
7
|
-
schema: {
|
|
8
|
-
poolId: z.string().describe("Pool ID"),
|
|
9
|
-
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
10
|
-
},
|
|
11
|
-
handler: async (args) => {
|
|
12
|
-
try {
|
|
13
|
-
const { client } = await resolveClient();
|
|
14
|
-
const chainId = args.chainId ?? getChainId();
|
|
15
|
-
const result = await getPoolLevelConfig(client, args.poolId, chainId);
|
|
16
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
|
-
import { getDirectionDesc, getCloseTypeDesc } from "../utils/mappings.js";
|
|
4
|
-
export const getPositionHistoryTool = {
|
|
5
|
-
name: "get_position_history",
|
|
6
|
-
description: "Get historical closed positions with optional pool filter.",
|
|
7
|
-
schema: {
|
|
8
|
-
poolId: z.string().optional().describe("Filter by pool ID"),
|
|
9
|
-
limit: z.number().int().positive().optional().describe("Results per page (default 20)"),
|
|
10
|
-
},
|
|
11
|
-
handler: async (args) => {
|
|
12
|
-
try {
|
|
13
|
-
const { client, address } = await resolveClient();
|
|
14
|
-
const chainId = getChainId();
|
|
15
|
-
const query = { chainId, poolId: args.poolId, limit: args.limit ?? 20 };
|
|
16
|
-
const result = await client.position.getPositionHistory(query, address);
|
|
17
|
-
const enhancedData = (result?.data || []).map((pos) => ({
|
|
18
|
-
...pos,
|
|
19
|
-
directionDesc: getDirectionDesc(pos.direction),
|
|
20
|
-
closeTypeDesc: getCloseTypeDesc(pos.closeType)
|
|
21
|
-
}));
|
|
22
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: { ...result, data: enhancedData } }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
23
|
-
}
|
|
24
|
-
catch (error) {
|
|
25
|
-
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { resolveClient } from "../auth/resolveClient.js";
|
|
3
|
-
import { searchMarket } from "../services/marketService.js";
|
|
4
|
-
export const searchMarketTool = {
|
|
5
|
-
name: "search_market",
|
|
6
|
-
description: "Search active markets by keyword. Leave keyword empty to list active markets.",
|
|
7
|
-
schema: {
|
|
8
|
-
keyword: z.string().optional().describe('Search keyword, e.g. "BTC", "ETH". Leave empty to return active markets.'),
|
|
9
|
-
limit: z.number().int().positive().optional().describe("Max results (default 100)"),
|
|
10
|
-
},
|
|
11
|
-
handler: async (args) => {
|
|
12
|
-
try {
|
|
13
|
-
const { client } = await resolveClient();
|
|
14
|
-
const activeMarkets = await searchMarket(client, args.keyword ?? "", args.limit ?? 100);
|
|
15
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: activeMarkets }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
16
|
-
}
|
|
17
|
-
catch (error) {
|
|
18
|
-
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
};
|
package/dist/tools/setTpSl.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { resolveClient } from "../auth/resolveClient.js";
|
|
3
|
-
import { setPositionTpSl } from "../services/tradeService.js";
|
|
4
|
-
import { finalizeMutationResult } from "../utils/mutationResult.js";
|
|
5
|
-
import { mapDirection, mapTriggerType } from "../utils/mappings.js";
|
|
6
|
-
import { SLIPPAGE_PCT_4DP_DESC } from "../utils/slippage.js";
|
|
7
|
-
export const setTpSlTool = {
|
|
8
|
-
name: "set_tp_sl",
|
|
9
|
-
description: "Create TP/SL order using SDK-native parameters.",
|
|
10
|
-
schema: {
|
|
11
|
-
poolId: z.string().describe("Hex Pool ID, e.g. '0x14a19...'. Get via get_pool_list."),
|
|
12
|
-
positionId: z.string().describe("Active Position ID. Get via get_positions."),
|
|
13
|
-
direction: z.any().describe("0=LONG, 1=SHORT, or strings like 'BUY'/'SELL'/'LONG'/'SHORT'."),
|
|
14
|
-
leverage: z.coerce.number().describe("Leverage multiplier, e.g., 10."),
|
|
15
|
-
executionFeeToken: z.string().describe("Address of token to pay gas/execution fees."),
|
|
16
|
-
tpTriggerType: z.union([z.number(), z.string()]).optional().describe("0/NONE, 1/GTE, 2/LTE. e.g. 'GTE'."),
|
|
17
|
-
slTriggerType: z.union([z.number(), z.string()]).optional().describe("0/NONE, 1/GTE, 2/LTE. e.g. 'LTE'."),
|
|
18
|
-
slippagePct: z.coerce.string().default("50").describe(`${SLIPPAGE_PCT_4DP_DESC}. Default is 50 (0.5%).`),
|
|
19
|
-
tpPrice: z.coerce.string().optional().describe("Take Profit trigger price. e.g. '2.5' or 'raw:...' (30 decimals)."),
|
|
20
|
-
tpSize: z.coerce.string().optional().describe("TP size in base tokens. Use '0' to disable."),
|
|
21
|
-
slPrice: z.coerce.string().optional().describe("Stop Loss trigger price. e.g. '2.1' or 'raw:...' (30 decimals)."),
|
|
22
|
-
slSize: z.coerce.string().optional().describe("SL size in base tokens. Use '0' to disable."),
|
|
23
|
-
},
|
|
24
|
-
handler: async (args) => {
|
|
25
|
-
try {
|
|
26
|
-
const { client, address, signer } = await resolveClient();
|
|
27
|
-
const { chainId } = await resolveClient();
|
|
28
|
-
const poolId = args.poolId;
|
|
29
|
-
// Fetch pool detail to get quoteToken for execution fee
|
|
30
|
-
const poolResponse = await client.markets.getMarketDetail({ chainId, poolId });
|
|
31
|
-
const poolData = poolResponse?.data || (poolResponse?.marketId ? poolResponse : null);
|
|
32
|
-
if (!poolData)
|
|
33
|
-
throw new Error(`Could not find pool metadata for ID: ${poolId}`);
|
|
34
|
-
// Map inputs
|
|
35
|
-
const mappedArgs = {
|
|
36
|
-
...args,
|
|
37
|
-
direction: mapDirection(args.direction),
|
|
38
|
-
tpTriggerType: args.tpTriggerType !== undefined ? mapTriggerType(args.tpTriggerType) : undefined,
|
|
39
|
-
slTriggerType: args.slTriggerType !== undefined ? mapTriggerType(args.slTriggerType) : undefined,
|
|
40
|
-
executionFeeToken: poolData.quoteToken || args.executionFeeToken
|
|
41
|
-
};
|
|
42
|
-
const raw = await setPositionTpSl(client, address, mappedArgs);
|
|
43
|
-
const data = await finalizeMutationResult(raw, signer, "set_tp_sl");
|
|
44
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { resolveClient } from "../auth/resolveClient.js";
|
|
3
|
-
import { updateOrderTpSl } from "../services/tradeService.js";
|
|
4
|
-
import { finalizeMutationResult } from "../utils/mutationResult.js";
|
|
5
|
-
import { extractErrorMessage } from "../utils/errorMessage.js";
|
|
6
|
-
export const updateOrderTpSlTool = {
|
|
7
|
-
name: "update_order_tp_sl",
|
|
8
|
-
description: "Update an existing take profit or stop loss order.",
|
|
9
|
-
schema: {
|
|
10
|
-
orderId: z.string().describe("The ID of the order to update"),
|
|
11
|
-
marketId: z.string().describe("The market ID (config hash) for the order"),
|
|
12
|
-
poolId: z.string().optional().describe("Optional poolId hint for decimal resolution."),
|
|
13
|
-
size: z.union([z.string(), z.number()]).describe("Order size (raw or human-readable)"),
|
|
14
|
-
price: z.union([z.string(), z.number()]).describe("Order price (raw or human-readable, 30 decimals)"),
|
|
15
|
-
tpPrice: z.union([z.string(), z.number()]).describe("TP price (raw or human-readable, 30 decimals)"),
|
|
16
|
-
tpSize: z.union([z.string(), z.number()]).describe("TP size (raw or human-readable)"),
|
|
17
|
-
slPrice: z.union([z.string(), z.number()]).describe("SL price (raw or human-readable, 30 decimals)"),
|
|
18
|
-
slSize: z.union([z.string(), z.number()]).describe("SL size (raw or human-readable)"),
|
|
19
|
-
useOrderCollateral: z.coerce.boolean().describe("Whether to use order collateral"),
|
|
20
|
-
isTpSlOrder: z.coerce.boolean().optional().describe("Whether this is a TP/SL order"),
|
|
21
|
-
quoteToken: z.string().describe("Quote token address"),
|
|
22
|
-
},
|
|
23
|
-
handler: async (args) => {
|
|
24
|
-
try {
|
|
25
|
-
const { client, address, signer } = await resolveClient();
|
|
26
|
-
const raw = await updateOrderTpSl(client, address, args);
|
|
27
|
-
const data = await finalizeMutationResult(raw, signer, "update_order_tp_sl");
|
|
28
|
-
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
return { content: [{ type: "text", text: `Error: ${extractErrorMessage(error)}` }], isError: true };
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
};
|