ccxt 4.5.63 → 4.5.64

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.
Files changed (124) hide show
  1. package/README.md +6 -8
  2. package/dist/ccxt.browser.min.js +4 -4
  3. package/dist/cjs/ccxt.js +6 -12
  4. package/dist/cjs/src/aster.js +2 -2
  5. package/dist/cjs/src/base/Exchange.js +34 -3
  6. package/dist/cjs/src/bitget.js +5 -3
  7. package/dist/cjs/src/bitmex.js +1 -1
  8. package/dist/cjs/src/bitstamp.js +2 -1
  9. package/dist/cjs/src/bitvavo.js +1 -0
  10. package/dist/cjs/src/btcbox.js +1 -1
  11. package/dist/cjs/src/bullish.js +1 -1
  12. package/dist/cjs/src/bybiteu.js +3 -0
  13. package/dist/cjs/src/coinbase.js +3 -2
  14. package/dist/cjs/src/coinbaseinternational.js +1 -1
  15. package/dist/cjs/src/delta.js +23 -1
  16. package/dist/cjs/src/derive.js +1 -1
  17. package/dist/cjs/src/digifinex.js +12 -0
  18. package/dist/cjs/src/dydx.js +2 -2
  19. package/dist/cjs/src/extended.js +1 -1
  20. package/dist/cjs/src/gateeu.js +1 -0
  21. package/dist/cjs/src/grvt.js +1 -1
  22. package/dist/cjs/src/hashkey.js +127 -6
  23. package/dist/cjs/src/hibachi.js +20 -10
  24. package/dist/cjs/src/hyperliquid.js +1 -1
  25. package/dist/cjs/src/kraken.js +2 -0
  26. package/dist/cjs/src/kucoin.js +1 -1
  27. package/dist/cjs/src/kucoineu.js +3 -0
  28. package/dist/cjs/src/lighter.js +6 -4
  29. package/dist/cjs/src/mudrex.js +1328 -0
  30. package/dist/cjs/src/myokx.js +3 -0
  31. package/dist/cjs/src/okxus.js +1 -5
  32. package/dist/cjs/src/onetrading.js +1 -0
  33. package/dist/cjs/src/pacifica.js +1 -1
  34. package/dist/cjs/src/poloniex.js +1 -1
  35. package/dist/cjs/src/pro/bingx.js +4 -2
  36. package/dist/cjs/src/pro/bitget.js +9 -7
  37. package/dist/cjs/src/pro/grvt.js +1 -1
  38. package/dist/cjs/src/pro/hashkey.js +1 -1
  39. package/dist/cjs/src/pro/kraken.js +1 -1
  40. package/dist/cjs/src/pro/mudrex.js +226 -0
  41. package/dist/cjs/src/pro/okxus.js +1 -1
  42. package/js/ccxt.d.ts +8 -14
  43. package/js/ccxt.js +6 -10
  44. package/js/src/abstract/binance.d.ts +3 -0
  45. package/js/src/abstract/binancecoinm.d.ts +3 -0
  46. package/js/src/abstract/binanceus.d.ts +3 -0
  47. package/js/src/abstract/binanceusdm.d.ts +3 -0
  48. package/js/src/abstract/bybit.d.ts +39 -0
  49. package/js/src/abstract/bybiteu.d.ts +39 -0
  50. package/js/src/abstract/coincheck.d.ts +3 -0
  51. package/js/src/abstract/coinsph.d.ts +8 -1
  52. package/js/src/abstract/kucoineu.js +0 -6
  53. package/js/src/abstract/mudrex.d.ts +33 -0
  54. package/js/src/aster.js +2 -2
  55. package/js/src/base/Exchange.d.ts +10 -1
  56. package/js/src/base/Exchange.js +34 -3
  57. package/js/src/bitget.js +5 -3
  58. package/js/src/bitmex.js +1 -1
  59. package/js/src/bitstamp.js +2 -1
  60. package/js/src/bitvavo.js +1 -0
  61. package/js/src/btcbox.js +1 -1
  62. package/js/src/bullish.js +1 -1
  63. package/js/src/bybiteu.js +3 -0
  64. package/js/src/coinbase.js +3 -2
  65. package/js/src/coinbaseinternational.js +1 -1
  66. package/js/src/delta.d.ts +12 -0
  67. package/js/src/delta.js +23 -1
  68. package/js/src/derive.js +1 -1
  69. package/js/src/digifinex.d.ts +12 -0
  70. package/js/src/digifinex.js +12 -0
  71. package/js/src/dydx.d.ts +2 -2
  72. package/js/src/dydx.js +2 -2
  73. package/js/src/extended.js +1 -1
  74. package/js/src/gateeu.js +1 -0
  75. package/js/src/grvt.d.ts +1 -1
  76. package/js/src/grvt.js +1 -1
  77. package/js/src/hashkey.d.ts +40 -3
  78. package/js/src/hashkey.js +127 -6
  79. package/js/src/hibachi.d.ts +9 -5
  80. package/js/src/hibachi.js +20 -10
  81. package/js/src/hyperliquid.js +1 -1
  82. package/js/src/kraken.js +2 -0
  83. package/js/src/kucoin.js +1 -1
  84. package/js/src/kucoineu.js +3 -0
  85. package/js/src/lighter.js +6 -4
  86. package/js/src/mudrex.d.ts +310 -0
  87. package/js/src/mudrex.js +1321 -0
  88. package/js/src/myokx.js +3 -0
  89. package/js/src/okxus.js +1 -5
  90. package/js/src/onetrading.js +1 -0
  91. package/js/src/pacifica.js +1 -1
  92. package/js/src/poloniex.js +1 -1
  93. package/js/src/pro/bingx.js +4 -2
  94. package/js/src/pro/bitget.js +9 -7
  95. package/js/src/pro/grvt.d.ts +1 -1
  96. package/js/src/pro/grvt.js +1 -1
  97. package/js/src/pro/hashkey.d.ts +1 -1
  98. package/js/src/pro/hashkey.js +1 -1
  99. package/js/src/pro/kraken.js +1 -1
  100. package/js/src/pro/mudrex.d.ts +23 -0
  101. package/js/src/pro/mudrex.js +219 -0
  102. package/js/src/pro/okxus.js +1 -1
  103. package/package.json +3 -3
  104. package/dist/cjs/src/abstract/coinmetro.js +0 -11
  105. package/dist/cjs/src/abstract/novadax.js +0 -11
  106. package/dist/cjs/src/ascendex.js +0 -3780
  107. package/dist/cjs/src/coinmetro.js +0 -2030
  108. package/dist/cjs/src/novadax.js +0 -1678
  109. package/dist/cjs/src/pro/ascendex.js +0 -1013
  110. package/js/src/abstract/ascendex.d.ts +0 -80
  111. package/js/src/abstract/coinmetro.d.ts +0 -37
  112. package/js/src/abstract/coinmetro.js +0 -5
  113. package/js/src/abstract/novadax.d.ts +0 -32
  114. package/js/src/abstract/novadax.js +0 -5
  115. package/js/src/ascendex.d.ts +0 -436
  116. package/js/src/ascendex.js +0 -3773
  117. package/js/src/coinmetro.d.ts +0 -245
  118. package/js/src/coinmetro.js +0 -2023
  119. package/js/src/novadax.d.ts +0 -279
  120. package/js/src/novadax.js +0 -1671
  121. package/js/src/pro/ascendex.d.ts +0 -99
  122. package/js/src/pro/ascendex.js +0 -1006
  123. /package/dist/cjs/src/abstract/{ascendex.js → mudrex.js} +0 -0
  124. /package/js/src/abstract/{ascendex.js → mudrex.js} +0 -0
@@ -0,0 +1,1321 @@
1
+ // ---------------------------------------------------------------------------
2
+ import Exchange from './abstract/mudrex.js';
3
+ import { ArgumentsRequired, AuthenticationError, BadRequest, BadSymbol, ExchangeError, InsufficientFunds, OrderNotFound, RateLimitExceeded } from './base/errors.js';
4
+ import { Precise } from './base/Precise.js';
5
+ // ---------------------------------------------------------------------------
6
+ /**
7
+ * @class mudrex
8
+ * @augments Exchange
9
+ */
10
+ export default class mudrex extends Exchange {
11
+ describe() {
12
+ return this.deepExtend(super.describe(), {
13
+ 'id': 'mudrex',
14
+ 'name': 'Mudrex',
15
+ 'countries': ['IN'],
16
+ 'rateLimit': 100, // 10 req/s default
17
+ 'version': 'v1',
18
+ 'pro': true,
19
+ 'certified': false,
20
+ 'dex': false,
21
+ 'hostname': 'trade.mudrex.com',
22
+ 'has': {
23
+ 'CORS': undefined,
24
+ 'spot': false,
25
+ 'margin': false,
26
+ 'swap': true,
27
+ 'future': false,
28
+ 'option': false,
29
+ 'addMargin': true,
30
+ 'cancelOrder': true,
31
+ 'closePosition': true,
32
+ 'createMarketOrder': true,
33
+ 'createOrder': true,
34
+ 'createOrderWithTakeProfitAndStopLoss': true,
35
+ 'createReduceOnlyOrder': true,
36
+ 'editOrder': true,
37
+ 'fetchBalance': true,
38
+ 'fetchClosedOrders': true,
39
+ 'fetchFundingRate': false,
40
+ 'fetchFundingRateHistory': false,
41
+ 'fetchFundingRates': false,
42
+ 'fetchIndexOHLCV': false,
43
+ 'fetchLeverage': true,
44
+ 'fetchMarkets': true,
45
+ 'fetchMarkOHLCV': true,
46
+ 'fetchMyTrades': true,
47
+ 'fetchOHLCV': true,
48
+ 'fetchOpenInterest': false,
49
+ 'fetchOpenInterests': false,
50
+ 'fetchOpenOrders': true,
51
+ 'fetchOrder': true,
52
+ 'fetchOrderBook': false,
53
+ 'fetchOrders': true,
54
+ 'fetchPositions': true,
55
+ 'fetchPositionsHistory': true,
56
+ 'fetchTicker': true,
57
+ 'fetchTickers': true,
58
+ 'fetchTrades': false,
59
+ 'reduceMargin': true,
60
+ 'setLeverage': true,
61
+ 'transfer': true,
62
+ 'watchOHLCV': true,
63
+ 'watchTicker': true,
64
+ 'watchTickers': true,
65
+ },
66
+ 'timeframes': {
67
+ '1m': '1m',
68
+ '3m': '3t',
69
+ '5m': '5t',
70
+ '10m': '10t',
71
+ '15m': '15t',
72
+ '30m': '30t',
73
+ '1h': '1h',
74
+ '4h': '4h',
75
+ '6h': '6h',
76
+ '12h': '12h',
77
+ '1d': '1d',
78
+ '1w': '1w',
79
+ '1M': '1mth',
80
+ },
81
+ 'urls': {
82
+ 'logo': 'https://github.com/user-attachments/assets/12a65022-f416-4bf8-98eb-5b6b9b05cb6a',
83
+ 'api': {
84
+ 'public': 'https://trade.mudrex.com/fapi/v1',
85
+ 'private': 'https://trade.mudrex.com/fapi/v1',
86
+ 'market': 'https://trade.mudrex.com/fapi/v1',
87
+ },
88
+ 'www': 'https://mudrex.com',
89
+ 'doc': 'https://docs.trade.mudrex.com/docs',
90
+ 'fees': 'https://docs.trade.mudrex.com',
91
+ },
92
+ 'api': {
93
+ 'market': {
94
+ 'get': {
95
+ 'price/kline': 1,
96
+ 'price/mark-kline': 1,
97
+ },
98
+ },
99
+ 'public': {
100
+ 'get': {},
101
+ },
102
+ 'private': {
103
+ 'get': {
104
+ 'futures': 1,
105
+ 'futures/{asset_id}': 1,
106
+ 'wallet/funds': 5,
107
+ 'futures/funds': 5,
108
+ 'futures/orders': 1,
109
+ 'futures/orders/history': 1,
110
+ 'futures/orders/{order_id}': 1,
111
+ 'futures/positions': 1,
112
+ 'futures/positions/history': 1,
113
+ 'futures/fee/history': 1,
114
+ 'futures/{asset_id}/leverage': 2,
115
+ 'futures/positions/{position_id}/liq-price': 1,
116
+ },
117
+ 'post': {
118
+ 'wallet/futures/transfer': 5,
119
+ 'futures/transfers/inr': 5,
120
+ 'futures/{asset_id}/order': 2,
121
+ 'futures/positions/{position_id}/close': 2,
122
+ 'futures/positions/{position_id}/close/partial': 2,
123
+ 'futures/positions/{position_id}/reverse': 2,
124
+ 'futures/positions/{position_id}/add-margin': 2,
125
+ 'futures/positions/{position_id}/riskorder': 2,
126
+ 'futures/{asset_id}/leverage': 2,
127
+ },
128
+ 'patch': {
129
+ 'futures/orders/{order_id}': 1,
130
+ 'futures/positions/{position_id}/riskorder': 2,
131
+ },
132
+ 'delete': {
133
+ 'futures/orders/{order_id}': 2,
134
+ },
135
+ },
136
+ },
137
+ 'requiredCredentials': {
138
+ 'apiKey': false,
139
+ 'secret': true,
140
+ },
141
+ 'fees': {
142
+ 'trading': {
143
+ 'tierBased': false,
144
+ 'percentage': true,
145
+ 'taker': this.parseNumber('0.00059'),
146
+ 'maker': this.parseNumber('0.00023'),
147
+ },
148
+ },
149
+ 'options': {
150
+ 'defaultType': 'swap',
151
+ 'broker': '42ce8902-8585-448c-a1e8-0371a6ca7ca8',
152
+ },
153
+ 'exceptions': {
154
+ 'exact': {
155
+ '400 Invalid trade currency': BadRequest,
156
+ },
157
+ 'broad': {
158
+ 'Invalid trade currency': BadRequest,
159
+ 'Params error': BadRequest,
160
+ 'invalid trigger type': BadRequest,
161
+ 'invalid order type': BadRequest,
162
+ 'order price out of permissible range': BadRequest,
163
+ 'quantity not a multiple of the quantity step': BadRequest,
164
+ 'leverage out of permissible range': BadRequest,
165
+ 'insufficient balance': InsufficientFunds,
166
+ 'asset not found': BadSymbol,
167
+ 'leverage not found': OrderNotFound,
168
+ 'order not found': OrderNotFound,
169
+ 'Rate limit exceeded': RateLimitExceeded,
170
+ },
171
+ },
172
+ });
173
+ }
174
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
175
+ const apiUrls = this.safeDict(this.urls, 'api', {});
176
+ const base = this.safeString(apiUrls, api);
177
+ if (base === undefined) {
178
+ throw new ExchangeError(this.id + ' unknown API namespace: ' + api);
179
+ }
180
+ let url = base + '/' + this.implodeParams(path, params);
181
+ let query = this.omit(params, this.extractParams(path));
182
+ headers = (headers !== undefined) ? this.extend({}, headers) : {};
183
+ const brokerId = this.safeString(this.options, 'broker');
184
+ if (brokerId !== undefined) {
185
+ headers['Partner-Id'] = brokerId;
186
+ }
187
+ const methodUpper = method.toUpperCase();
188
+ if (api === 'private') {
189
+ this.checkRequiredCredentials();
190
+ headers['X-Authentication'] = this.secret;
191
+ if (methodUpper === 'POST' || methodUpper === 'PATCH' || methodUpper === 'DELETE') {
192
+ headers['Content-Type'] = 'application/json';
193
+ // is_symbol is a query-string flag even on write requests
194
+ const isSymbol = this.safeString(query, 'is_symbol');
195
+ if (isSymbol !== undefined) {
196
+ query = this.omit(query, 'is_symbol');
197
+ url += '?' + this.urlencode({ 'is_symbol': isSymbol });
198
+ }
199
+ if ((methodUpper === 'DELETE') && this.isEmpty(query)) {
200
+ return { 'url': url, 'method': methodUpper, 'body': undefined, 'headers': headers };
201
+ }
202
+ const bodyStr = this.json(query);
203
+ return { 'url': url, 'method': methodUpper, 'body': bodyStr, 'headers': headers };
204
+ }
205
+ }
206
+ if (Object.keys(query).length) {
207
+ url += '?' + this.urlencode(query);
208
+ }
209
+ return { 'url': url, 'method': methodUpper, 'body': undefined, 'headers': headers };
210
+ }
211
+ handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
212
+ if (response === undefined || typeof response !== 'object') {
213
+ return undefined;
214
+ }
215
+ const success = this.safeBool(response, 'success', true);
216
+ if (!success) {
217
+ const errors = this.safeList(response, 'errors', []);
218
+ const first = this.safeDict(errors, 0, {});
219
+ const text = this.safeString(first, 'text', this.json(response));
220
+ const errCode = this.safeString(first, 'code');
221
+ this.throwExactlyMatchedException(this.exceptions['exact'], text, this.id + ' ' + text);
222
+ this.throwExactlyMatchedException(this.exceptions['exact'], errCode, this.id + ' ' + text);
223
+ this.throwBroadlyMatchedException(this.exceptions['broad'], text, this.id + ' ' + text);
224
+ const msg = this.id + ' ' + text;
225
+ const low = text.toLowerCase();
226
+ if (code === 401 || low.indexOf('auth') >= 0) {
227
+ throw new AuthenticationError(msg);
228
+ }
229
+ if (code === 429 || low.indexOf('rate') >= 0) {
230
+ throw new RateLimitExceeded(msg);
231
+ }
232
+ if (low.indexOf('insufficient') >= 0) {
233
+ throw new InsufficientFunds(msg);
234
+ }
235
+ if (code === 400) {
236
+ throw new BadRequest(msg);
237
+ }
238
+ throw new ExchangeError(msg);
239
+ }
240
+ return undefined;
241
+ }
242
+ parseOHLCV(ohlcv, market = undefined) {
243
+ //
244
+ // [ 1782984660, 60681, 60797.6, 60671.8, 60693.3, 275.741 ]
245
+ // [ timestampInSeconds, open, high, low, close, volume ]
246
+ //
247
+ return [
248
+ this.safeTimestamp(ohlcv, 0),
249
+ this.safeNumber(ohlcv, 1),
250
+ this.safeNumber(ohlcv, 2),
251
+ this.safeNumber(ohlcv, 3),
252
+ this.safeNumber(ohlcv, 4),
253
+ this.safeNumber(ohlcv, 5),
254
+ ];
255
+ }
256
+ /**
257
+ * @method
258
+ * @name mudrex#fetchOHLCV
259
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
260
+ * @see https://docs.trade.mudrex.com/docs/historical-kline
261
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
262
+ * @param {string} timeframe the length of time each candle represents
263
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
264
+ * @param {int} [limit] the maximum amount of candles to fetch
265
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
266
+ * @param {int} [params.until] timestamp in ms of the latest candle to fetch
267
+ * @param {string} [params.price] "mark" to fetch mark price candles
268
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
269
+ */
270
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
271
+ await this.loadMarkets();
272
+ const market = this.market(symbol);
273
+ const priceType = this.safeString(params, 'price');
274
+ params = this.omit(params, 'price');
275
+ // the endpoint expects the pair in "BASE/QUOTE" format (comma-separated for multiple)
276
+ const assetPair = market['baseId'] + '/' + market['quoteId'];
277
+ const request = {
278
+ 'assets': assetPair,
279
+ 'aggregation': this.safeString(this.timeframes, timeframe, timeframe),
280
+ };
281
+ // the endpoint requires an explicit time window (in seconds)
282
+ const duration = this.parseTimeframe(timeframe);
283
+ let requestLimit = limit;
284
+ if (requestLimit === undefined) {
285
+ requestLimit = 500;
286
+ }
287
+ const now = this.seconds();
288
+ let startTime = undefined;
289
+ if (since !== undefined) {
290
+ startTime = this.parseToInt(since / 1000);
291
+ }
292
+ else {
293
+ startTime = now - duration * requestLimit;
294
+ }
295
+ let endTime = startTime + duration * requestLimit;
296
+ const until = this.safeInteger(params, 'until');
297
+ if (until !== undefined) {
298
+ params = this.omit(params, 'until');
299
+ endTime = this.parseToInt(until / 1000);
300
+ }
301
+ else if (endTime > now) {
302
+ endTime = now;
303
+ }
304
+ request['start_time'] = startTime;
305
+ request['end_time'] = endTime;
306
+ let response = undefined;
307
+ if (priceType === 'mark') {
308
+ response = await this.marketGetPriceMarkKline(this.extend(request, params));
309
+ }
310
+ else {
311
+ response = await this.marketGetPriceKline(this.extend(request, params));
312
+ }
313
+ //
314
+ // {
315
+ // "success": true,
316
+ // "data": {
317
+ // "asset_ticks": {
318
+ // "btc/usdt": [ [ 1782984660, 60681, 60797.6, 60671.8, 60693.3, 275.741 ] ]
319
+ // }
320
+ // }
321
+ // }
322
+ //
323
+ const data = this.safeDict(response, 'data', {});
324
+ const assetTicks = this.safeDict(data, 'asset_ticks', {});
325
+ const ohlcvs = this.safeList(assetTicks, assetPair.toLowerCase(), []);
326
+ return this.parseOHLCVs(ohlcvs, market, timeframe, since, limit);
327
+ }
328
+ /**
329
+ * @method
330
+ * @name mudrex#fetchMarkOHLCV
331
+ * @description fetches historical mark price candlestick data containing the open, high, low, and close price of a market
332
+ * @see https://docs.trade.mudrex.com/docs
333
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
334
+ * @param {string} timeframe the length of time each candle represents
335
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
336
+ * @param {int} [limit] the maximum amount of candles to fetch
337
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
338
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
339
+ */
340
+ async fetchMarkOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
341
+ return await this.fetchOHLCV(symbol, timeframe, since, limit, this.extend(params, { 'price': 'mark' }));
342
+ }
343
+ /**
344
+ * @method
345
+ * @name mudrex#fetchTicker
346
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
347
+ * @see https://docs.trade.mudrex.com/docs
348
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
349
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
350
+ * @returns {object} a [ticker structure](https://docs.ccxt.com/#/?id=ticker-structure)
351
+ */
352
+ async fetchTicker(symbol, params = {}) {
353
+ await this.loadMarkets();
354
+ const market = this.market(symbol);
355
+ const request = {
356
+ 'asset_id': market['id'],
357
+ 'is_symbol': 1,
358
+ };
359
+ const response = await this.privateGetFuturesAssetId(this.extend(request, params));
360
+ const data = this.safeDict(response, 'data', {});
361
+ return this.parseTicker(data, market);
362
+ }
363
+ /**
364
+ * @method
365
+ * @name mudrex#fetchTickers
366
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
367
+ * @see https://docs.trade.mudrex.com/docs
368
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
369
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
370
+ * @returns {object} a dictionary of [ticker structures](https://docs.ccxt.com/#/?id=ticker-structure)
371
+ */
372
+ async fetchTickers(symbols = undefined, params = {}) {
373
+ await this.loadMarkets();
374
+ const request = {};
375
+ const response = await this.privateGetFutures(this.extend(request, params));
376
+ const data = this.safeValue(response, 'data', []);
377
+ const rows = Array.isArray(data) ? data : this.safeList(data, 'items', []);
378
+ const resultTickers = {};
379
+ for (let i = 0; i < rows.length; i++) {
380
+ const t = rows[i];
381
+ const sym = this.safeString(t, 'symbol');
382
+ if (sym === undefined) {
383
+ continue;
384
+ }
385
+ const m = this.safeMarket(sym);
386
+ const symbol = m['symbol'];
387
+ if (symbols !== undefined && !this.inArray(symbol, symbols)) {
388
+ continue;
389
+ }
390
+ resultTickers[symbol] = this.parseTicker(t, m);
391
+ }
392
+ return this.filterByArrayTickers(resultTickers, 'symbol', symbols);
393
+ }
394
+ parseTicker(ticker, market = undefined) {
395
+ const ms = this.safeString(ticker, 'symbol');
396
+ market = this.safeMarket(ms, market);
397
+ const symbol = market['symbol'];
398
+ const ts = this.milliseconds();
399
+ const pct = this.safeNumber(ticker, 'change_perc');
400
+ return this.safeTicker({
401
+ 'symbol': symbol,
402
+ 'timestamp': ts,
403
+ 'datetime': this.iso8601(ts),
404
+ 'high': undefined,
405
+ 'low': undefined,
406
+ 'bid': undefined,
407
+ 'bidVolume': undefined,
408
+ 'ask': undefined,
409
+ 'askVolume': undefined,
410
+ 'vwap': undefined,
411
+ 'open': this.safeNumber(ticker, 'last_day_price'),
412
+ 'close': this.safeNumber(ticker, 'price'),
413
+ 'last': this.safeNumber(ticker, 'price'),
414
+ 'previousClose': undefined,
415
+ 'change': undefined,
416
+ 'percentage': pct,
417
+ 'average': undefined,
418
+ 'baseVolume': undefined,
419
+ 'quoteVolume': this.safeNumber(ticker, 'volume'),
420
+ 'info': ticker,
421
+ }, market);
422
+ }
423
+ /**
424
+ * @method
425
+ * @name mudrex#fetchMarkets
426
+ * @description retrieves data on all markets for the exchange
427
+ * @see https://docs.trade.mudrex.com/docs
428
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
429
+ * @returns {object[]} an array of objects representing market data
430
+ */
431
+ async fetchMarkets(params = {}) {
432
+ const aggregated = [];
433
+ let offset = 0;
434
+ const pageLimit = 100;
435
+ let paging = true;
436
+ while (paging === true) {
437
+ const q = this.extend({ 'limit': pageLimit, 'offset': offset }, params);
438
+ const response = await this.privateGetFutures(q);
439
+ const data = this.safeValue(response, 'data', []);
440
+ let items = [];
441
+ if (typeof data === 'object' && !Array.isArray(data)) {
442
+ items = this.safeList(data, 'items', []);
443
+ if (!items.length) {
444
+ items = this.safeList(data, 'results', []);
445
+ }
446
+ if (!items.length && ('symbol' in data)) {
447
+ items = [data];
448
+ }
449
+ }
450
+ else {
451
+ items = this.toArray(data);
452
+ }
453
+ if (!items.length) {
454
+ paging = false;
455
+ break;
456
+ }
457
+ for (let i = 0; i < items.length; i++) {
458
+ aggregated.push(items[i]);
459
+ }
460
+ if (items.length < pageLimit) {
461
+ paging = false;
462
+ }
463
+ else {
464
+ offset += pageLimit;
465
+ }
466
+ }
467
+ const result = [];
468
+ for (let i = 0; i < aggregated.length; i++) {
469
+ result.push(this.parseMarket(aggregated[i]));
470
+ }
471
+ return result;
472
+ }
473
+ parseMarket(asset) {
474
+ const ms = this.safeString(asset, 'symbol');
475
+ let base = ms;
476
+ if (ms !== undefined && ms.endsWith('USDT')) {
477
+ base = ms.slice(0, -4);
478
+ }
479
+ const quote = 'USDT';
480
+ const settle = 'USDT';
481
+ let symbol = undefined;
482
+ if (base !== undefined) {
483
+ symbol = base + '/' + quote + ':' + settle;
484
+ }
485
+ const priceStep = this.safeString(asset, 'price_step', '0.01');
486
+ const qtyStep = this.safeString(asset, 'quantity_step', '0.001');
487
+ return {
488
+ 'id': ms,
489
+ 'lowercaseId': undefined,
490
+ 'symbol': symbol,
491
+ 'base': base,
492
+ 'quote': quote,
493
+ 'settle': settle,
494
+ 'baseId': base,
495
+ 'quoteId': 'USDT',
496
+ 'settleId': 'USDT',
497
+ 'type': 'swap',
498
+ 'spot': false,
499
+ 'margin': false,
500
+ 'swap': true,
501
+ 'future': false,
502
+ 'option': false,
503
+ 'active': true,
504
+ 'contract': true,
505
+ 'linear': true,
506
+ 'inverse': false,
507
+ 'taker': this.safeNumber(this.fees['trading'], 'taker'),
508
+ 'maker': this.safeNumber(this.fees['trading'], 'maker'),
509
+ 'contractSize': this.safeNumber(asset, 'contract_size', 1),
510
+ 'expiry': undefined,
511
+ 'expiryDatetime': undefined,
512
+ 'strike': undefined,
513
+ 'optionType': undefined,
514
+ 'precision': {
515
+ 'amount': this.parseNumber(qtyStep),
516
+ 'price': this.parseNumber(priceStep),
517
+ },
518
+ 'limits': {
519
+ 'amount': {
520
+ 'min': this.safeNumber(asset, 'min_contract'),
521
+ 'max': this.safeNumber(asset, 'max_contract'),
522
+ },
523
+ 'price': {
524
+ 'min': this.safeNumber(asset, 'min_price'),
525
+ 'max': this.safeNumber(asset, 'max_price'),
526
+ },
527
+ 'cost': {
528
+ 'min': this.safeNumber(asset, 'min_notional_value'),
529
+ 'max': undefined,
530
+ },
531
+ },
532
+ 'info': asset,
533
+ 'created': undefined,
534
+ };
535
+ }
536
+ /**
537
+ * @method
538
+ * @name mudrex#fetchBalance
539
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
540
+ * @see https://docs.trade.mudrex.com/docs
541
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
542
+ * @param {string} [params.type] 'swap' (default) or 'spot' - which wallet balance to fetch
543
+ * @param {string} [params.trade_currency] the settlement currency to query the balance for
544
+ * @returns {object} a [balance structure](https://docs.ccxt.com/#/?id=balance-structure)
545
+ */
546
+ async fetchBalance(params = {}) {
547
+ await this.loadMarkets();
548
+ let type = undefined;
549
+ [type, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params, 'swap');
550
+ const requested = this.safeStringN(params, ['trade_currency', 'tradeCurrency', 'currency']);
551
+ params = this.omit(params, ['trade_currency', 'tradeCurrency', 'currency']);
552
+ const request = {};
553
+ let response = undefined;
554
+ if (type === 'spot') {
555
+ if (requested !== undefined) {
556
+ request['currency'] = requested;
557
+ }
558
+ response = await this.privateGetWalletFunds(this.extend(request, params));
559
+ }
560
+ else {
561
+ if (requested !== undefined) {
562
+ request['trade_currency'] = requested;
563
+ }
564
+ response = await this.privateGetFuturesFunds(this.extend(request, params));
565
+ }
566
+ let currency = requested;
567
+ if (currency === undefined) {
568
+ currency = 'USDT';
569
+ }
570
+ response['currency'] = currency;
571
+ return this.parseBalance(response);
572
+ }
573
+ parseBalance(response) {
574
+ const data = this.safeDict(response, 'data', {});
575
+ const currency = this.safeString(response, 'currency', 'USDT');
576
+ const timestamp = this.milliseconds();
577
+ const result = {
578
+ 'info': response,
579
+ 'timestamp': timestamp,
580
+ 'datetime': this.iso8601(timestamp),
581
+ };
582
+ const account = this.account();
583
+ const futuresBalance = this.safeString(data, 'balance');
584
+ if (futuresBalance !== undefined) {
585
+ // futures wallet: balance is the free/available margin, locked_amount is used, safeBalance derives total
586
+ account['free'] = futuresBalance;
587
+ account['used'] = this.safeString(data, 'locked_amount');
588
+ }
589
+ else {
590
+ // spot wallet: total is the total, withdrawable is free, safeBalance derives used
591
+ account['total'] = this.safeString(data, 'total');
592
+ account['free'] = this.safeString(data, 'withdrawable');
593
+ }
594
+ result[currency] = account;
595
+ return this.safeBalance(result);
596
+ }
597
+ /**
598
+ * @method
599
+ * @name mudrex#fetchLeverage
600
+ * @description fetch the set leverage for a market
601
+ * @see https://docs.trade.mudrex.com/docs
602
+ * @param {string} symbol unified market symbol
603
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
604
+ * @returns {object} a [leverage structure](https://docs.ccxt.com/#/?id=leverage-structure)
605
+ */
606
+ async fetchLeverage(symbol, params = {}) {
607
+ await this.loadMarkets();
608
+ const market = this.market(symbol);
609
+ const request = {
610
+ 'asset_id': market['id'],
611
+ 'is_symbol': 1,
612
+ };
613
+ const response = await this.privateGetFuturesAssetIdLeverage(this.extend(request, params));
614
+ const data = this.safeDict(response, 'data', {});
615
+ return {
616
+ 'info': response,
617
+ 'symbol': symbol,
618
+ 'marginMode': this.safeStringLower(data, 'margin_type'),
619
+ 'longLeverage': this.safeNumber(data, 'leverage'),
620
+ 'shortLeverage': this.safeNumber(data, 'leverage'),
621
+ };
622
+ }
623
+ /**
624
+ * @method
625
+ * @name mudrex#setLeverage
626
+ * @description set the level of leverage for a market
627
+ * @see https://docs.trade.mudrex.com/docs
628
+ * @param {float} leverage the rate of leverage
629
+ * @param {string} symbol unified market symbol
630
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
631
+ * @param {string} [params.marginType] 'ISOLATED' (default) or 'CROSSED'
632
+ * @returns {object} response from the exchange
633
+ */
634
+ async setLeverage(leverage, symbol = undefined, params = {}) {
635
+ if (symbol === undefined) {
636
+ throw new ArgumentsRequired(this.id + ' setLeverage() requires a symbol');
637
+ }
638
+ await this.loadMarkets();
639
+ const market = this.market(symbol);
640
+ const marginType = this.safeString(params, 'marginType', 'ISOLATED');
641
+ const request = {
642
+ 'asset_id': market['id'],
643
+ 'is_symbol': 1,
644
+ 'margin_type': marginType,
645
+ 'leverage': leverage,
646
+ };
647
+ params = this.omit(params, ['marginType']);
648
+ const response = await this.privatePostFuturesAssetIdLeverage(this.extend(request, params));
649
+ return response;
650
+ }
651
+ /**
652
+ * @method
653
+ * @name mudrex#createOrder
654
+ * @description create a trade order
655
+ * @see https://docs.trade.mudrex.com/docs
656
+ * @param {string} symbol unified market symbol
657
+ * @param {string} type 'market' or 'limit'
658
+ * @param {string} side 'buy' or 'sell'
659
+ * @param {float} amount how much you want to trade in units of the base currency
660
+ * @param {float} [price] the price to fulfill the order, in units of the quote currency (also required for market orders on this exchange)
661
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
662
+ * @param {int} [params.leverage] leverage for the order, required if setLeverage() was not called beforehand
663
+ * @param {bool} [params.reduceOnly] true if the order is reduce only
664
+ * @param {object} [params.takeProfit] *takeProfit object in params* containing the trigger price of the take-profit order attached to this order
665
+ * @param {float} [params.takeProfit.triggerPrice] take profit trigger price
666
+ * @param {object} [params.stopLoss] *stopLoss object in params* containing the trigger price of the stop-loss order attached to this order
667
+ * @param {float} [params.stopLoss.triggerPrice] stop loss trigger price
668
+ * @param {float} [params.takeProfitPrice] the trigger price for a standalone take-profit order on an existing position (requires params.positionId)
669
+ * @param {float} [params.stopLossPrice] the trigger price for a standalone stop-loss order on an existing position (requires params.positionId)
670
+ * @param {string} [params.positionId] the id of the position the standalone stopLossPrice/takeProfitPrice order is attached to
671
+ * @param {string} [params.trade_currency] the settlement currency for the order
672
+ * @returns {object} an [order structure](https://docs.ccxt.com/#/?id=order-structure)
673
+ */
674
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
675
+ await this.loadMarkets();
676
+ const market = this.market(symbol);
677
+ // standalone stop-loss / take-profit orders (stopLossPrice/takeProfitPrice) are attached to
678
+ // an existing position through the riskorder endpoint, so a positionId is required
679
+ const stopLossPrice = this.safeString(params, 'stopLossPrice');
680
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
681
+ if ((stopLossPrice !== undefined) || (takeProfitPrice !== undefined)) {
682
+ const positionId = this.safeString2(params, 'positionId', 'position_id');
683
+ if (positionId === undefined) {
684
+ throw new ArgumentsRequired(this.id + ' createOrder() requires a positionId parameter to place a stopLossPrice or takeProfitPrice order');
685
+ }
686
+ params = this.omit(params, ['stopLossPrice', 'takeProfitPrice', 'positionId', 'position_id']);
687
+ const riskRequest = {
688
+ 'position_id': positionId,
689
+ };
690
+ if (takeProfitPrice !== undefined) {
691
+ riskRequest['is_takeprofit'] = true;
692
+ riskRequest['takeprofit_price'] = this.priceToPrecision(symbol, takeProfitPrice);
693
+ }
694
+ if (stopLossPrice !== undefined) {
695
+ riskRequest['is_stoploss'] = true;
696
+ riskRequest['stoploss_price'] = this.priceToPrecision(symbol, stopLossPrice);
697
+ }
698
+ const riskResponse = await this.privatePostFuturesPositionsPositionIdRiskorder(this.extend(riskRequest, params));
699
+ const riskData = this.safeDict(riskResponse, 'data', riskResponse);
700
+ return this.parseOrder(riskData, market);
701
+ }
702
+ const lev = this.safeInteger(params, 'leverage', 1);
703
+ if ((type === 'market') && (price === undefined)) {
704
+ throw new ArgumentsRequired(this.id + ' createOrder() requires a price argument for market orders');
705
+ }
706
+ const request = {
707
+ 'asset_id': market['id'],
708
+ 'is_symbol': 1,
709
+ 'leverage': this.numberToString(lev),
710
+ 'quantity': this.amountToPrecision(symbol, amount),
711
+ 'order_price': this.priceToPrecision(symbol, price),
712
+ 'order_type': (side === 'buy') ? 'LONG' : 'SHORT',
713
+ 'trigger_type': (type === 'market') ? 'MARKET' : 'LIMIT',
714
+ 'reduce_only': this.safeBool(params, 'reduceOnly', false),
715
+ };
716
+ // mudrex only supports take-profit / stop-loss orders attached to the position-opening order
717
+ const takeProfit = this.safeDict(params, 'takeProfit');
718
+ const stopLoss = this.safeDict(params, 'stopLoss');
719
+ if (takeProfit !== undefined) {
720
+ request['is_takeprofit'] = true;
721
+ request['takeprofit_price'] = this.priceToPrecision(symbol, this.safeStringN(takeProfit, ['triggerPrice', 'stopPrice', 'price']));
722
+ }
723
+ if (stopLoss !== undefined) {
724
+ request['is_stoploss'] = true;
725
+ request['stoploss_price'] = this.priceToPrecision(symbol, this.safeStringN(stopLoss, ['triggerPrice', 'stopPrice', 'price']));
726
+ }
727
+ params = this.omit(params, ['leverage', 'reduceOnly', 'takeProfit', 'stopLoss']);
728
+ const response = await this.privatePostFuturesAssetIdOrder(this.extend(request, params));
729
+ const data = this.safeDict(response, 'data', response);
730
+ // the create response omits the order/trigger type, so restore them from the request
731
+ data['order_type'] = request['order_type'];
732
+ data['trigger_type'] = request['trigger_type'];
733
+ return this.parseOrder(data, market);
734
+ }
735
+ /**
736
+ * @method
737
+ * @name mudrex#editOrder
738
+ * @description edit a trade order
739
+ * @see https://docs.trade.mudrex.com/docs
740
+ * @param {string} id order id
741
+ * @param {string} symbol unified symbol of the market to edit an order in
742
+ * @param {string} type 'market' or 'limit'
743
+ * @param {string} side 'buy' or 'sell'
744
+ * @param {float} [amount] how much of the currency you want to trade in units of the base currency
745
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency
746
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
747
+ * @returns {object} an [order structure](https://docs.ccxt.com/#/?id=order-structure)
748
+ */
749
+ async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
750
+ await this.loadMarkets();
751
+ let market = undefined;
752
+ if (symbol !== undefined) {
753
+ market = this.market(symbol);
754
+ }
755
+ const request = {
756
+ 'order_id': id,
757
+ };
758
+ if (amount !== undefined) {
759
+ request['quantity'] = this.amountToPrecision(symbol, amount);
760
+ }
761
+ if (price !== undefined) {
762
+ request['order_price'] = this.priceToPrecision(symbol, price);
763
+ }
764
+ const response = await this.privatePatchFuturesOrdersOrderId(this.extend(request, params));
765
+ const data = this.safeDict(response, 'data', response);
766
+ return this.parseOrder(data, market);
767
+ }
768
+ parseOrderStatus(status) {
769
+ const statuses = {
770
+ 'open': 'open',
771
+ 'created': 'open',
772
+ 'new': 'open',
773
+ 'pending': 'open',
774
+ 'partially_filled': 'open',
775
+ 'filled': 'closed',
776
+ 'completed': 'closed',
777
+ 'cancelled': 'canceled',
778
+ 'canceled': 'canceled',
779
+ 'rejected': 'rejected',
780
+ 'expired': 'expired',
781
+ };
782
+ return this.safeString(statuses, status, status);
783
+ }
784
+ parseOrder(order, market = undefined) {
785
+ const oms = this.safeString(order, 'symbol');
786
+ market = this.safeMarket(oms, market);
787
+ const oid = this.safeString2(order, 'order_id', 'id');
788
+ const rawSide = this.safeStringUpper(order, 'order_type');
789
+ let side = undefined;
790
+ if (rawSide === 'LONG') {
791
+ side = 'buy';
792
+ }
793
+ else if (rawSide === 'SHORT') {
794
+ side = 'sell';
795
+ }
796
+ const trig = this.safeStringUpper(order, 'trigger_type');
797
+ let typ = undefined;
798
+ if (trig === 'MARKET') {
799
+ typ = 'market';
800
+ }
801
+ else if (trig === 'LIMIT') {
802
+ typ = 'limit';
803
+ }
804
+ let ts = this.parse8601(this.safeString(order, 'created_at'));
805
+ if (ts === undefined) {
806
+ ts = this.milliseconds();
807
+ }
808
+ const status = this.parseOrderStatus(this.safeStringLower(order, 'status'));
809
+ const sym = market['symbol'];
810
+ return this.safeOrder({
811
+ 'info': order,
812
+ 'id': oid,
813
+ 'clientOrderId': undefined,
814
+ 'timestamp': ts,
815
+ 'datetime': this.iso8601(ts),
816
+ 'lastTradeTimestamp': undefined,
817
+ 'symbol': sym,
818
+ 'type': typ,
819
+ 'timeInForce': undefined,
820
+ 'postOnly': undefined,
821
+ 'side': side,
822
+ 'price': this.safeNumber2(order, 'price', 'order_price'),
823
+ 'stopPrice': undefined,
824
+ 'triggerPrice': undefined,
825
+ 'amount': this.safeNumber2(order, 'quantity', 'amount'),
826
+ 'cost': undefined,
827
+ 'average': undefined,
828
+ 'filled': undefined,
829
+ 'remaining': undefined,
830
+ 'status': status,
831
+ 'fee': undefined,
832
+ 'trades': [],
833
+ 'fees': [],
834
+ 'lastUpdateTimestamp': undefined,
835
+ 'reduceOnly': this.safeBool(order, 'reduce_only'),
836
+ }, market);
837
+ }
838
+ /**
839
+ * @method
840
+ * @name mudrex#cancelOrder
841
+ * @description cancels an open order
842
+ * @see https://docs.trade.mudrex.com/docs
843
+ * @param {string} id order id
844
+ * @param {string} [symbol] unified symbol of the market the order was made in
845
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
846
+ * @returns {object} An [order structure](https://docs.ccxt.com/#/?id=order-structure)
847
+ */
848
+ async cancelOrder(id, symbol = undefined, params = {}) {
849
+ await this.loadMarkets();
850
+ let market = undefined;
851
+ if (symbol !== undefined) {
852
+ market = this.market(symbol);
853
+ }
854
+ const request = {
855
+ 'order_id': id,
856
+ };
857
+ const response = await this.privateDeleteFuturesOrdersOrderId(this.extend(request, params));
858
+ const data = this.safeDict(response, 'data', response);
859
+ return this.parseOrder(data, market);
860
+ }
861
+ /**
862
+ * @method
863
+ * @name mudrex#fetchOrder
864
+ * @description fetches information on an order made by the user
865
+ * @see https://docs.trade.mudrex.com/docs
866
+ * @param {string} id the order id
867
+ * @param {string} [symbol] unified symbol of the market the order was made in
868
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
869
+ * @returns {object} An [order structure](https://docs.ccxt.com/#/?id=order-structure)
870
+ */
871
+ async fetchOrder(id, symbol = undefined, params = {}) {
872
+ await this.loadMarkets();
873
+ let market = undefined;
874
+ if (symbol !== undefined) {
875
+ market = this.market(symbol);
876
+ }
877
+ const request = {
878
+ 'order_id': id,
879
+ };
880
+ const response = await this.privateGetFuturesOrdersOrderId(this.extend(request, params));
881
+ const data = this.safeDict(response, 'data', response);
882
+ return this.parseOrder(data, market);
883
+ }
884
+ /**
885
+ * @method
886
+ * @name mudrex#fetchOrdersByState
887
+ * @ignore
888
+ * @description fetches a list of orders filtered by their state
889
+ * @param {string} state the state of the orders to fetch
890
+ * @param {string} [symbol] unified market symbol
891
+ * @param {int} [since] the earliest time in ms to fetch orders for
892
+ * @param {int} [limit] the maximum number of order structures to retrieve
893
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
894
+ * @returns {Order[]} a list of [order structures](https://docs.ccxt.com/#/?id=order-structure)
895
+ */
896
+ async fetchOrdersByState(state, symbol = undefined, since = undefined, limit = undefined, params = {}) {
897
+ await this.loadMarkets();
898
+ const q = {};
899
+ if (limit !== undefined) {
900
+ q['limit'] = limit;
901
+ }
902
+ const request = this.extend(q, params);
903
+ let response = undefined;
904
+ if (state === 'closed') {
905
+ response = await this.privateGetFuturesOrdersHistory(request);
906
+ }
907
+ else {
908
+ response = await this.privateGetFuturesOrders(request);
909
+ }
910
+ const data = this.safeValue(response, 'data', []);
911
+ const rows = this.toArray(data);
912
+ let market = undefined;
913
+ if (symbol !== undefined) {
914
+ market = this.market(symbol);
915
+ }
916
+ const orders = [];
917
+ for (let i = 0; i < rows.length; i++) {
918
+ orders.push(this.parseOrder(rows[i], market));
919
+ }
920
+ return this.filterBySymbolSinceLimit(orders, symbol, since, limit);
921
+ }
922
+ /**
923
+ * @method
924
+ * @name mudrex#fetchOrders
925
+ * @description fetches information on multiple orders made by the user
926
+ * @see https://docs.trade.mudrex.com/docs
927
+ * @param {string} [symbol] unified market symbol of the market orders were made in
928
+ * @param {int} [since] the earliest time in ms to fetch orders for
929
+ * @param {int} [limit] the maximum number of order structures to retrieve
930
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
931
+ * @returns {Order[]} a list of [order structures](https://docs.ccxt.com/#/?id=order-structure)
932
+ */
933
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
934
+ return await this.fetchOrdersByState('closed', symbol, since, limit, params);
935
+ }
936
+ /**
937
+ * @method
938
+ * @name mudrex#fetchOpenOrders
939
+ * @description fetch all unfilled currently open orders
940
+ * @see https://docs.trade.mudrex.com/docs
941
+ * @param {string} [symbol] unified market symbol
942
+ * @param {int} [since] the earliest time in ms to fetch open orders for
943
+ * @param {int} [limit] the maximum number of open order structures to retrieve
944
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
945
+ * @returns {Order[]} a list of [order structures](https://docs.ccxt.com/#/?id=order-structure)
946
+ */
947
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
948
+ return await this.fetchOrdersByState('open', symbol, since, limit, params);
949
+ }
950
+ /**
951
+ * @method
952
+ * @name mudrex#fetchClosedOrders
953
+ * @description fetches information on multiple closed orders made by the user
954
+ * @see https://docs.trade.mudrex.com/docs
955
+ * @param {string} [symbol] unified market symbol of the market orders were made in
956
+ * @param {int} [since] the earliest time in ms to fetch orders for
957
+ * @param {int} [limit] the maximum number of order structures to retrieve
958
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
959
+ * @returns {Order[]} a list of [order structures](https://docs.ccxt.com/#/?id=order-structure)
960
+ */
961
+ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
962
+ return await this.fetchOrdersByState('closed', symbol, since, limit, params);
963
+ }
964
+ /**
965
+ * @method
966
+ * @name mudrex#fetchPositions
967
+ * @description fetch all open positions
968
+ * @see https://docs.trade.mudrex.com/docs
969
+ * @param {string[]} [symbols] list of unified market symbols
970
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
971
+ * @param {string} [params.trade_currency] the settlement currency to query positions for
972
+ * @returns {object[]} a list of [position structures](https://docs.ccxt.com/#/?id=position-structure)
973
+ */
974
+ async fetchPositions(symbols = undefined, params = {}) {
975
+ await this.loadMarkets();
976
+ const q = {};
977
+ const response = await this.privateGetFuturesPositions(this.extend(q, params));
978
+ const data = this.safeValue(response, 'data', []);
979
+ if (data === undefined) {
980
+ return [];
981
+ }
982
+ const rows = this.toArray(data);
983
+ const outPos = [];
984
+ for (let i = 0; i < rows.length; i++) {
985
+ const p = rows[i];
986
+ const symRaw = this.safeString(p, 'symbol');
987
+ const m = this.safeMarket(symRaw);
988
+ const pos = this.parsePosition(p, m);
989
+ outPos.push(pos);
990
+ }
991
+ return this.filterByArrayPositions(outPos, 'symbol', symbols, false);
992
+ }
993
+ /**
994
+ * @method
995
+ * @name mudrex#fetchPositionsHistory
996
+ * @description fetches the history of closed positions
997
+ * @see https://docs.trade.mudrex.com/docs/get-position-history
998
+ * @param {string[]} [symbols] a list of unified market symbols
999
+ * @param {int} [since] the earliest time in ms to fetch positions for
1000
+ * @param {int} [limit] the maximum number of position structures to retrieve
1001
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1002
+ * @param {string} [params.trade_currency] the settlement currency to filter positions by
1003
+ * @returns {object[]} a list of [position structures](https://docs.ccxt.com/#/?id=position-structure)
1004
+ */
1005
+ async fetchPositionsHistory(symbols = undefined, since = undefined, limit = undefined, params = {}) {
1006
+ await this.loadMarkets();
1007
+ symbols = this.marketSymbols(symbols);
1008
+ const request = {};
1009
+ if (limit !== undefined) {
1010
+ request['limit'] = limit;
1011
+ }
1012
+ const response = await this.privateGetFuturesPositionsHistory(this.extend(request, params));
1013
+ //
1014
+ // {
1015
+ // "success": true,
1016
+ // "data": [
1017
+ // {
1018
+ // "id": "019f1ed6-...",
1019
+ // "position_type": "SHORT",
1020
+ // "status": "CLOSED",
1021
+ // "leverage": "3",
1022
+ // "entry_price": "1.3112",
1023
+ // "closed_price": "1.3395",
1024
+ // "quantity": "34",
1025
+ // "pnl": "-0.9622",
1026
+ // "created_at": "2026-07-01T10:18:57Z",
1027
+ // "updated_at": "2026-07-01T18:00:21Z",
1028
+ // "symbol": "CAKEUSDT",
1029
+ // "trade_currency": "USDT"
1030
+ // }
1031
+ // ]
1032
+ // }
1033
+ //
1034
+ const data = this.safeList(response, 'data', []);
1035
+ const positions = this.parsePositions(data, symbols);
1036
+ return this.filterBySinceLimit(positions, since, limit);
1037
+ }
1038
+ parsePosition(position, market = undefined) {
1039
+ market = this.safeMarket(undefined, market);
1040
+ const ms = this.safeString(position, 'symbol');
1041
+ const symbol = this.safeSymbol(ms, market);
1042
+ // open positions use "order_type", closed positions (history) use "position_type"
1043
+ const rawSide = this.safeStringUpper2(position, 'order_type', 'position_type');
1044
+ let side = undefined;
1045
+ if (rawSide === 'LONG') {
1046
+ side = 'long';
1047
+ }
1048
+ else if (rawSide === 'SHORT') {
1049
+ side = 'short';
1050
+ }
1051
+ let ts = this.parse8601(this.safeString(position, 'updated_at'));
1052
+ if (ts === undefined) {
1053
+ ts = this.parse8601(this.safeString(position, 'created_at'));
1054
+ }
1055
+ const quantityString = this.safeString(position, 'quantity');
1056
+ const entryPriceString = this.safeString(position, 'entry_price');
1057
+ const contractSizeString = this.safeString(market, 'contractSize', '1');
1058
+ let notional = undefined;
1059
+ if ((quantityString !== undefined) && (entryPriceString !== undefined)) {
1060
+ notional = this.parseNumber(Precise.stringMul(Precise.stringMul(quantityString, entryPriceString), contractSizeString));
1061
+ }
1062
+ const initialMargin = this.safeString(position, 'initial_margin');
1063
+ return {
1064
+ 'info': position,
1065
+ 'id': this.safeString(position, 'id'),
1066
+ 'symbol': symbol,
1067
+ 'timestamp': ts,
1068
+ 'datetime': this.iso8601(ts),
1069
+ 'isolated': true,
1070
+ 'hedged': false,
1071
+ 'side': side,
1072
+ 'contracts': this.safeNumber(position, 'quantity'),
1073
+ 'contractSize': this.safeNumber(market, 'contractSize'),
1074
+ 'entryPrice': this.safeNumber(position, 'entry_price'),
1075
+ 'markPrice': undefined,
1076
+ 'lastPrice': this.safeNumber(position, 'closed_price'), // exit price for closed positions
1077
+ 'notional': notional,
1078
+ 'leverage': this.safeInteger(position, 'leverage'),
1079
+ 'collateral': this.parseNumber(initialMargin),
1080
+ 'initialMargin': this.parseNumber(initialMargin),
1081
+ 'initialMarginPercentage': undefined,
1082
+ 'maintenanceMargin': this.safeNumber(position, 'maintenance_margin'),
1083
+ 'maintenanceMarginPercentage': undefined,
1084
+ 'unrealizedPnl': undefined,
1085
+ 'realizedPnl': this.safeNumber(position, 'pnl'), // realized pnl for closed positions
1086
+ 'liquidationPrice': this.safeNumber(position, 'liquidation_price'),
1087
+ 'marginMode': 'isolated',
1088
+ 'percentage': undefined,
1089
+ };
1090
+ }
1091
+ /**
1092
+ * @method
1093
+ * @name mudrex#closePosition
1094
+ * @description closes an open position for a market
1095
+ * @see https://docs.trade.mudrex.com/docs
1096
+ * @param {string} symbol unified CCXT market symbol
1097
+ * @param {string} [side] 'buy' or 'sell', not required by mudrex
1098
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1099
+ * @param {string} [params.position_id] the id of the position to close, resolved from the symbol if not provided
1100
+ * @param {float} [params.amount] the amount to close for a partial close, closes the whole position if not provided
1101
+ * @returns {object} an [order structure](https://docs.ccxt.com/#/?id=order-structure)
1102
+ */
1103
+ async closePosition(symbol, side = undefined, params = {}) {
1104
+ await this.loadMarkets();
1105
+ let positionId = this.safeString(params, 'position_id');
1106
+ const amount = this.safeValue(params, 'amount');
1107
+ if (positionId === undefined) {
1108
+ const market = this.market(symbol);
1109
+ const positions = await this.fetchPositions([symbol], params);
1110
+ for (let i = 0; i < positions.length; i++) {
1111
+ const p = positions[i];
1112
+ if (side !== undefined && p['side'] !== side) {
1113
+ continue;
1114
+ }
1115
+ if (p['symbol'] === market['symbol']) {
1116
+ positionId = this.safeString(p, 'id');
1117
+ break;
1118
+ }
1119
+ }
1120
+ }
1121
+ if (positionId === undefined) {
1122
+ throw new OrderNotFound(this.id + ' closePosition() could not resolve position_id');
1123
+ }
1124
+ const request = {
1125
+ 'position_id': positionId,
1126
+ };
1127
+ if (amount !== undefined) {
1128
+ const orderType = this.safeStringUpper(params, 'order_type', 'LIMIT');
1129
+ request['order_type'] = orderType;
1130
+ request['quantity'] = this.amountToPrecision(symbol, amount);
1131
+ const lp = this.safeString(params, 'limit_price');
1132
+ if (orderType === 'LIMIT' && lp !== undefined) {
1133
+ request['limit_price'] = lp;
1134
+ }
1135
+ params = this.omit(params, ['order_type', 'limit_price', 'amount', 'position_id']);
1136
+ return await this.privatePostFuturesPositionsPositionIdClosePartial(this.extend(request, params));
1137
+ }
1138
+ params = this.omit(params, ['position_id']);
1139
+ return await this.privatePostFuturesPositionsPositionIdClose(this.extend(request, params));
1140
+ }
1141
+ /**
1142
+ * @method
1143
+ * @name mudrex#addMargin
1144
+ * @description add margin to a position
1145
+ * @see https://docs.trade.mudrex.com/docs
1146
+ * @param {string} symbol unified market symbol
1147
+ * @param {float} amount amount of margin to add
1148
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1149
+ * @param {string} [params.position_id] the id of the position to add margin to, resolved from the symbol if not provided
1150
+ * @returns {object} a [margin structure](https://docs.ccxt.com/#/?id=add-margin-structure)
1151
+ */
1152
+ async addMargin(symbol, amount, params = {}) {
1153
+ await this.loadMarkets();
1154
+ let positionId = this.safeString(params, 'position_id');
1155
+ if (positionId === undefined) {
1156
+ const positions = await this.fetchPositions([symbol], params);
1157
+ for (let i = 0; i < positions.length; i++) {
1158
+ const p = positions[i];
1159
+ if (p['symbol'] === symbol) {
1160
+ positionId = this.safeString(p, 'id');
1161
+ break;
1162
+ }
1163
+ }
1164
+ }
1165
+ if (positionId === undefined) {
1166
+ throw new OrderNotFound(this.id + ' addMargin() could not resolve position_id');
1167
+ }
1168
+ const request = {
1169
+ 'position_id': positionId,
1170
+ 'margin': this.costToPrecision(symbol, amount),
1171
+ };
1172
+ params = this.omit(params, ['position_id']);
1173
+ return await this.privatePostFuturesPositionsPositionIdAddMargin(this.extend(request, params));
1174
+ }
1175
+ /**
1176
+ * @method
1177
+ * @name mudrex#reduceMargin
1178
+ * @description remove margin from a position
1179
+ * @see https://docs.trade.mudrex.com/docs
1180
+ * @param {string} symbol unified market symbol
1181
+ * @param {float} amount the amount of margin to remove
1182
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1183
+ * @returns {object} a [margin structure](https://docs.ccxt.com/#/?id=reduce-margin-structure)
1184
+ */
1185
+ async reduceMargin(symbol, amount, params = {}) {
1186
+ return await this.addMargin(symbol, -amount, params);
1187
+ }
1188
+ /**
1189
+ * @method
1190
+ * @name mudrex#fetchMyTrades
1191
+ * @description fetch all trades made by the user
1192
+ * @see https://docs.trade.mudrex.com/docs
1193
+ * @param {string} [symbol] unified market symbol
1194
+ * @param {int} [since] the earliest time in ms to fetch trades for
1195
+ * @param {int} [limit] the maximum number of trade structures to retrieve
1196
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1197
+ * @param {string} [params.trade_currency] the settlement currency to filter trades by
1198
+ * @returns {Trade[]} a list of [trade structures](https://docs.ccxt.com/#/?id=trade-structure)
1199
+ */
1200
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1201
+ await this.loadMarkets();
1202
+ let market = undefined;
1203
+ if (symbol !== undefined) {
1204
+ market = this.market(symbol);
1205
+ }
1206
+ const request = {};
1207
+ if (limit !== undefined) {
1208
+ request['limit'] = limit;
1209
+ }
1210
+ const response = await this.privateGetFuturesFeeHistory(this.extend(request, params));
1211
+ const data = this.safeValue(response, 'data', []);
1212
+ const rows = this.toArray(data);
1213
+ return this.parseTrades(rows, market, since, limit);
1214
+ }
1215
+ parseTrade(trade, market = undefined) {
1216
+ const ms = this.safeString(trade, 'symbol');
1217
+ market = this.safeMarket(ms, market);
1218
+ const symbol = market['symbol'];
1219
+ let ts = this.parse8601(this.safeString(trade, 'created_at'));
1220
+ if (ts === undefined) {
1221
+ ts = this.safeInteger(trade, 'time');
1222
+ }
1223
+ const side = this.safeStringLower2(trade, 'side', 'order_type');
1224
+ let tradeSide = undefined;
1225
+ if (side === 'buy' || side === 'long') {
1226
+ tradeSide = 'buy';
1227
+ }
1228
+ else if (side === 'sell' || side === 'short') {
1229
+ tradeSide = 'sell';
1230
+ }
1231
+ const feeType = this.safeStringUpper(trade, 'fee_type');
1232
+ let takerOrMaker = undefined;
1233
+ if (feeType === 'TRANSACTION') {
1234
+ takerOrMaker = 'taker';
1235
+ }
1236
+ else if (feeType === 'REBATE') {
1237
+ takerOrMaker = 'maker';
1238
+ }
1239
+ let fee = undefined;
1240
+ const feeCost = this.safeNumber(trade, 'fee_amount');
1241
+ if (feeCost !== undefined) {
1242
+ fee = {
1243
+ 'cost': feeCost,
1244
+ 'currency': this.safeString(trade, 'trade_currency'),
1245
+ };
1246
+ }
1247
+ return this.safeTrade({
1248
+ 'info': trade,
1249
+ 'timestamp': ts,
1250
+ 'datetime': this.iso8601(ts),
1251
+ 'symbol': symbol,
1252
+ 'id': this.safeString2(trade, 'execId', 'id'),
1253
+ 'order': this.safeString(trade, 'order_id'),
1254
+ 'type': this.safeStringLower(trade, 'trigger_type'),
1255
+ 'side': tradeSide,
1256
+ 'takerOrMaker': takerOrMaker,
1257
+ 'price': this.safeNumber(trade, 'price'),
1258
+ 'amount': this.safeNumber2(trade, 'size', 'quantity'),
1259
+ 'cost': this.safeNumber(trade, 'transaction_amount'),
1260
+ 'fee': fee,
1261
+ }, market);
1262
+ }
1263
+ /**
1264
+ * @method
1265
+ * @name mudrex#transfer
1266
+ * @description transfer currency internally between wallets on the same account
1267
+ * @see https://docs.trade.mudrex.com/docs
1268
+ * @param {string} code unified currency code
1269
+ * @param {float} amount amount to transfer
1270
+ * @param {string} fromAccount 'spot' or 'futures'
1271
+ * @param {string} toAccount 'spot' or 'futures'
1272
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1273
+ * @returns {object} a [transfer structure](https://docs.ccxt.com/#/?id=transfer-structure)
1274
+ */
1275
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
1276
+ const mp = {
1277
+ 'spot': 'SPOT',
1278
+ 'SPOT': 'SPOT',
1279
+ 'futures': 'FUTURES',
1280
+ 'future': 'FUTURES',
1281
+ 'FUTURES': 'FUTURES',
1282
+ };
1283
+ const fw = this.safeString(mp, fromAccount, fromAccount.toUpperCase());
1284
+ const tw = this.safeString(mp, toAccount, toAccount.toUpperCase());
1285
+ const body = {
1286
+ 'from_wallet_type': fw,
1287
+ 'to_wallet_type': tw,
1288
+ 'amount': this.numberToString(amount),
1289
+ };
1290
+ let useInr = false;
1291
+ if (code === 'INR') {
1292
+ useInr = true;
1293
+ }
1294
+ else {
1295
+ // default USDT does not use the inr path
1296
+ const tradeCurrency = this.safeString2(params, 'trade_currency', 'tradeCurrency');
1297
+ if (tradeCurrency === 'INR') {
1298
+ useInr = true;
1299
+ }
1300
+ }
1301
+ let response = undefined;
1302
+ if (useInr) {
1303
+ response = await this.privatePostFuturesTransfersInr(this.extend(body, params));
1304
+ }
1305
+ else {
1306
+ response = await this.privatePostWalletFuturesTransfer(this.extend(body, params));
1307
+ }
1308
+ const data = this.safeDict(response, 'data', response);
1309
+ return {
1310
+ 'info': response,
1311
+ 'id': this.safeString(data, 'id'),
1312
+ 'timestamp': undefined,
1313
+ 'datetime': undefined,
1314
+ 'currency': code,
1315
+ 'amount': amount,
1316
+ 'fromAccount': fw,
1317
+ 'toAccount': tw,
1318
+ 'status': 'ok',
1319
+ };
1320
+ }
1321
+ }