gate-mcp 0.5.0 → 0.7.0

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.
@@ -1,13 +1,22 @@
1
1
  import { z } from 'zod';
2
- import { FuturesApi, FuturesPositionCrossMode, InlineObject } from 'gate-api';
2
+ import { FuturesApi, FuturesPositionCrossMode, InlineObject, BatchFundingRatesRequest, FuturesBBOOrder, CreateTrailOrder, StopTrailOrder, StopAllTrailOrders, UpdateTrailOrder, BatchAmendOrderReq, FuturesUpdatePriceTriggeredOrder, } from 'gate-api';
3
3
  import { createClient, requireAuth } from '../client.js';
4
4
  import { textContent, errorContent } from '../utils.js';
5
5
  const settleSchema = z.enum(['btc', 'usdt']).describe('Settlement currency: btc or usdt');
6
6
  export function registerFuturesTools(server) {
7
7
  // ── Public tools ──────────────────────────────────────────────────────────
8
- server.tool('cex_futures_list_futures_contracts', 'List all perpetual futures contracts', { settle: settleSchema }, async ({ settle }) => {
8
+ server.tool('cex_futures_list_futures_contracts', 'List all perpetual futures contracts', {
9
+ settle: settleSchema,
10
+ limit: z.number().int().optional(),
11
+ offset: z.number().int().optional(),
12
+ }, async ({ settle, limit, offset }) => {
9
13
  try {
10
- const { body } = await new FuturesApi(createClient()).listFuturesContracts(settle, {});
14
+ const opts = {};
15
+ if (limit !== undefined)
16
+ opts.limit = limit;
17
+ if (offset !== undefined)
18
+ opts.offset = offset;
19
+ const { body } = await new FuturesApi(createClient()).listFuturesContracts(settle, opts);
11
20
  return textContent(body);
12
21
  }
13
22
  catch (e) {
@@ -29,12 +38,18 @@ export function registerFuturesTools(server) {
29
38
  server.tool('cex_futures_get_futures_order_book', 'Get futures order book', {
30
39
  settle: settleSchema,
31
40
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
41
+ interval: z.string().optional().describe('Price grouping interval e.g. 0, 0.1, 0.01'),
32
42
  limit: z.number().int().optional(),
33
- }, async ({ settle, contract, limit }) => {
43
+ with_id: z.boolean().optional().describe('Include order book ID in response'),
44
+ }, async ({ settle, contract, interval, limit, with_id }) => {
34
45
  try {
35
46
  const opts = {};
47
+ if (interval)
48
+ opts.interval = interval;
36
49
  if (limit !== undefined)
37
50
  opts.limit = limit;
51
+ if (with_id !== undefined)
52
+ opts.withId = with_id;
38
53
  const { body } = await new FuturesApi(createClient()).listFuturesOrderBook(settle, contract, opts);
39
54
  return textContent(body);
40
55
  }
@@ -49,7 +64,8 @@ export function registerFuturesTools(server) {
49
64
  limit: z.number().int().optional(),
50
65
  from: z.number().optional().describe('Start time (Unix timestamp)'),
51
66
  to: z.number().optional().describe('End time (Unix timestamp)'),
52
- }, async ({ settle, contract, interval, limit, from, to }) => {
67
+ timezone: z.string().optional().describe('Timezone for candle alignment e.g. Asia/Shanghai'),
68
+ }, async ({ settle, contract, interval, limit, from, to, timezone }) => {
53
69
  try {
54
70
  const opts = {};
55
71
  if (interval)
@@ -60,6 +76,8 @@ export function registerFuturesTools(server) {
60
76
  opts.from = from;
61
77
  if (to !== undefined)
62
78
  opts.to = to;
79
+ if (timezone)
80
+ opts.timezone = timezone;
63
81
  const { body } = await new FuturesApi(createClient()).listFuturesCandlesticks(settle, contract, opts);
64
82
  return textContent(body);
65
83
  }
@@ -86,11 +104,17 @@ export function registerFuturesTools(server) {
86
104
  settle: settleSchema,
87
105
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
88
106
  limit: z.number().int().optional(),
89
- }, async ({ settle, contract, limit }) => {
107
+ from: z.number().optional().describe('Start time (Unix timestamp)'),
108
+ to: z.number().optional().describe('End time (Unix timestamp)'),
109
+ }, async ({ settle, contract, limit, from, to }) => {
90
110
  try {
91
111
  const opts = {};
92
112
  if (limit !== undefined)
93
113
  opts.limit = limit;
114
+ if (from !== undefined)
115
+ opts.from = from;
116
+ if (to !== undefined)
117
+ opts.to = to;
94
118
  const { body } = await new FuturesApi(createClient()).listFuturesFundingRateHistory(settle, contract, opts);
95
119
  return textContent(body);
96
120
  }
@@ -98,380 +122,445 @@ export function registerFuturesTools(server) {
98
122
  return errorContent(e);
99
123
  }
100
124
  });
101
- // ── Private tools ─────────────────────────────────────────────────────────
102
- server.tool('cex_futures_get_futures_accounts', 'Get futures account balances (requires authentication)', { settle: settleSchema }, async ({ settle }) => {
103
- try {
104
- requireAuth();
105
- const { body } = await new FuturesApi(createClient()).listFuturesAccounts(settle);
106
- return textContent(body);
107
- }
108
- catch (e) {
109
- return errorContent(e);
110
- }
111
- });
112
- server.tool('cex_futures_list_futures_positions', 'List all open futures positions (requires authentication)', {
125
+ server.tool('cex_futures_get_futures_trades', 'Get recent public trades for a futures contract', {
113
126
  settle: settleSchema,
114
- holding: z.boolean().optional().describe('Only return positions with non-zero size'),
127
+ contract: z.string().describe('Contract name e.g. BTC_USDT'),
115
128
  limit: z.number().int().optional(),
116
129
  offset: z.number().int().optional(),
117
- }, async ({ settle, holding, limit, offset }) => {
130
+ last_id: z.string().optional().describe('Pagination cursor return records after this trade ID'),
131
+ from: z.number().optional().describe('Start time (Unix timestamp)'),
132
+ to: z.number().optional().describe('End time (Unix timestamp)'),
133
+ }, async ({ settle, contract, limit, offset, last_id, from, to }) => {
118
134
  try {
119
- requireAuth();
120
135
  const opts = {};
121
- if (holding !== undefined)
122
- opts.holding = holding;
123
136
  if (limit !== undefined)
124
137
  opts.limit = limit;
125
138
  if (offset !== undefined)
126
139
  opts.offset = offset;
127
- const { body } = await new FuturesApi(createClient()).listPositions(settle, opts);
140
+ if (last_id)
141
+ opts.lastId = last_id;
142
+ if (from !== undefined)
143
+ opts.from = from;
144
+ if (to !== undefined)
145
+ opts.to = to;
146
+ const { body } = await new FuturesApi(createClient()).listFuturesTrades(settle, contract, opts);
128
147
  return textContent(body);
129
148
  }
130
149
  catch (e) {
131
150
  return errorContent(e);
132
151
  }
133
152
  });
134
- server.tool('cex_futures_get_futures_position', 'Get a single futures position (requires authentication)', {
153
+ server.tool('cex_futures_list_contract_stats', 'Get contract statistics (open interest, long/short ratio, etc.)', {
135
154
  settle: settleSchema,
136
155
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
137
- }, async ({ settle, contract }) => {
138
- try {
139
- requireAuth();
140
- const { body } = await new FuturesApi(createClient()).getPosition(settle, contract);
141
- return textContent(body);
142
- }
143
- catch (e) {
144
- return errorContent(e);
145
- }
146
- });
147
- server.tool('cex_futures_list_futures_orders', 'List futures orders (requires authentication)', {
148
- settle: settleSchema,
149
- status: z.enum(['open', 'finished']).describe('Order status'),
150
- contract: z.string().optional().describe('Filter by contract'),
156
+ from: z.number().optional().describe('Start time (Unix timestamp)'),
157
+ interval: z.enum(['5m', '15m', '30m', '1h', '4h', '1d']).optional(),
151
158
  limit: z.number().int().optional(),
152
- offset: z.number().int().optional(),
153
- }, async ({ settle, status, contract, limit, offset }) => {
159
+ }, async ({ settle, contract, from, interval, limit }) => {
154
160
  try {
155
- requireAuth();
156
161
  const opts = {};
157
- if (contract)
158
- opts.contract = contract;
162
+ if (from !== undefined)
163
+ opts.from = from;
164
+ if (interval)
165
+ opts.interval = interval;
159
166
  if (limit !== undefined)
160
167
  opts.limit = limit;
161
- if (offset !== undefined)
162
- opts.offset = offset;
163
- const { body } = await new FuturesApi(createClient()).listFuturesOrders(settle, status, opts);
168
+ const { body } = await new FuturesApi(createClient()).listContractStats(settle, contract, opts);
164
169
  return textContent(body);
165
170
  }
166
171
  catch (e) {
167
172
  return errorContent(e);
168
173
  }
169
174
  });
170
- server.tool('cex_futures_create_futures_order', 'Create a futures order (requires authentication) always confirm the details with the user before calling this tool', {
175
+ server.tool('cex_futures_get_futures_premium_index', 'Get premium index (mark price minus index price) history for a contract', {
171
176
  settle: settleSchema,
172
177
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
173
- size: z.string().describe('Order size in contracts (negative = short)'),
174
- price: z.string().describe('Order price (0 for market orders)'),
175
- tif: z.enum(['gtc', 'ioc', 'poc', 'fok']).optional().describe('Time in force'),
176
- reduce_only: z.boolean().optional().describe('Reduce-only order'),
177
- close: z.boolean().optional().describe('Close position'),
178
- text: z.string().optional().describe('Custom reference text'),
179
- }, async ({ settle, contract, size, price, tif, reduce_only, close, text }) => {
178
+ from: z.number().optional().describe('Start time (Unix timestamp)'),
179
+ to: z.number().optional().describe('End time (Unix timestamp)'),
180
+ interval: z.enum(['1m', '5m', '15m', '30m', '1h', '4h', '8h', '1d', '7d']).optional(),
181
+ limit: z.number().int().optional(),
182
+ }, async ({ settle, contract, from, to, interval, limit }) => {
180
183
  try {
181
- requireAuth();
182
- const order = { contract, size, price };
183
- order.tif = tif ?? (price === '0' ? 'ioc' : 'gtc');
184
- if (reduce_only !== undefined)
185
- order.reduceOnly = reduce_only;
186
- if (close !== undefined)
187
- order.close = close;
188
- if (text)
189
- order.text = text;
190
- const { body } = await new FuturesApi(createClient()).createFuturesOrder(settle, order, {});
184
+ const opts = {};
185
+ if (from !== undefined)
186
+ opts.from = from;
187
+ if (to !== undefined)
188
+ opts.to = to;
189
+ if (interval)
190
+ opts.interval = interval;
191
+ if (limit !== undefined)
192
+ opts.limit = limit;
193
+ const { body } = await new FuturesApi(createClient()).listFuturesPremiumIndex(settle, contract, opts);
191
194
  return textContent(body);
192
195
  }
193
196
  catch (e) {
194
197
  return errorContent(e);
195
198
  }
196
199
  });
197
- server.tool('cex_futures_get_futures_order', 'Get a futures order by ID (requires authentication)', {
200
+ server.tool('cex_futures_list_batch_futures_funding_rates', 'Get current funding rates for multiple contracts in one request', {
198
201
  settle: settleSchema,
199
- order_id: z.string().describe('Order ID'),
200
- }, async ({ settle, order_id }) => {
202
+ contracts: z.array(z.string()).describe('List of contract names e.g. ["BTC_USDT","ETH_USDT"]'),
203
+ }, async ({ settle, contracts }) => {
201
204
  try {
202
- requireAuth();
203
- const { body } = await new FuturesApi(createClient()).getFuturesOrder(settle, order_id);
205
+ const req = new BatchFundingRatesRequest();
206
+ req.contracts = contracts;
207
+ const { body } = await new FuturesApi(createClient()).listBatchFuturesFundingRates(settle, req);
204
208
  return textContent(body);
205
209
  }
206
210
  catch (e) {
207
211
  return errorContent(e);
208
212
  }
209
213
  });
210
- server.tool('cex_futures_cancel_futures_order', 'Cancel a futures order (requires authentication) — always confirm with the user before calling this tool', {
214
+ server.tool('cex_futures_list_futures_insurance_ledger', 'Get futures insurance fund history', {
211
215
  settle: settleSchema,
212
- order_id: z.string().describe('Order ID'),
213
- }, async ({ settle, order_id }) => {
216
+ limit: z.number().int().optional(),
217
+ }, async ({ settle, limit }) => {
214
218
  try {
215
- requireAuth();
216
- const { body } = await new FuturesApi(createClient()).cancelFuturesOrder(settle, order_id, {});
219
+ const opts = {};
220
+ if (limit !== undefined)
221
+ opts.limit = limit;
222
+ const { body } = await new FuturesApi(createClient()).listFuturesInsuranceLedger(settle, opts);
217
223
  return textContent(body);
218
224
  }
219
225
  catch (e) {
220
226
  return errorContent(e);
221
227
  }
222
228
  });
223
- server.tool('cex_futures_amend_futures_order', 'Amend an open futures order (requires authentication) always confirm the new values with the user before calling this tool', {
229
+ server.tool('cex_futures_get_index_constituents', 'Get constituent assets and weights for a futures index', {
224
230
  settle: settleSchema,
225
- order_id: z.string().describe('Order ID'),
226
- size: z.string().optional().describe('New order size'),
227
- price: z.string().optional().describe('New order price'),
228
- }, async ({ settle, order_id, size, price }) => {
231
+ index: z.string().describe('Index name e.g. BTC_USDT'),
232
+ }, async ({ settle, index }) => {
229
233
  try {
230
- requireAuth();
231
- const amendment = {};
232
- if (size !== undefined)
233
- amendment.size = size;
234
- if (price)
235
- amendment.price = price;
236
- const { body } = await new FuturesApi(createClient()).amendFuturesOrder(settle, order_id, amendment, {});
234
+ const { body } = await new FuturesApi(createClient()).getIndexConstituents(settle, index);
237
235
  return textContent(body);
238
236
  }
239
237
  catch (e) {
240
238
  return errorContent(e);
241
239
  }
242
240
  });
243
- server.tool('cex_futures_list_futures_my_trades', 'Get personal futures trading history (requires authentication)', {
241
+ server.tool('cex_futures_list_liquidated_orders', 'Get public market-wide liquidation order history', {
244
242
  settle: settleSchema,
245
243
  contract: z.string().optional().describe('Filter by contract'),
244
+ from: z.number().optional().describe('Start time (Unix timestamp)'),
245
+ to: z.number().optional().describe('End time (Unix timestamp)'),
246
246
  limit: z.number().int().optional(),
247
- offset: z.number().int().optional(),
248
- }, async ({ settle, contract, limit, offset }) => {
247
+ }, async ({ settle, contract, from, to, limit }) => {
249
248
  try {
250
- requireAuth();
251
249
  const opts = {};
252
250
  if (contract)
253
251
  opts.contract = contract;
252
+ if (from !== undefined)
253
+ opts.from = from;
254
+ if (to !== undefined)
255
+ opts.to = to;
254
256
  if (limit !== undefined)
255
257
  opts.limit = limit;
256
- if (offset !== undefined)
257
- opts.offset = offset;
258
- const { body } = await new FuturesApi(createClient()).getMyTrades(settle, opts);
258
+ const { body } = await new FuturesApi(createClient()).listLiquidatedOrders(settle, opts);
259
259
  return textContent(body);
260
260
  }
261
261
  catch (e) {
262
262
  return errorContent(e);
263
263
  }
264
264
  });
265
- server.tool('cex_futures_list_position_close', 'List position close history (requires authentication)', {
265
+ // ── Private tools ─────────────────────────────────────────────────────────
266
+ server.tool('cex_futures_get_futures_accounts', 'Get futures account balances (requires authentication)', { settle: settleSchema }, async ({ settle }) => {
267
+ try {
268
+ requireAuth();
269
+ const { body } = await new FuturesApi(createClient()).listFuturesAccounts(settle);
270
+ return textContent(body);
271
+ }
272
+ catch (e) {
273
+ return errorContent(e);
274
+ }
275
+ });
276
+ server.tool('cex_futures_list_futures_account_book', 'Get futures account transaction/ledger history (requires authentication)', {
266
277
  settle: settleSchema,
267
- contract: z.string().optional(),
278
+ contract: z.string().optional().describe('Filter by contract'),
279
+ from: z.number().optional().describe('Start time (Unix timestamp)'),
280
+ to: z.number().optional().describe('End time (Unix timestamp)'),
268
281
  limit: z.number().int().optional(),
269
- }, async ({ settle, contract, limit }) => {
282
+ offset: z.number().int().optional(),
283
+ type: z.string().optional().describe('Entry type filter e.g. dnw, pnl, fee, refr, fund'),
284
+ }, async ({ settle, contract, from, to, limit, offset, type }) => {
270
285
  try {
271
286
  requireAuth();
272
287
  const opts = {};
273
288
  if (contract)
274
289
  opts.contract = contract;
290
+ if (from !== undefined)
291
+ opts.from = from;
292
+ if (to !== undefined)
293
+ opts.to = to;
275
294
  if (limit !== undefined)
276
295
  opts.limit = limit;
277
- const { body } = await new FuturesApi(createClient()).listPositionClose(settle, opts);
296
+ if (offset !== undefined)
297
+ opts.offset = offset;
298
+ if (type)
299
+ opts.type = type;
300
+ const { body } = await new FuturesApi(createClient()).listFuturesAccountBook(settle, opts);
278
301
  return textContent(body);
279
302
  }
280
303
  catch (e) {
281
304
  return errorContent(e);
282
305
  }
283
306
  });
284
- server.tool('cex_futures_list_price_triggered_orders', 'List futures price-triggered orders (requires authentication)', {
307
+ server.tool('cex_futures_list_futures_positions', 'List all open futures positions (requires authentication)', {
285
308
  settle: settleSchema,
286
- status: z.enum(['open', 'finished']),
287
- contract: z.string().optional(),
309
+ holding: z.boolean().optional().describe('Only return positions with non-zero size'),
288
310
  limit: z.number().int().optional(),
289
- }, async ({ settle, status, contract, limit }) => {
311
+ offset: z.number().int().optional(),
312
+ }, async ({ settle, holding, limit, offset }) => {
290
313
  try {
291
314
  requireAuth();
292
315
  const opts = {};
293
- if (contract)
294
- opts.contract = contract;
316
+ if (holding !== undefined)
317
+ opts.holding = holding;
295
318
  if (limit !== undefined)
296
319
  opts.limit = limit;
297
- const { body } = await new FuturesApi(createClient()).listPriceTriggeredOrders(settle, status, opts);
320
+ if (offset !== undefined)
321
+ opts.offset = offset;
322
+ const { body } = await new FuturesApi(createClient()).listPositions(settle, opts);
298
323
  return textContent(body);
299
324
  }
300
325
  catch (e) {
301
326
  return errorContent(e);
302
327
  }
303
328
  });
304
- // ── Additional public tools ────────────────────────────────────────────────
305
- server.tool('cex_futures_get_futures_trades', 'Get recent public trades for a futures contract', {
329
+ server.tool('cex_futures_list_positions_timerange', 'Get position history for a contract filtered by time range (requires authentication)', {
306
330
  settle: settleSchema,
307
331
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
308
- limit: z.number().int().optional(),
309
332
  from: z.number().optional().describe('Start time (Unix timestamp)'),
310
333
  to: z.number().optional().describe('End time (Unix timestamp)'),
311
- }, async ({ settle, contract, limit, from, to }) => {
334
+ limit: z.number().int().optional(),
335
+ offset: z.number().int().optional(),
336
+ }, async ({ settle, contract, from, to, limit, offset }) => {
312
337
  try {
338
+ requireAuth();
313
339
  const opts = {};
314
- if (limit !== undefined)
315
- opts.limit = limit;
316
340
  if (from !== undefined)
317
341
  opts.from = from;
318
342
  if (to !== undefined)
319
343
  opts.to = to;
320
- const { body } = await new FuturesApi(createClient()).listFuturesTrades(settle, contract, opts);
344
+ if (limit !== undefined)
345
+ opts.limit = limit;
346
+ if (offset !== undefined)
347
+ opts.offset = offset;
348
+ const { body } = await new FuturesApi(createClient()).listPositionsTimerange(settle, contract, opts);
321
349
  return textContent(body);
322
350
  }
323
351
  catch (e) {
324
352
  return errorContent(e);
325
353
  }
326
354
  });
327
- server.tool('cex_futures_list_contract_stats', 'Get contract statistics (open interest, long/short ratio, etc.)', {
355
+ server.tool('cex_futures_get_futures_position', 'Get a single futures position (requires authentication)', {
328
356
  settle: settleSchema,
329
357
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
330
- from: z.number().optional().describe('Start time (Unix timestamp)'),
331
- interval: z.enum(['5m', '15m', '30m', '1h', '4h', '1d']).optional(),
332
- limit: z.number().int().optional(),
333
- }, async ({ settle, contract, from, interval, limit }) => {
358
+ }, async ({ settle, contract }) => {
334
359
  try {
335
- const opts = {};
336
- if (from !== undefined)
337
- opts.from = from;
338
- if (interval)
339
- opts.interval = interval;
340
- if (limit !== undefined)
341
- opts.limit = limit;
342
- const { body } = await new FuturesApi(createClient()).listContractStats(settle, contract, opts);
360
+ requireAuth();
361
+ const { body } = await new FuturesApi(createClient()).getPosition(settle, contract);
343
362
  return textContent(body);
344
363
  }
345
364
  catch (e) {
346
365
  return errorContent(e);
347
366
  }
348
367
  });
349
- server.tool('cex_futures_get_futures_premium_index', 'Get premium index (mark price minus index price) history for a contract', {
368
+ server.tool('cex_futures_get_leverage', 'Get current leverage for a futures position (requires authentication)', {
350
369
  settle: settleSchema,
351
370
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
352
- from: z.number().optional().describe('Start time (Unix timestamp)'),
353
- to: z.number().optional().describe('End time (Unix timestamp)'),
354
- interval: z.enum(['1m', '5m', '15m', '30m', '1h', '4h', '8h', '1d', '7d']).optional(),
355
- limit: z.number().int().optional(),
356
- }, async ({ settle, contract, from, to, interval, limit }) => {
371
+ pos_margin_mode: z.string().optional().describe('Position margin mode filter'),
372
+ dual_side: z.string().optional().describe('Dual side filter: long or short'),
373
+ }, async ({ settle, contract, pos_margin_mode, dual_side }) => {
357
374
  try {
375
+ requireAuth();
358
376
  const opts = {};
359
- if (from !== undefined)
360
- opts.from = from;
361
- if (to !== undefined)
362
- opts.to = to;
363
- if (interval)
364
- opts.interval = interval;
365
- if (limit !== undefined)
366
- opts.limit = limit;
367
- const { body } = await new FuturesApi(createClient()).listFuturesPremiumIndex(settle, contract, opts);
377
+ if (pos_margin_mode)
378
+ opts.posMarginMode = pos_margin_mode;
379
+ if (dual_side)
380
+ opts.dualSide = dual_side;
381
+ const { body } = await new FuturesApi(createClient()).getLeverage(settle, contract, opts);
368
382
  return textContent(body);
369
383
  }
370
384
  catch (e) {
371
385
  return errorContent(e);
372
386
  }
373
387
  });
374
- // ── Additional private tools ───────────────────────────────────────────────
375
- server.tool('cex_futures_list_futures_account_book', 'Get futures account transaction/ledger history (requires authentication)', {
388
+ server.tool('cex_futures_get_futures_fee', 'Get futures trading fee rates (requires authentication)', {
376
389
  settle: settleSchema,
377
390
  contract: z.string().optional().describe('Filter by contract'),
378
- from: z.number().optional().describe('Start time (Unix timestamp)'),
379
- to: z.number().optional().describe('End time (Unix timestamp)'),
380
- limit: z.number().int().optional(),
381
- offset: z.number().int().optional(),
382
- type: z.string().optional().describe('Entry type filter e.g. dnw, pnl, fee, refr, fund'),
383
- }, async ({ settle, contract, from, to, limit, offset, type }) => {
391
+ }, async ({ settle, contract }) => {
384
392
  try {
385
393
  requireAuth();
386
394
  const opts = {};
387
395
  if (contract)
388
396
  opts.contract = contract;
389
- if (from !== undefined)
390
- opts.from = from;
391
- if (to !== undefined)
392
- opts.to = to;
393
- if (limit !== undefined)
397
+ const { body } = await new FuturesApi(createClient()).getFuturesFee(settle, opts);
398
+ return textContent(body);
399
+ }
400
+ catch (e) {
401
+ return errorContent(e);
402
+ }
403
+ });
404
+ server.tool('cex_futures_list_futures_risk_limit_tiers', 'Get risk limit tiers for a futures contract', {
405
+ settle: settleSchema,
406
+ contract: z.string().optional().describe('Contract name e.g. BTC_USDT'),
407
+ limit: z.number().int().optional(),
408
+ offset: z.number().int().optional(),
409
+ }, async ({ settle, contract, limit, offset }) => {
410
+ try {
411
+ const opts = {};
412
+ if (contract)
413
+ opts.contract = contract;
414
+ if (limit !== undefined)
394
415
  opts.limit = limit;
395
416
  if (offset !== undefined)
396
417
  opts.offset = offset;
397
- if (type)
398
- opts.type = type;
399
- const { body } = await new FuturesApi(createClient()).listFuturesAccountBook(settle, opts);
418
+ const { body } = await new FuturesApi(createClient()).listFuturesRiskLimitTiers(settle, opts);
400
419
  return textContent(body);
401
420
  }
402
421
  catch (e) {
403
422
  return errorContent(e);
404
423
  }
405
424
  });
406
- server.tool('cex_futures_get_futures_fee', 'Get futures trading fee rates (requires authentication)', {
425
+ server.tool('cex_futures_get_futures_risk_limit_table', 'Get a specific risk limit tier table by table ID (requires authentication)', {
426
+ settle: settleSchema,
427
+ table_id: z.string().describe('Risk limit table ID'),
428
+ }, async ({ settle, table_id }) => {
429
+ try {
430
+ requireAuth();
431
+ const { body } = await new FuturesApi(createClient()).getFuturesRiskLimitTable(settle, table_id);
432
+ return textContent(body);
433
+ }
434
+ catch (e) {
435
+ return errorContent(e);
436
+ }
437
+ });
438
+ server.tool('cex_futures_list_futures_orders', 'List futures orders (requires authentication)', {
407
439
  settle: settleSchema,
440
+ status: z.enum(['open', 'finished']).describe('Order status'),
408
441
  contract: z.string().optional().describe('Filter by contract'),
409
- }, async ({ settle, contract }) => {
442
+ limit: z.number().int().optional(),
443
+ offset: z.number().int().optional(),
444
+ last_id: z.string().optional().describe('Pagination cursor — return records after this order ID'),
445
+ }, async ({ settle, status, contract, limit, offset, last_id }) => {
410
446
  try {
411
447
  requireAuth();
412
448
  const opts = {};
413
449
  if (contract)
414
450
  opts.contract = contract;
415
- const { body } = await new FuturesApi(createClient()).getFuturesFee(settle, opts);
451
+ if (limit !== undefined)
452
+ opts.limit = limit;
453
+ if (offset !== undefined)
454
+ opts.offset = offset;
455
+ if (last_id)
456
+ opts.lastId = last_id;
457
+ const { body } = await new FuturesApi(createClient()).listFuturesOrders(settle, status, opts);
416
458
  return textContent(body);
417
459
  }
418
460
  catch (e) {
419
461
  return errorContent(e);
420
462
  }
421
463
  });
422
- server.tool('cex_futures_get_leverage', 'Get current leverage for a futures position (requires authentication)', {
464
+ server.tool('cex_futures_create_futures_order', 'Create a futures order (requires authentication) — always confirm the details with the user before calling this tool', {
423
465
  settle: settleSchema,
424
466
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
425
- }, async ({ settle, contract }) => {
467
+ size: z.string().describe('Order size in contracts (negative = short)'),
468
+ price: z.string().describe('Order price (0 for market orders)'),
469
+ tif: z.enum(['gtc', 'ioc', 'poc', 'fok']).optional().describe('Time in force'),
470
+ reduce_only: z.boolean().optional().describe('Reduce-only order'),
471
+ close: z.boolean().optional().describe('Close position'),
472
+ text: z.string().optional().describe('Custom reference text'),
473
+ }, async ({ settle, contract, size, price, tif, reduce_only, close, text }) => {
426
474
  try {
427
475
  requireAuth();
428
- const { body } = await new FuturesApi(createClient()).getLeverage(settle, contract, {});
476
+ const order = { contract, size, price };
477
+ order.tif = tif ?? (price === '0' ? 'ioc' : 'gtc');
478
+ if (reduce_only !== undefined)
479
+ order.reduceOnly = reduce_only;
480
+ if (close !== undefined)
481
+ order.close = close;
482
+ if (text)
483
+ order.text = text;
484
+ const { body } = await new FuturesApi(createClient()).createFuturesOrder(settle, order, {});
429
485
  return textContent(body);
430
486
  }
431
487
  catch (e) {
432
488
  return errorContent(e);
433
489
  }
434
490
  });
435
- server.tool('cex_futures_update_futures_position_leverage', 'Update leverage for a futures position (requires authentication) — always confirm the new leverage with the user before calling this tool', {
491
+ server.tool('cex_futures_create_futures_bbo_order', 'Create a Best-Bid/Offer futures order (requires authentication) — always confirm details with the user before calling this tool', {
436
492
  settle: settleSchema,
437
493
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
438
- leverage: z.string().describe('New leverage value; 0 for cross-margin mode'),
439
- cross_leverage_limit: z.string().optional().describe('Cross-margin leverage limit (only when leverage=0)'),
440
- }, async ({ settle, contract, leverage, cross_leverage_limit }) => {
494
+ size: z.number().int().describe('Order size in contracts (negative = short)'),
495
+ direction: z.string().describe('Order direction: long or short'),
496
+ level: z.number().int().describe('BBO level (1 = best bid/offer)'),
497
+ tif: z.enum(['gtc', 'ioc', 'poc', 'fok']).optional(),
498
+ reduce_only: z.boolean().optional(),
499
+ close: z.boolean().optional(),
500
+ text: z.string().optional(),
501
+ }, async ({ settle, contract, size, direction, level, tif, reduce_only, close, text }) => {
441
502
  try {
442
503
  requireAuth();
443
- const opts = {};
444
- if (cross_leverage_limit)
445
- opts.crossLeverageLimit = cross_leverage_limit;
446
- const { body } = await new FuturesApi(createClient()).updatePositionLeverage(settle, contract, leverage, opts);
504
+ const order = new FuturesBBOOrder();
505
+ order.contract = contract;
506
+ order.size = size;
507
+ order.direction = direction;
508
+ order.level = level;
509
+ if (tif !== undefined)
510
+ order.tif = tif;
511
+ if (reduce_only !== undefined)
512
+ order.reduceOnly = reduce_only;
513
+ if (close !== undefined)
514
+ order.close = close;
515
+ if (text)
516
+ order.text = text;
517
+ const { body } = await new FuturesApi(createClient()).createFuturesBBOOrder(settle, order, {});
447
518
  return textContent(body);
448
519
  }
449
520
  catch (e) {
450
521
  return errorContent(e);
451
522
  }
452
523
  });
453
- server.tool('cex_futures_update_futures_position_margin', 'Add or reduce margin for a futures position (requires authentication) — always confirm the amount with the user before calling this tool', {
524
+ server.tool('cex_futures_get_futures_order', 'Get a futures order by ID (requires authentication)', {
454
525
  settle: settleSchema,
455
- contract: z.string().describe('Contract name e.g. BTC_USDT'),
456
- change: z.string().describe('Margin change amount; positive to add, negative to reduce'),
457
- }, async ({ settle, contract, change }) => {
526
+ order_id: z.string().describe('Order ID'),
527
+ }, async ({ settle, order_id }) => {
458
528
  try {
459
529
  requireAuth();
460
- const { body } = await new FuturesApi(createClient()).updatePositionMargin(settle, contract, change);
530
+ const { body } = await new FuturesApi(createClient()).getFuturesOrder(settle, order_id);
461
531
  return textContent(body);
462
532
  }
463
533
  catch (e) {
464
534
  return errorContent(e);
465
535
  }
466
536
  });
467
- server.tool('cex_futures_update_futures_position_risk_limit', 'Update the risk limit for a futures position (requires authentication)', {
537
+ server.tool('cex_futures_amend_futures_order', 'Amend an open futures order (requires authentication) — always confirm the new values with the user before calling this tool', {
468
538
  settle: settleSchema,
469
- contract: z.string().describe('Contract name e.g. BTC_USDT'),
470
- risk_limit: z.string().describe('New risk limit value'),
471
- }, async ({ settle, contract, risk_limit }) => {
539
+ order_id: z.string().describe('Order ID'),
540
+ size: z.string().optional().describe('New order size'),
541
+ price: z.string().optional().describe('New order price'),
542
+ }, async ({ settle, order_id, size, price }) => {
472
543
  try {
473
544
  requireAuth();
474
- const { body } = await new FuturesApi(createClient()).updatePositionRiskLimit(settle, contract, risk_limit);
545
+ const amendment = {};
546
+ if (size !== undefined)
547
+ amendment.size = size;
548
+ if (price)
549
+ amendment.price = price;
550
+ const { body } = await new FuturesApi(createClient()).amendFuturesOrder(settle, order_id, amendment, {});
551
+ return textContent(body);
552
+ }
553
+ catch (e) {
554
+ return errorContent(e);
555
+ }
556
+ });
557
+ server.tool('cex_futures_cancel_futures_order', 'Cancel a futures order (requires authentication) — always confirm with the user before calling this tool', {
558
+ settle: settleSchema,
559
+ order_id: z.string().describe('Order ID'),
560
+ }, async ({ settle, order_id }) => {
561
+ try {
562
+ requireAuth();
563
+ const { body } = await new FuturesApi(createClient()).cancelFuturesOrder(settle, order_id, {});
475
564
  return textContent(body);
476
565
  }
477
566
  catch (e) {
@@ -482,7 +571,9 @@ export function registerFuturesTools(server) {
482
571
  settle: settleSchema,
483
572
  contract: z.string().optional().describe('Only cancel orders for this contract'),
484
573
  side: z.enum(['ask', 'bid']).optional().describe('Only cancel ask (sell) or bid (buy) orders'),
485
- }, async ({ settle, contract, side }) => {
574
+ exclude_reduce_only: z.boolean().optional().describe('Exclude reduce-only orders from cancellation'),
575
+ text: z.string().optional().describe('Only cancel orders with this text label'),
576
+ }, async ({ settle, contract, side, exclude_reduce_only, text }) => {
486
577
  try {
487
578
  requireAuth();
488
579
  const opts = {};
@@ -490,6 +581,10 @@ export function registerFuturesTools(server) {
490
581
  opts.contract = contract;
491
582
  if (side)
492
583
  opts.side = side;
584
+ if (exclude_reduce_only !== undefined)
585
+ opts.excludeReduceOnly = exclude_reduce_only;
586
+ if (text)
587
+ opts.text = text;
493
588
  const { body } = await new FuturesApi(createClient()).cancelFuturesOrders(settle, opts);
494
589
  return textContent(body);
495
590
  }
@@ -542,6 +637,39 @@ export function registerFuturesTools(server) {
542
637
  return errorContent(e);
543
638
  }
544
639
  });
640
+ server.tool('cex_futures_amend_batch_futures_orders', 'Amend multiple futures orders in a single request (requires authentication) — always confirm the new values with the user before calling this tool', {
641
+ settle: settleSchema,
642
+ orders: z.array(z.object({
643
+ order_id: z.number().int().optional().describe('Order ID to amend'),
644
+ size: z.string().optional().describe('New size'),
645
+ price: z.string().optional().describe('New price'),
646
+ text: z.string().optional(),
647
+ amend_text: z.string().optional().describe('Reason for amendment'),
648
+ })).describe('Array of order amendments'),
649
+ }, async ({ settle, orders }) => {
650
+ try {
651
+ requireAuth();
652
+ const reqs = orders.map(o => {
653
+ const req = new BatchAmendOrderReq();
654
+ if (o.order_id !== undefined)
655
+ req.orderId = o.order_id;
656
+ if (o.size)
657
+ req.size = o.size;
658
+ if (o.price)
659
+ req.price = o.price;
660
+ if (o.text)
661
+ req.text = o.text;
662
+ if (o.amend_text)
663
+ req.amendText = o.amend_text;
664
+ return req;
665
+ });
666
+ const { body } = await new FuturesApi(createClient()).amendBatchFutureOrders(settle, reqs, {});
667
+ return textContent(body);
668
+ }
669
+ catch (e) {
670
+ return errorContent(e);
671
+ }
672
+ });
545
673
  server.tool('cex_futures_get_futures_orders_with_time_range', 'Get futures orders filtered by time range (requires authentication)', {
546
674
  settle: settleSchema,
547
675
  contract: z.string().optional().describe('Filter by contract'),
@@ -570,6 +698,34 @@ export function registerFuturesTools(server) {
570
698
  return errorContent(e);
571
699
  }
572
700
  });
701
+ server.tool('cex_futures_list_futures_my_trades', 'Get personal futures trading history (requires authentication)', {
702
+ settle: settleSchema,
703
+ contract: z.string().optional().describe('Filter by contract'),
704
+ order: z.number().int().optional().describe('Filter by order ID'),
705
+ limit: z.number().int().optional(),
706
+ offset: z.number().int().optional(),
707
+ last_id: z.string().optional().describe('Pagination cursor — return records after this trade ID'),
708
+ }, async ({ settle, contract, order, limit, offset, last_id }) => {
709
+ try {
710
+ requireAuth();
711
+ const opts = {};
712
+ if (contract)
713
+ opts.contract = contract;
714
+ if (order !== undefined)
715
+ opts.order = order;
716
+ if (limit !== undefined)
717
+ opts.limit = limit;
718
+ if (offset !== undefined)
719
+ opts.offset = offset;
720
+ if (last_id)
721
+ opts.lastId = last_id;
722
+ const { body } = await new FuturesApi(createClient()).getMyTrades(settle, opts);
723
+ return textContent(body);
724
+ }
725
+ catch (e) {
726
+ return errorContent(e);
727
+ }
728
+ });
573
729
  server.tool('cex_futures_get_futures_my_trades_timerange', 'Get personal futures trade history filtered by time range (requires authentication)', {
574
730
  settle: settleSchema,
575
731
  contract: z.string().optional().describe('Filter by contract'),
@@ -601,6 +757,40 @@ export function registerFuturesTools(server) {
601
757
  return errorContent(e);
602
758
  }
603
759
  });
760
+ server.tool('cex_futures_list_position_close', 'List position close history (requires authentication)', {
761
+ settle: settleSchema,
762
+ contract: z.string().optional(),
763
+ limit: z.number().int().optional(),
764
+ offset: z.number().int().optional(),
765
+ from: z.number().optional().describe('Start time (Unix timestamp)'),
766
+ to: z.number().optional().describe('End time (Unix timestamp)'),
767
+ side: z.string().optional().describe('Position side: long or short'),
768
+ pnl: z.string().optional().describe('Filter by profit/loss: profit or loss'),
769
+ }, async ({ settle, contract, limit, offset, from, to, side, pnl }) => {
770
+ try {
771
+ requireAuth();
772
+ const opts = {};
773
+ if (contract)
774
+ opts.contract = contract;
775
+ if (limit !== undefined)
776
+ opts.limit = limit;
777
+ if (offset !== undefined)
778
+ opts.offset = offset;
779
+ if (from !== undefined)
780
+ opts.from = from;
781
+ if (to !== undefined)
782
+ opts.to = to;
783
+ if (side)
784
+ opts.side = side;
785
+ if (pnl)
786
+ opts.pnl = pnl;
787
+ const { body } = await new FuturesApi(createClient()).listPositionClose(settle, opts);
788
+ return textContent(body);
789
+ }
790
+ catch (e) {
791
+ return errorContent(e);
792
+ }
793
+ });
604
794
  server.tool('cex_futures_list_futures_liq_orders', 'Get personal futures liquidation history (requires authentication)', {
605
795
  settle: settleSchema,
606
796
  contract: z.string().optional(),
@@ -608,7 +798,8 @@ export function registerFuturesTools(server) {
608
798
  to: z.number().optional().describe('End time (Unix timestamp)'),
609
799
  limit: z.number().int().optional(),
610
800
  offset: z.number().int().optional(),
611
- }, async ({ settle, contract, from, to, limit, offset }) => {
801
+ at: z.number().optional().describe('Timestamp snapshot return liquidations at this time'),
802
+ }, async ({ settle, contract, from, to, limit, offset, at }) => {
612
803
  try {
613
804
  requireAuth();
614
805
  const opts = {};
@@ -622,6 +813,8 @@ export function registerFuturesTools(server) {
622
813
  opts.limit = limit;
623
814
  if (offset !== undefined)
624
815
  opts.offset = offset;
816
+ if (at !== undefined)
817
+ opts.at = at;
625
818
  const { body } = await new FuturesApi(createClient()).listLiquidates(settle, opts);
626
819
  return textContent(body);
627
820
  }
@@ -629,98 +822,130 @@ export function registerFuturesTools(server) {
629
822
  return errorContent(e);
630
823
  }
631
824
  });
632
- server.tool('cex_futures_get_futures_price_triggered_order', 'Get details of a futures price-triggered order (requires authentication)', {
825
+ server.tool('cex_futures_list_auto_deleverages', 'Get personal auto-deleverage history (requires authentication)', {
633
826
  settle: settleSchema,
634
- order_id: z.string().describe('Order ID'),
635
- }, async ({ settle, order_id }) => {
827
+ contract: z.string().optional(),
828
+ from: z.number().optional().describe('Start time (Unix timestamp)'),
829
+ to: z.number().optional().describe('End time (Unix timestamp)'),
830
+ limit: z.number().int().optional(),
831
+ offset: z.number().int().optional(),
832
+ at: z.number().optional().describe('Timestamp snapshot'),
833
+ }, async ({ settle, contract, from, to, limit, offset, at }) => {
636
834
  try {
637
835
  requireAuth();
638
- const { body } = await new FuturesApi(createClient()).getPriceTriggeredOrder(settle, order_id);
836
+ const opts = {};
837
+ if (contract)
838
+ opts.contract = contract;
839
+ if (from !== undefined)
840
+ opts.from = from;
841
+ if (to !== undefined)
842
+ opts.to = to;
843
+ if (limit !== undefined)
844
+ opts.limit = limit;
845
+ if (offset !== undefined)
846
+ opts.offset = offset;
847
+ if (at !== undefined)
848
+ opts.at = at;
849
+ const { body } = await new FuturesApi(createClient()).listAutoDeleverages(settle, opts);
639
850
  return textContent(body);
640
851
  }
641
852
  catch (e) {
642
853
  return errorContent(e);
643
854
  }
644
855
  });
645
- server.tool('cex_futures_create_futures_price_triggered_order', 'Create a futures price-triggered order (requires authentication) — always confirm the details with the user before calling this tool', {
856
+ server.tool('cex_futures_update_futures_position_leverage', 'Update leverage for a futures position (requires authentication) — always confirm the new leverage with the user before calling this tool', {
646
857
  settle: settleSchema,
647
858
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
648
- trigger_price: z.string().describe('Price that activates the order'),
649
- trigger_rule: z.enum(['>=', '<=']).describe('>= fires when price rises to trigger_price; <= fires when it drops'),
650
- trigger_expiration: z.number().int().optional().describe('Trigger expiration in seconds'),
651
- order_size: z.number().describe('Order size (negative = short)'),
652
- order_price: z.string().describe('Execution price; "0" for market'),
653
- order_tif: z.enum(['gtc', 'ioc']).optional(),
654
- order_reduce_only: z.boolean().optional(),
655
- order_close: z.boolean().optional(),
656
- order_text: z.string().optional(),
657
- }, async ({ settle, contract, trigger_price, trigger_rule, trigger_expiration, order_size, order_price, order_tif, order_reduce_only, order_close, order_text }) => {
859
+ leverage: z.string().describe('New leverage value; 0 for cross-margin mode'),
860
+ cross_leverage_limit: z.string().optional().describe('Cross-margin leverage limit (only when leverage=0)'),
861
+ }, async ({ settle, contract, leverage, cross_leverage_limit }) => {
658
862
  try {
659
863
  requireAuth();
660
- const trigger = { price: trigger_price, rule: trigger_rule === '>=' ? 1 : 2 };
661
- if (trigger_expiration !== undefined)
662
- trigger.expiration = trigger_expiration;
663
- const initial = { contract, size: order_size, price: order_price };
664
- if (order_tif)
665
- initial.tif = order_tif;
666
- if (order_reduce_only !== undefined)
667
- initial.reduceOnly = order_reduce_only;
668
- if (order_close !== undefined)
669
- initial.close = order_close;
670
- if (order_text)
671
- initial.text = order_text;
672
- const { body } = await new FuturesApi(createClient()).createPriceTriggeredOrder(settle, { initial, trigger });
864
+ const opts = {};
865
+ if (cross_leverage_limit)
866
+ opts.crossLeverageLimit = cross_leverage_limit;
867
+ const { body } = await new FuturesApi(createClient()).updatePositionLeverage(settle, contract, leverage, opts);
673
868
  return textContent(body);
674
869
  }
675
870
  catch (e) {
676
871
  return errorContent(e);
677
872
  }
678
873
  });
679
- server.tool('cex_futures_cancel_futures_price_triggered_order', 'Cancel a single futures price-triggered order (requires authentication) — always confirm with the user before calling this tool', {
874
+ server.tool('cex_futures_update_futures_contract_position_leverage', 'Update position leverage with explicit margin mode (requires authentication) — always confirm with the user before calling this tool', {
680
875
  settle: settleSchema,
681
- order_id: z.string().describe('Order ID'),
682
- }, async ({ settle, order_id }) => {
876
+ contract: z.string().describe('Contract name e.g. BTC_USDT'),
877
+ leverage: z.string().describe('New leverage value'),
878
+ margin_mode: z.string().describe('Margin mode: isolated or cross'),
879
+ dual_side: z.string().optional().describe('Dual side: long or short'),
880
+ }, async ({ settle, contract, leverage, margin_mode, dual_side }) => {
683
881
  try {
684
882
  requireAuth();
685
- const { body } = await new FuturesApi(createClient()).cancelPriceTriggeredOrder(settle, order_id);
883
+ const opts = {};
884
+ if (dual_side)
885
+ opts.dualSide = dual_side;
886
+ const { body } = await new FuturesApi(createClient()).updateContractPositionLeverage(settle, contract, leverage, margin_mode, opts);
686
887
  return textContent(body);
687
888
  }
688
889
  catch (e) {
689
890
  return errorContent(e);
690
891
  }
691
892
  });
692
- server.tool('cex_futures_cancel_futures_price_triggered_order_list', 'Cancel all futures price-triggered orders (requires authentication) — always confirm with the user before calling this tool', {
893
+ server.tool('cex_futures_update_futures_position_margin', 'Add or reduce margin for a futures position (requires authentication) — always confirm the amount with the user before calling this tool', {
693
894
  settle: settleSchema,
694
- contract: z.string().optional().describe('Only cancel orders for this contract'),
695
- }, async ({ settle, contract }) => {
895
+ contract: z.string().describe('Contract name e.g. BTC_USDT'),
896
+ change: z.string().describe('Margin change amount; positive to add, negative to reduce'),
897
+ }, async ({ settle, contract, change }) => {
696
898
  try {
697
899
  requireAuth();
698
- const opts = {};
699
- if (contract)
700
- opts.contract = contract;
701
- const { body } = await new FuturesApi(createClient()).cancelPriceTriggeredOrderList(settle, opts);
900
+ const { body } = await new FuturesApi(createClient()).updatePositionMargin(settle, contract, change);
702
901
  return textContent(body);
703
902
  }
704
903
  catch (e) {
705
904
  return errorContent(e);
706
905
  }
707
906
  });
708
- server.tool('cex_futures_list_futures_risk_limit_tiers', 'Get risk limit tiers for a futures contract (requires authentication)', {
907
+ server.tool('cex_futures_update_futures_position_risk_limit', 'Update the risk limit for a futures position (requires authentication)', {
709
908
  settle: settleSchema,
710
- contract: z.string().optional().describe('Contract name e.g. BTC_USDT'),
711
- limit: z.number().int().optional(),
712
- offset: z.number().int().optional(),
713
- }, async ({ settle, contract, limit, offset }) => {
909
+ contract: z.string().describe('Contract name e.g. BTC_USDT'),
910
+ risk_limit: z.string().describe('New risk limit value'),
911
+ }, async ({ settle, contract, risk_limit }) => {
714
912
  try {
715
913
  requireAuth();
716
- const opts = {};
717
- if (contract)
718
- opts.contract = contract;
719
- if (limit !== undefined)
720
- opts.limit = limit;
721
- if (offset !== undefined)
722
- opts.offset = offset;
723
- const { body } = await new FuturesApi(createClient()).listFuturesRiskLimitTiers(settle, opts);
914
+ const { body } = await new FuturesApi(createClient()).updatePositionRiskLimit(settle, contract, risk_limit);
915
+ return textContent(body);
916
+ }
917
+ catch (e) {
918
+ return errorContent(e);
919
+ }
920
+ });
921
+ server.tool('cex_futures_update_futures_position_cross_mode', 'Switch a single-mode position between isolated and cross margin (requires authentication)', {
922
+ settle: settleSchema,
923
+ contract: z.string().describe('Contract name e.g. BTC_USDT'),
924
+ mode: z.enum(['cross', 'isolated']).describe('Margin mode to set'),
925
+ }, async ({ settle, contract, mode }) => {
926
+ try {
927
+ requireAuth();
928
+ const crossMode = new FuturesPositionCrossMode();
929
+ crossMode.contract = contract;
930
+ crossMode.mode = mode;
931
+ const { body } = await new FuturesApi(createClient()).updatePositionCrossMode(settle, crossMode);
932
+ return textContent(body);
933
+ }
934
+ catch (e) {
935
+ return errorContent(e);
936
+ }
937
+ });
938
+ server.tool('cex_futures_update_futures_dual_comp_position_cross_mode', 'Switch a dual-mode position between isolated and cross margin (requires authentication)', {
939
+ settle: settleSchema,
940
+ contract: z.string().describe('Contract name e.g. BTC_USDT'),
941
+ mode: z.enum(['cross', 'isolated']).describe('Margin mode to set'),
942
+ }, async ({ settle, contract, mode }) => {
943
+ try {
944
+ requireAuth();
945
+ const inlineObj = new InlineObject();
946
+ inlineObj.contract = contract;
947
+ inlineObj.mode = mode;
948
+ const { body } = await new FuturesApi(createClient()).updateDualCompPositionCrossMode(settle, inlineObj);
724
949
  return textContent(body);
725
950
  }
726
951
  catch (e) {
@@ -740,6 +965,19 @@ export function registerFuturesTools(server) {
740
965
  return errorContent(e);
741
966
  }
742
967
  });
968
+ server.tool('cex_futures_set_position_mode', 'Set account-level position mode (requires authentication)', {
969
+ settle: settleSchema,
970
+ position_mode: z.string().describe('Position mode e.g. single_mode or dual_long_short_mode'),
971
+ }, async ({ settle, position_mode }) => {
972
+ try {
973
+ requireAuth();
974
+ const { body } = await new FuturesApi(createClient()).setPositionMode(settle, position_mode);
975
+ return textContent(body);
976
+ }
977
+ catch (e) {
978
+ return errorContent(e);
979
+ }
980
+ });
743
981
  server.tool('cex_futures_get_futures_dual_mode_position', 'Get dual-mode positions for a contract (requires authentication)', {
744
982
  settle: settleSchema,
745
983
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
@@ -800,51 +1038,314 @@ export function registerFuturesTools(server) {
800
1038
  return errorContent(e);
801
1039
  }
802
1040
  });
803
- server.tool('cex_futures_update_futures_position_cross_mode', 'Switch a single-mode position between isolated and cross margin (requires authentication)', {
1041
+ server.tool('cex_futures_countdown_cancel_all_futures', 'Set a countdown timer to cancel all futures orders (safety kill-switch, requires authentication)', {
1042
+ settle: settleSchema,
1043
+ timeout: z.number().int().describe('Countdown in seconds; 0 disables the timer'),
1044
+ contract: z.string().optional().describe('Limit cancellation to this contract'),
1045
+ }, async ({ settle, timeout, contract }) => {
1046
+ try {
1047
+ requireAuth();
1048
+ const task = { timeout };
1049
+ if (contract)
1050
+ task.contract = contract;
1051
+ const { body } = await new FuturesApi(createClient()).countdownCancelAllFutures(settle, task);
1052
+ return textContent(body);
1053
+ }
1054
+ catch (e) {
1055
+ return errorContent(e);
1056
+ }
1057
+ });
1058
+ // ── Trail Orders ──────────────────────────────────────────────────────────
1059
+ server.tool('cex_futures_create_trail_order', 'Create a trailing stop order (requires authentication) — always confirm details with the user before calling this tool', {
804
1060
  settle: settleSchema,
805
1061
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
806
- mode: z.enum(['cross', 'isolated']).describe('Margin mode to set'),
807
- }, async ({ settle, contract, mode }) => {
1062
+ amount: z.string().describe('Order size'),
1063
+ activation_price: z.string().optional().describe('Price that activates the trailing stop'),
1064
+ is_gte: z.boolean().optional().describe('true = activate when price >= activation_price'),
1065
+ price_type: z.number().int().optional().describe('Price type: 1=mark, 2=index, 3=last'),
1066
+ price_offset: z.string().optional().describe('Trailing offset from the activation price'),
1067
+ reduce_only: z.boolean().optional(),
1068
+ text: z.string().optional(),
1069
+ }, async ({ settle, contract, amount, activation_price, is_gte, price_type, price_offset, reduce_only, text }) => {
808
1070
  try {
809
1071
  requireAuth();
810
- const crossMode = new FuturesPositionCrossMode();
811
- crossMode.contract = contract;
812
- crossMode.mode = mode;
813
- const { body } = await new FuturesApi(createClient()).updatePositionCrossMode(settle, crossMode);
1072
+ const req = new CreateTrailOrder();
1073
+ req.contract = contract;
1074
+ req.amount = amount;
1075
+ if (activation_price)
1076
+ req.activationPrice = activation_price;
1077
+ if (is_gte !== undefined)
1078
+ req.isGte = is_gte;
1079
+ if (price_type !== undefined)
1080
+ req.priceType = price_type;
1081
+ if (price_offset)
1082
+ req.priceOffset = price_offset;
1083
+ if (reduce_only !== undefined)
1084
+ req.reduceOnly = reduce_only;
1085
+ if (text)
1086
+ req.text = text;
1087
+ const { body } = await new FuturesApi(createClient()).createTrailOrder(settle, req);
814
1088
  return textContent(body);
815
1089
  }
816
1090
  catch (e) {
817
1091
  return errorContent(e);
818
1092
  }
819
1093
  });
820
- server.tool('cex_futures_update_futures_dual_comp_position_cross_mode', 'Switch a dual-mode position between isolated and cross margin (requires authentication)', {
1094
+ server.tool('cex_futures_get_trail_orders', 'List trail orders (requires authentication)', {
1095
+ settle: settleSchema,
1096
+ contract: z.string().optional(),
1097
+ is_finished: z.boolean().optional(),
1098
+ start_at: z.number().optional().describe('Start time (Unix timestamp)'),
1099
+ end_at: z.number().optional().describe('End time (Unix timestamp)'),
1100
+ page_num: z.number().int().optional(),
1101
+ page_size: z.number().int().optional(),
1102
+ }, async ({ settle, contract, is_finished, start_at, end_at, page_num, page_size }) => {
1103
+ try {
1104
+ requireAuth();
1105
+ const opts = {};
1106
+ if (contract)
1107
+ opts.contract = contract;
1108
+ if (is_finished !== undefined)
1109
+ opts.isFinished = is_finished;
1110
+ if (start_at !== undefined)
1111
+ opts.startAt = start_at;
1112
+ if (end_at !== undefined)
1113
+ opts.endAt = end_at;
1114
+ if (page_num !== undefined)
1115
+ opts.pageNum = page_num;
1116
+ if (page_size !== undefined)
1117
+ opts.pageSize = page_size;
1118
+ const { body } = await new FuturesApi(createClient()).getTrailOrders(settle, opts);
1119
+ return textContent(body);
1120
+ }
1121
+ catch (e) {
1122
+ return errorContent(e);
1123
+ }
1124
+ });
1125
+ server.tool('cex_futures_get_trail_order_detail', 'Get details of a single trail order (requires authentication)', {
1126
+ settle: settleSchema,
1127
+ id: z.number().int().describe('Trail order ID'),
1128
+ }, async ({ settle, id }) => {
1129
+ try {
1130
+ requireAuth();
1131
+ const { body } = await new FuturesApi(createClient()).getTrailOrderDetail(settle, id);
1132
+ return textContent(body);
1133
+ }
1134
+ catch (e) {
1135
+ return errorContent(e);
1136
+ }
1137
+ });
1138
+ server.tool('cex_futures_update_trail_order', 'Update an existing trail order (requires authentication) — always confirm changes with the user before calling this tool', {
1139
+ settle: settleSchema,
1140
+ id: z.number().describe('Trail order ID'),
1141
+ amount: z.string().optional().describe('New order size'),
1142
+ activation_price: z.string().optional().describe('New activation price'),
1143
+ price_offset: z.string().optional().describe('New trailing price offset'),
1144
+ price_type: z.number().int().optional().describe('Price type: 0=default, 1=mark, 2=index, 3=last'),
1145
+ }, async ({ settle, id, amount, activation_price, price_offset, price_type }) => {
1146
+ try {
1147
+ requireAuth();
1148
+ const req = new UpdateTrailOrder();
1149
+ req.id = BigInt(id);
1150
+ if (amount)
1151
+ req.amount = amount;
1152
+ if (activation_price)
1153
+ req.activationPrice = activation_price;
1154
+ if (price_offset)
1155
+ req.priceOffset = price_offset;
1156
+ if (price_type !== undefined)
1157
+ req.priceType = price_type;
1158
+ const { body } = await new FuturesApi(createClient()).updateTrailOrder(settle, req);
1159
+ return textContent(body);
1160
+ }
1161
+ catch (e) {
1162
+ return errorContent(e);
1163
+ }
1164
+ });
1165
+ server.tool('cex_futures_stop_trail_order', 'Stop a specific trail order (requires authentication) — always confirm with the user before calling this tool', {
1166
+ settle: settleSchema,
1167
+ id: z.number().describe('Trail order ID'),
1168
+ text: z.string().optional().describe('Stop reason text'),
1169
+ }, async ({ settle, id, text }) => {
1170
+ try {
1171
+ requireAuth();
1172
+ const req = new StopTrailOrder();
1173
+ req.id = BigInt(id);
1174
+ if (text)
1175
+ req.text = text;
1176
+ const { body } = await new FuturesApi(createClient()).stopTrailOrder(settle, req);
1177
+ return textContent(body);
1178
+ }
1179
+ catch (e) {
1180
+ return errorContent(e);
1181
+ }
1182
+ });
1183
+ server.tool('cex_futures_stop_all_trail_orders', 'Stop all trail orders (requires authentication) — always confirm with the user before calling this tool', {
1184
+ settle: settleSchema,
1185
+ contract: z.string().optional().describe('Only stop trail orders for this contract'),
1186
+ related_position: z.number().int().optional().describe('Related position filter: 1 or 2'),
1187
+ }, async ({ settle, contract, related_position }) => {
1188
+ try {
1189
+ requireAuth();
1190
+ const req = new StopAllTrailOrders();
1191
+ if (contract)
1192
+ req.contract = contract;
1193
+ if (related_position !== undefined)
1194
+ req.relatedPosition = related_position;
1195
+ const { body } = await new FuturesApi(createClient()).stopAllTrailOrders(settle, req);
1196
+ return textContent(body);
1197
+ }
1198
+ catch (e) {
1199
+ return errorContent(e);
1200
+ }
1201
+ });
1202
+ server.tool('cex_futures_get_trail_order_change_log', 'Get change log for a trail order (requires authentication)', {
1203
+ settle: settleSchema,
1204
+ id: z.number().int().describe('Trail order ID'),
1205
+ page_num: z.number().int().optional(),
1206
+ page_size: z.number().int().optional(),
1207
+ }, async ({ settle, id, page_num, page_size }) => {
1208
+ try {
1209
+ requireAuth();
1210
+ const opts = {};
1211
+ if (page_num !== undefined)
1212
+ opts.pageNum = page_num;
1213
+ if (page_size !== undefined)
1214
+ opts.pageSize = page_size;
1215
+ const { body } = await new FuturesApi(createClient()).getTrailOrderChangeLog(settle, id, opts);
1216
+ return textContent(body);
1217
+ }
1218
+ catch (e) {
1219
+ return errorContent(e);
1220
+ }
1221
+ });
1222
+ // ── Price-triggered orders ─────────────────────────────────────────────────
1223
+ server.tool('cex_futures_list_price_triggered_orders', 'List futures price-triggered orders (requires authentication)', {
1224
+ settle: settleSchema,
1225
+ status: z.enum(['open', 'finished']),
1226
+ contract: z.string().optional(),
1227
+ limit: z.number().int().optional(),
1228
+ offset: z.number().int().optional(),
1229
+ }, async ({ settle, status, contract, limit, offset }) => {
1230
+ try {
1231
+ requireAuth();
1232
+ const opts = {};
1233
+ if (contract)
1234
+ opts.contract = contract;
1235
+ if (limit !== undefined)
1236
+ opts.limit = limit;
1237
+ if (offset !== undefined)
1238
+ opts.offset = offset;
1239
+ const { body } = await new FuturesApi(createClient()).listPriceTriggeredOrders(settle, status, opts);
1240
+ return textContent(body);
1241
+ }
1242
+ catch (e) {
1243
+ return errorContent(e);
1244
+ }
1245
+ });
1246
+ server.tool('cex_futures_create_futures_price_triggered_order', 'Create a futures price-triggered order (requires authentication) — always confirm the details with the user before calling this tool', {
821
1247
  settle: settleSchema,
822
1248
  contract: z.string().describe('Contract name e.g. BTC_USDT'),
823
- mode: z.enum(['cross', 'isolated']).describe('Margin mode to set'),
824
- }, async ({ settle, contract, mode }) => {
1249
+ trigger_price: z.string().describe('Price that activates the order'),
1250
+ trigger_rule: z.enum(['>=', '<=']).describe('>= fires when price rises to trigger_price; <= fires when it drops'),
1251
+ trigger_expiration: z.number().int().optional().describe('Trigger expiration in seconds'),
1252
+ order_size: z.number().describe('Order size (negative = short)'),
1253
+ order_price: z.string().describe('Execution price; "0" for market'),
1254
+ order_tif: z.enum(['gtc', 'ioc']).optional(),
1255
+ order_reduce_only: z.boolean().optional(),
1256
+ order_close: z.boolean().optional(),
1257
+ order_text: z.string().optional(),
1258
+ }, async ({ settle, contract, trigger_price, trigger_rule, trigger_expiration, order_size, order_price, order_tif, order_reduce_only, order_close, order_text }) => {
825
1259
  try {
826
1260
  requireAuth();
827
- const inlineObj = new InlineObject();
828
- inlineObj.contract = contract;
829
- inlineObj.mode = mode;
830
- const { body } = await new FuturesApi(createClient()).updateDualCompPositionCrossMode(settle, inlineObj);
1261
+ const trigger = { price: trigger_price, rule: trigger_rule === '>=' ? 1 : 2 };
1262
+ if (trigger_expiration !== undefined)
1263
+ trigger.expiration = trigger_expiration;
1264
+ const initial = { contract, size: order_size, price: order_price };
1265
+ if (order_tif)
1266
+ initial.tif = order_tif;
1267
+ if (order_reduce_only !== undefined)
1268
+ initial.reduceOnly = order_reduce_only;
1269
+ if (order_close !== undefined)
1270
+ initial.close = order_close;
1271
+ if (order_text)
1272
+ initial.text = order_text;
1273
+ const { body } = await new FuturesApi(createClient()).createPriceTriggeredOrder(settle, { initial, trigger });
831
1274
  return textContent(body);
832
1275
  }
833
1276
  catch (e) {
834
1277
  return errorContent(e);
835
1278
  }
836
1279
  });
837
- server.tool('cex_futures_countdown_cancel_all_futures', 'Set a countdown timer to cancel all futures orders (safety kill-switch, requires authentication)', {
1280
+ server.tool('cex_futures_get_futures_price_triggered_order', 'Get details of a futures price-triggered order (requires authentication)', {
838
1281
  settle: settleSchema,
839
- timeout: z.number().int().describe('Countdown in seconds; 0 disables the timer'),
840
- contract: z.string().optional().describe('Limit cancellation to this contract'),
841
- }, async ({ settle, timeout, contract }) => {
1282
+ order_id: z.number().int().describe('Order ID'),
1283
+ }, async ({ settle, order_id }) => {
842
1284
  try {
843
1285
  requireAuth();
844
- const task = { timeout };
1286
+ const { body } = await new FuturesApi(createClient()).getPriceTriggeredOrder(settle, order_id);
1287
+ return textContent(body);
1288
+ }
1289
+ catch (e) {
1290
+ return errorContent(e);
1291
+ }
1292
+ });
1293
+ server.tool('cex_futures_update_futures_price_triggered_order', 'Update an existing futures price-triggered order (requires authentication) — always confirm the new values with the user before calling this tool', {
1294
+ settle: settleSchema,
1295
+ order_id: z.number().int().describe('Order ID'),
1296
+ size: z.number().int().optional().describe('New order size'),
1297
+ price: z.string().optional().describe('New execution price'),
1298
+ trigger_price: z.string().optional().describe('New trigger price'),
1299
+ price_type: z.number().int().optional().describe('Trigger price type: 0=last, 1=mark, 2=index'),
1300
+ auto_size: z.string().optional(),
1301
+ close: z.boolean().optional(),
1302
+ }, async ({ settle, order_id, size, price, trigger_price, price_type, auto_size, close }) => {
1303
+ try {
1304
+ requireAuth();
1305
+ const req = new FuturesUpdatePriceTriggeredOrder();
1306
+ req.orderId = order_id;
1307
+ if (size !== undefined)
1308
+ req.size = size;
1309
+ if (price)
1310
+ req.price = price;
1311
+ if (trigger_price)
1312
+ req.triggerPrice = trigger_price;
1313
+ if (price_type !== undefined)
1314
+ req.priceType = price_type;
1315
+ if (auto_size)
1316
+ req.autoSize = auto_size;
1317
+ if (close !== undefined)
1318
+ req.close = close;
1319
+ const { body } = await new FuturesApi(createClient()).updatePriceTriggeredOrder(settle, order_id, req);
1320
+ return textContent(body);
1321
+ }
1322
+ catch (e) {
1323
+ return errorContent(e);
1324
+ }
1325
+ });
1326
+ server.tool('cex_futures_cancel_futures_price_triggered_order', 'Cancel a single futures price-triggered order (requires authentication) — always confirm with the user before calling this tool', {
1327
+ settle: settleSchema,
1328
+ order_id: z.number().int().describe('Order ID'),
1329
+ }, async ({ settle, order_id }) => {
1330
+ try {
1331
+ requireAuth();
1332
+ const { body } = await new FuturesApi(createClient()).cancelPriceTriggeredOrder(settle, order_id);
1333
+ return textContent(body);
1334
+ }
1335
+ catch (e) {
1336
+ return errorContent(e);
1337
+ }
1338
+ });
1339
+ server.tool('cex_futures_cancel_futures_price_triggered_order_list', 'Cancel all futures price-triggered orders (requires authentication) — always confirm with the user before calling this tool', {
1340
+ settle: settleSchema,
1341
+ contract: z.string().optional().describe('Only cancel orders for this contract'),
1342
+ }, async ({ settle, contract }) => {
1343
+ try {
1344
+ requireAuth();
1345
+ const opts = {};
845
1346
  if (contract)
846
- task.contract = contract;
847
- const { body } = await new FuturesApi(createClient()).countdownCancelAllFutures(settle, task);
1347
+ opts.contract = contract;
1348
+ const { body } = await new FuturesApi(createClient()).cancelPriceTriggeredOrderList(settle, opts);
848
1349
  return textContent(body);
849
1350
  }
850
1351
  catch (e) {