ccxt 4.4.32 → 4.4.34

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 (118) hide show
  1. package/README.md +8 -7
  2. package/dist/ccxt.browser.min.js +6 -6
  3. package/dist/cjs/ccxt.js +4 -1
  4. package/dist/cjs/src/abstract/ellipx.js +9 -0
  5. package/dist/cjs/src/alpaca.js +2 -0
  6. package/dist/cjs/src/base/Exchange.js +116 -1
  7. package/dist/cjs/src/binance.js +164 -6
  8. package/dist/cjs/src/bingx.js +156 -9
  9. package/dist/cjs/src/bitbank.js +5 -0
  10. package/dist/cjs/src/bitbns.js +2 -0
  11. package/dist/cjs/src/bitfinex2.js +2 -1
  12. package/dist/cjs/src/bitget.js +177 -44
  13. package/dist/cjs/src/bitmex.js +2 -0
  14. package/dist/cjs/src/bitopro.js +3 -0
  15. package/dist/cjs/src/bitrue.js +1 -0
  16. package/dist/cjs/src/btcmarkets.js +2 -0
  17. package/dist/cjs/src/bybit.js +148 -13
  18. package/dist/cjs/src/cex.js +16 -6
  19. package/dist/cjs/src/coinbase.js +5 -24
  20. package/dist/cjs/src/coinbaseexchange.js +2 -1
  21. package/dist/cjs/src/coinex.js +2 -0
  22. package/dist/cjs/src/coinone.js +7 -7
  23. package/dist/cjs/src/coinsph.js +7 -7
  24. package/dist/cjs/src/coinspot.js +39 -39
  25. package/dist/cjs/src/cryptocom.js +36 -34
  26. package/dist/cjs/src/ellipx.js +1871 -0
  27. package/dist/cjs/src/gate.js +2 -1
  28. package/dist/cjs/src/hyperliquid.js +16 -2
  29. package/dist/cjs/src/kraken.js +1 -0
  30. package/dist/cjs/src/krakenfutures.js +3 -1
  31. package/dist/cjs/src/kucoinfutures.js +1 -1
  32. package/dist/cjs/src/lbank.js +1 -0
  33. package/dist/cjs/src/okcoin.js +2 -0
  34. package/dist/cjs/src/okx.js +104 -9
  35. package/dist/cjs/src/onetrading.js +14 -1
  36. package/dist/cjs/src/paradex.js +2 -0
  37. package/dist/cjs/src/phemex.js +35 -7
  38. package/dist/cjs/src/poloniex.js +3 -1
  39. package/dist/cjs/src/poloniexfutures.js +3 -1
  40. package/dist/cjs/src/pro/idex.js +5 -0
  41. package/dist/cjs/src/pro/okx.js +11 -1
  42. package/dist/cjs/src/pro/probit.js +4 -2
  43. package/dist/cjs/src/pro/woo.js +15 -15
  44. package/dist/cjs/src/vertex.js +2 -0
  45. package/dist/cjs/src/woo.js +69 -69
  46. package/examples/js/cli.js +1 -1
  47. package/js/ccxt.d.ts +5 -2
  48. package/js/ccxt.js +4 -2
  49. package/js/src/abstract/bingx.d.ts +16 -0
  50. package/js/src/abstract/bitbank.d.ts +5 -0
  51. package/js/src/abstract/bitfinex2.d.ts +1 -0
  52. package/js/src/abstract/coinbaseexchange.d.ts +1 -0
  53. package/js/src/abstract/ellipx.d.ts +28 -0
  54. package/js/src/abstract/ellipx.js +11 -0
  55. package/js/src/abstract/kraken.d.ts +1 -0
  56. package/js/src/alpaca.js +2 -0
  57. package/js/src/base/Exchange.d.ts +11 -0
  58. package/js/src/base/Exchange.js +116 -1
  59. package/js/src/binance.js +164 -6
  60. package/js/src/bingx.d.ts +3 -1
  61. package/js/src/bingx.js +156 -9
  62. package/js/src/bitbank.js +5 -0
  63. package/js/src/bitbns.js +2 -0
  64. package/js/src/bitfinex2.js +2 -1
  65. package/js/src/bitget.d.ts +4 -4
  66. package/js/src/bitget.js +177 -44
  67. package/js/src/bitmex.js +2 -0
  68. package/js/src/bitopro.d.ts +1 -0
  69. package/js/src/bitopro.js +3 -0
  70. package/js/src/bitrue.js +1 -0
  71. package/js/src/btcmarkets.d.ts +1 -0
  72. package/js/src/btcmarkets.js +2 -0
  73. package/js/src/bybit.d.ts +3 -2
  74. package/js/src/bybit.js +149 -14
  75. package/js/src/cex.d.ts +1 -0
  76. package/js/src/cex.js +17 -7
  77. package/js/src/coinbase.d.ts +2 -1
  78. package/js/src/coinbase.js +5 -24
  79. package/js/src/coinbaseexchange.js +2 -1
  80. package/js/src/coinex.js +2 -0
  81. package/js/src/coinone.js +7 -7
  82. package/js/src/coinsph.js +7 -7
  83. package/js/src/coinspot.js +39 -39
  84. package/js/src/cryptocom.d.ts +1 -1
  85. package/js/src/cryptocom.js +36 -34
  86. package/js/src/ellipx.d.ts +236 -0
  87. package/js/src/ellipx.js +1874 -0
  88. package/js/src/gate.d.ts +2 -2
  89. package/js/src/gate.js +2 -1
  90. package/js/src/hyperliquid.d.ts +2 -1
  91. package/js/src/hyperliquid.js +16 -2
  92. package/js/src/kraken.js +1 -0
  93. package/js/src/krakenfutures.js +3 -1
  94. package/js/src/kucoinfutures.d.ts +1 -1
  95. package/js/src/kucoinfutures.js +1 -1
  96. package/js/src/lbank.js +1 -0
  97. package/js/src/okcoin.js +2 -0
  98. package/js/src/okx.d.ts +1 -1
  99. package/js/src/okx.js +104 -9
  100. package/js/src/onetrading.d.ts +5 -0
  101. package/js/src/onetrading.js +15 -2
  102. package/js/src/paradex.js +2 -0
  103. package/js/src/phemex.d.ts +4 -0
  104. package/js/src/phemex.js +35 -7
  105. package/js/src/poloniex.d.ts +1 -1
  106. package/js/src/poloniex.js +3 -1
  107. package/js/src/poloniexfutures.d.ts +1 -1
  108. package/js/src/poloniexfutures.js +3 -1
  109. package/js/src/pro/idex.d.ts +5 -0
  110. package/js/src/pro/idex.js +5 -0
  111. package/js/src/pro/okx.js +11 -1
  112. package/js/src/pro/probit.js +4 -2
  113. package/js/src/pro/woo.d.ts +11 -11
  114. package/js/src/pro/woo.js +15 -15
  115. package/js/src/vertex.js +2 -0
  116. package/js/src/woo.d.ts +60 -60
  117. package/js/src/woo.js +69 -69
  118. package/package.json +3 -3
@@ -0,0 +1,1871 @@
1
+ 'use strict';
2
+
3
+ var ellipx$1 = require('./abstract/ellipx.js');
4
+ var errors = require('./base/errors.js');
5
+ var number = require('./base/functions/number.js');
6
+ require('../ccxt.js');
7
+ var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
8
+ var ed25519 = require('./static_dependencies/noble-curves/ed25519.js');
9
+ var crypto = require('./base/functions/crypto.js');
10
+ var Precise = require('./base/Precise.js');
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * @class ellipx
16
+ * @augments Exchange
17
+ */
18
+ class ellipx extends ellipx$1 {
19
+ describe() {
20
+ return this.deepExtend(super.describe(), {
21
+ 'id': 'ellipx',
22
+ 'name': 'Ellipx',
23
+ 'countries': ['PL'],
24
+ 'rateLimit': 200,
25
+ 'version': 'v1',
26
+ 'certified': false,
27
+ 'pro': false,
28
+ 'has': {
29
+ 'CORS': undefined,
30
+ 'spot': true,
31
+ 'margin': false,
32
+ 'swap': false,
33
+ 'future': false,
34
+ 'option': false,
35
+ 'addMargin': false,
36
+ 'cancelAllOrders': false,
37
+ 'cancelAllOrdersAfter': false,
38
+ 'cancelOrder': true,
39
+ 'cancelOrders': false,
40
+ 'cancelWithdraw': false,
41
+ 'closePosition': false,
42
+ 'createConvertTrade': false,
43
+ 'createDepositAddress': false,
44
+ 'createMarketBuyOrderWithCost': false,
45
+ 'createMarketOrder': false,
46
+ 'createMarketOrderWithCost': false,
47
+ 'createMarketSellOrderWithCost': false,
48
+ 'createOrder': true,
49
+ 'createOrderWithTakeProfitAndStopLoss': false,
50
+ 'createReduceOnlyOrder': false,
51
+ 'createStopLimitOrder': false,
52
+ 'createStopLossOrder': false,
53
+ 'createStopMarketOrder': false,
54
+ 'createStopOrder': false,
55
+ 'createTakeProfitOrder': false,
56
+ 'createTrailingAmountOrder': false,
57
+ 'createTrailingPercentOrder': false,
58
+ 'createTriggerOrder': false,
59
+ 'fetchAccounts': false,
60
+ 'fetchBalance': true,
61
+ 'fetchCanceledAndClosedOrders': false,
62
+ 'fetchCanceledOrders': false,
63
+ 'fetchClosedOrder': false,
64
+ 'fetchClosedOrders': false,
65
+ 'fetchConvertCurrencies': false,
66
+ 'fetchConvertQuote': false,
67
+ 'fetchConvertTrade': false,
68
+ 'fetchConvertTradeHistory': false,
69
+ 'fetchCurrencies': true,
70
+ 'fetchDepositAddress': true,
71
+ 'fetchDeposits': false,
72
+ 'fetchDepositsWithdrawals': false,
73
+ 'fetchFundingHistory': false,
74
+ 'fetchFundingRate': false,
75
+ 'fetchFundingRateHistory': false,
76
+ 'fetchFundingRates': false,
77
+ 'fetchIndexOHLCV': false,
78
+ 'fetchLedger': false,
79
+ 'fetchLeverage': false,
80
+ 'fetchLeverageTiers': false,
81
+ 'fetchMarginAdjustmentHistory': false,
82
+ 'fetchMarginMode': false,
83
+ 'fetchMarkets': true,
84
+ 'fetchMarkOHLCV': false,
85
+ 'fetchMyTrades': false,
86
+ 'fetchOHLCV': true,
87
+ 'fetchOpenInterestHistory': false,
88
+ 'fetchOpenOrder': false,
89
+ 'fetchOpenOrders': true,
90
+ 'fetchOrder': true,
91
+ 'fetchOrderBook': true,
92
+ 'fetchOrders': true,
93
+ 'fetchOrderTrades': true,
94
+ 'fetchPosition': false,
95
+ 'fetchPositionHistory': false,
96
+ 'fetchPositionMode': false,
97
+ 'fetchPositions': false,
98
+ 'fetchPositionsForSymbol': false,
99
+ 'fetchPositionsHistory': false,
100
+ 'fetchPremiumIndexOHLCV': false,
101
+ 'fetchStatus': false,
102
+ 'fetchTicker': true,
103
+ 'fetchTickers': false,
104
+ 'fetchTime': false,
105
+ 'fetchTrades': true,
106
+ 'fetchTradingFee': true,
107
+ 'fetchTradingFees': false,
108
+ 'fetchTransactions': false,
109
+ 'fetchTransfers': false,
110
+ 'fetchWithdrawals': false,
111
+ 'reduceMargin': false,
112
+ 'sandbox': false,
113
+ 'setLeverage': false,
114
+ 'setMargin': false,
115
+ 'setPositionMode': false,
116
+ 'transfer': false,
117
+ 'withdraw': true,
118
+ },
119
+ 'timeframes': {
120
+ '1m': '1m',
121
+ '5m': '5m',
122
+ '10m': '10m',
123
+ '1h': '1h',
124
+ '6h': '6h',
125
+ '12h': '12h',
126
+ '1d': '1d',
127
+ },
128
+ 'urls': {
129
+ 'logo': 'https://github.com/user-attachments/assets/e07c3f40-281c-4cdf-bacf-fa1c58218a2c',
130
+ 'api': {
131
+ 'public': 'https://data.ellipx.com',
132
+ 'private': 'https://app.ellipx.com/_rest',
133
+ '_rest': 'https://app.ellipx.com/_rest',
134
+ },
135
+ 'www': 'https://www.ellipx.com',
136
+ 'doc': 'https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM',
137
+ 'fees': 'https://www.ellipx.com/pages/pricing',
138
+ 'referral': '', // todo
139
+ },
140
+ 'api': {
141
+ '_rest': {
142
+ 'get': {
143
+ 'Market': 1,
144
+ 'Market/{currencyPair}': 1,
145
+ 'Crypto/Token/Info': 1,
146
+ },
147
+ },
148
+ 'public': {
149
+ 'get': {
150
+ 'Market/{currencyPair}:getDepth': 1,
151
+ 'Market/{currencyPair}:ticker': 1,
152
+ 'Market/{currencyPair}:getTrades': 1,
153
+ 'Market/{currencyPair}:getGraph': 1,
154
+ 'CMC:summary': 1,
155
+ 'CMC/{currencyPair}:ticker': 1,
156
+ },
157
+ },
158
+ 'private': {
159
+ 'get': {
160
+ 'User/Wallet': 1,
161
+ 'Market/{currencyPair}/Order': 1,
162
+ 'Market/Order/{orderUuid}': 1,
163
+ 'Market/{currencyPair}/Trade': 1,
164
+ 'Market/TradeFee:query': 1,
165
+ 'Unit/{currency}': 1,
166
+ 'Crypto/Token/{currency}': 1,
167
+ 'Crypto/Token/{currency}:chains': 1,
168
+ },
169
+ 'post': {
170
+ 'Market/{currencyPair}/Order': 1,
171
+ 'Crypto/Address:fetch': 1,
172
+ 'Crypto/Disbursement:withdraw': 1,
173
+ },
174
+ 'delete': {
175
+ 'Market/Order/{orderUuid}': 1,
176
+ },
177
+ },
178
+ },
179
+ 'fees': {
180
+ 'trading': {
181
+ 'tierBased': true,
182
+ 'feeSide': 'get',
183
+ 'percentage': true,
184
+ 'maker': this.parseNumber('0.0025'),
185
+ 'taker': this.parseNumber('0.0030'),
186
+ 'tiers': {
187
+ // volume in USDT
188
+ 'maker': [
189
+ [this.parseNumber('0'), this.parseNumber('0.0025')],
190
+ [this.parseNumber('10000'), this.parseNumber('0.0020')],
191
+ [this.parseNumber('50000'), this.parseNumber('0.0015')],
192
+ [this.parseNumber('100000'), this.parseNumber('0.0010')],
193
+ [this.parseNumber('1000000'), this.parseNumber('0.0008')],
194
+ [this.parseNumber('5000000'), this.parseNumber('0.0003')],
195
+ [this.parseNumber('15000000'), this.parseNumber('0.0000')],
196
+ [this.parseNumber('75000000'), this.parseNumber('0.0000')],
197
+ [this.parseNumber('100000000'), this.parseNumber('0.0000')], // 100M+: 0bps
198
+ ],
199
+ 'taker': [
200
+ [this.parseNumber('0'), this.parseNumber('0.0030')],
201
+ [this.parseNumber('10000'), this.parseNumber('0.0025')],
202
+ [this.parseNumber('50000'), this.parseNumber('0.0020')],
203
+ [this.parseNumber('100000'), this.parseNumber('0.0015')],
204
+ [this.parseNumber('1000000'), this.parseNumber('0.0012')],
205
+ [this.parseNumber('5000000'), this.parseNumber('0.0010')],
206
+ [this.parseNumber('15000000'), this.parseNumber('0.0008')],
207
+ [this.parseNumber('75000000'), this.parseNumber('0.0005')],
208
+ [this.parseNumber('100000000'), this.parseNumber('0.0003')], // 100M+: 3bps
209
+ ],
210
+ },
211
+ },
212
+ 'stablecoin': {
213
+ 'tierBased': false,
214
+ 'percentage': true,
215
+ 'maker': this.parseNumber('0.0000'),
216
+ 'taker': this.parseNumber('0.000015'), // 0.0015%
217
+ },
218
+ },
219
+ 'options': {
220
+ 'defaultType': 'spot',
221
+ 'recvWindow': 5 * 1000,
222
+ 'broker': 'CCXT',
223
+ 'networks': {
224
+ 'Bitcoin': 'Bitcoin',
225
+ 'Ethereum': 'ERC20',
226
+ },
227
+ 'defaultNetwork': 'defaultNetwork',
228
+ 'defaultNetworkCodeReplacements': {
229
+ 'BTC': 'Bitcoin',
230
+ 'ETH': 'Ethereum',
231
+ },
232
+ },
233
+ 'commonCurrencies': {},
234
+ 'exceptions': {
235
+ 'exact': {
236
+ // todo
237
+ '400': errors.BadRequest,
238
+ '401': errors.AuthenticationError,
239
+ '403': errors.PermissionDenied,
240
+ '404': errors.BadRequest,
241
+ '429': errors.DDoSProtection,
242
+ '418': errors.PermissionDenied,
243
+ '500': errors.ExchangeError,
244
+ '504': errors.ExchangeError,
245
+ },
246
+ 'broad': {},
247
+ },
248
+ 'precisionMode': number.TICK_SIZE,
249
+ });
250
+ }
251
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
252
+ path = this.implodeParams(path, params);
253
+ let url = this.urls['api'][api] + '/' + path;
254
+ if (api === 'private') {
255
+ this.checkRequiredCredentials();
256
+ const nonce = this.uuid();
257
+ const timestamp = this.seconds().toString();
258
+ if (method === 'GET') {
259
+ body = '';
260
+ }
261
+ else {
262
+ body = this.json(params);
263
+ }
264
+ params = this.extend({
265
+ '_key': this.apiKey,
266
+ '_time': timestamp,
267
+ '_nonce': nonce,
268
+ }, params);
269
+ const query = this.urlencode(params);
270
+ const bodyHash = this.hash(this.encode(body), sha256.sha256);
271
+ // Create sign string components
272
+ const bodyHashBytes = this.base16ToBinary(bodyHash);
273
+ const nulByte = this.numberToBE(0, 1);
274
+ const components = [
275
+ this.encode(method),
276
+ nulByte,
277
+ this.encode(path),
278
+ nulByte,
279
+ this.encode(query),
280
+ nulByte,
281
+ bodyHashBytes,
282
+ ];
283
+ // Join with null byte separator using encode
284
+ const signString = this.binaryConcatArray(components);
285
+ const sec = this.secret;
286
+ const remainder = this.calculateMod(sec.length, 4);
287
+ const paddingLength = remainder ? 4 - remainder : 0;
288
+ let secretWithPadding = this.secret.replaceAll('-', '+');
289
+ secretWithPadding = secretWithPadding.replaceAll('_', '/');
290
+ secretWithPadding = secretWithPadding.padEnd(this.secret.length + paddingLength, '=');
291
+ const secretBytes = this.base64ToBinary(secretWithPadding);
292
+ const seed = this.arraySlice(secretBytes, 0, 32); // Extract first 32 bytes as seed
293
+ const signature = crypto.eddsa(signString, seed, ed25519.ed25519);
294
+ params['_sign'] = signature;
295
+ }
296
+ if (Object.keys(params).length) {
297
+ url += '?' + this.urlencode(params);
298
+ }
299
+ if (method === 'GET') {
300
+ body = undefined;
301
+ }
302
+ else {
303
+ headers = {
304
+ 'Content-Type': 'application/json',
305
+ };
306
+ }
307
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
308
+ }
309
+ calculateMod(a, b) {
310
+ // trick to fix php transpiling error
311
+ return a % b;
312
+ }
313
+ /**
314
+ * @method
315
+ * @name ellipx#fetchMarkets
316
+ * @description Fetches market information from the exchange.
317
+ * @see https://docs.ccxt.com/en/latest/manual.html#markets
318
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.1a1t05wpgfof
319
+ * @param {object} [params] - Extra parameters specific to the exchange API endpoint
320
+ * @returns {Promise<Market[]>} An array of market structures.
321
+ */
322
+ async fetchMarkets(params = {}) {
323
+ const response = await this._restGetMarket(params);
324
+ // {
325
+ // Market__: "mkt-lrnp2e-eaor-eobj-ua73-75j6sjxe",
326
+ // Primary_Unit__: "unit-aebkye-u35b-e5zm-zt22-2qvwhsqa",
327
+ // Secondary_Unit__: "unit-jcevlk-soxf-fepb-yjwm-b32q5bom",
328
+ // Primary_Step: null,
329
+ // Secondary_Step: null,
330
+ // Status: "active",
331
+ // Default_Scale: "5",
332
+ // Priority: "100",
333
+ // Created: {
334
+ // unix: "1728113809",
335
+ // us: "0",
336
+ // iso: "2024-10-05 07:36:49.000000",
337
+ // tz: "UTC",
338
+ // full: "1728113809000000",
339
+ // unixms: "1728113809000",
340
+ // },
341
+ // Start: {
342
+ // unix: "1728295200",
343
+ // us: "0",
344
+ // iso: "2024-10-07 10:00:00.000000",
345
+ // tz: "UTC",
346
+ // full: "1728295200000000",
347
+ // unixms: "1728295200000",
348
+ // },
349
+ // Key: "BTC_USDC",
350
+ // Primary: {
351
+ // Unit__: "unit-aebkye-u35b-e5zm-zt22-2qvwhsqa",
352
+ // Currency__: "BTC",
353
+ // Crypto_Token__: "crtok-c5v3mh-grfn-hl5d-lmel-fvggbf4i",
354
+ // Key: "BTC",
355
+ // Symbol: "BTC",
356
+ // Symbol_Position: "after",
357
+ // Name: "Bitcoin",
358
+ // Decimals: "8",
359
+ // Display_Decimals: "8",
360
+ // Legacy_Decimals: null,
361
+ // Type: "crypto_token",
362
+ // Visible: "Y",
363
+ // Created: {
364
+ // unix: "1495247415",
365
+ // us: "0",
366
+ // iso: "2017-05-20 02:30:15.000000",
367
+ // tz: "UTC",
368
+ // full: "1495247415000000",
369
+ // unixms: "1495247415000",
370
+ // },
371
+ // },
372
+ // Secondary: {
373
+ // Unit__: "unit-jcevlk-soxf-fepb-yjwm-b32q5bom",
374
+ // Currency__: null,
375
+ // Crypto_Token__: "crtok-ptabkh-ra4r-anbd-cqra-bqfbtnba",
376
+ // Key: "USDC",
377
+ // Symbol: null,
378
+ // Symbol_Position: "before",
379
+ // Name: "Circle USD",
380
+ // Decimals: "6",
381
+ // Display_Decimals: "6",
382
+ // Legacy_Decimals: null,
383
+ // Type: "crypto_token",
384
+ // Visible: "Y",
385
+ // Created: {
386
+ // unix: "1694859829",
387
+ // us: "0",
388
+ // iso: "2023-09-16 10:23:49.000000",
389
+ // tz: "UTC",
390
+ // full: "1694859829000000",
391
+ // unixms: "1694859829000",
392
+ // },
393
+ // },
394
+ // }
395
+ const markets = this.safeValue(response, 'data', []);
396
+ return this.parseMarkets(markets);
397
+ }
398
+ parseMarket(market) {
399
+ const id = this.safeString(market, 'Key');
400
+ const base = this.safeString(market['Primary'], 'Key');
401
+ const quote = this.safeString(market['Secondary'], 'Key');
402
+ const baseId = this.safeString(market['Primary'], 'Crypto_Token__');
403
+ const quoteId = this.safeString(market['Secondary'], 'Crypto_Token__');
404
+ const status = this.safeString(market, 'Status') === 'active';
405
+ const created = this.safeTimestamp(market['Created'], 'unix');
406
+ const amountPrecision = this.parseNumber(this.parsePrecision(this.safeString(market['Primary'], 'Decimals')));
407
+ const pricePrecision = this.parseNumber(this.parsePrecision(this.safeString(market['Secondary'], 'Decimals')));
408
+ const fees = this.fees; // should use fetchTradingFees
409
+ return this.safeMarketStructure({
410
+ 'id': id,
411
+ 'symbol': base + '/' + quote,
412
+ 'base': base,
413
+ 'quote': quote,
414
+ 'settle': undefined,
415
+ 'baseId': baseId,
416
+ 'quoteId': quoteId,
417
+ 'settleId': undefined,
418
+ 'type': 'spot',
419
+ 'spot': true,
420
+ 'margin': false,
421
+ 'swap': false,
422
+ 'future': false,
423
+ 'option': false,
424
+ 'active': status,
425
+ 'contract': false,
426
+ 'linear': undefined,
427
+ 'inverse': undefined,
428
+ 'taker': fees['trading']['taker'],
429
+ 'maker': fees['trading']['maker'],
430
+ 'contractSize': undefined,
431
+ 'expiry': undefined,
432
+ 'expiryDatetime': undefined,
433
+ 'strike': undefined,
434
+ 'optionType': undefined,
435
+ 'precision': {
436
+ 'amount': amountPrecision,
437
+ 'price': pricePrecision,
438
+ },
439
+ 'limits': {
440
+ 'amount': {
441
+ 'min': undefined,
442
+ 'max': undefined,
443
+ },
444
+ 'price': {
445
+ 'min': undefined,
446
+ 'max': undefined,
447
+ },
448
+ 'cost': {
449
+ 'min': undefined,
450
+ 'max': undefined,
451
+ },
452
+ },
453
+ 'info': market,
454
+ 'created': created,
455
+ });
456
+ }
457
+ /**
458
+ * @method
459
+ * @name ellipx#fetchTicker
460
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
461
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.d2jylz4u6pmu
462
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
463
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
464
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
465
+ */
466
+ async fetchTicker(symbol, params = {}) {
467
+ await this.loadMarkets();
468
+ const market = this.market(symbol);
469
+ const marketId = market['id'];
470
+ const request = {
471
+ 'currencyPair': marketId,
472
+ };
473
+ const response = await this.publicGetMarketCurrencyPairTicker(this.extend(request, params));
474
+ //
475
+ // {
476
+ // "data": {
477
+ // "market": "BTC_USDC",
478
+ // "ticker": {
479
+ // "time": 1730814600,
480
+ // "count": 2135,
481
+ // "high": {
482
+ // "v": "74766990000",
483
+ // "e": 6,
484
+ // "f": 74766.99
485
+ // },
486
+ // "low": {
487
+ // "v": "68734020000",
488
+ // "e": 6,
489
+ // "f": 68734.02
490
+ // },
491
+ // "avg": {
492
+ // "v": "72347941430",
493
+ // "e": 6,
494
+ // "f": 72347.94143
495
+ // },
496
+ // "vwap": {
497
+ // "v": "73050064447",
498
+ // "e": 6,
499
+ // "f": 73050.064447
500
+ // },
501
+ // "vol": {
502
+ // "v": "4885361",
503
+ // "e": 8,
504
+ // "f": 0.04885361
505
+ // },
506
+ // "secvol": {
507
+ // "v": "3568759346",
508
+ // "e": 6,
509
+ // "f": 3568.759346
510
+ // },
511
+ // "open": {
512
+ // "v": "68784020000",
513
+ // "e": 6,
514
+ // "f": 68784.02
515
+ // },
516
+ // "close": {
517
+ // "v": "73955570000",
518
+ // "e": 6,
519
+ // "f": 73955.57
520
+ // }
521
+ // }
522
+ // },
523
+ // "request_id": "cbf183e0-7a62-4674-838c-6693031fa240",
524
+ // "result": "success",
525
+ // "time": 0.015463566
526
+ // }
527
+ //
528
+ const ticker = this.safeValue(response['data'], 'ticker', {});
529
+ return this.parseTicker(ticker, market);
530
+ }
531
+ parseTicker(ticker, market = undefined) {
532
+ const timestamp = this.safeIntegerProduct(ticker, 'time', 1000);
533
+ const open = this.parseAmount(this.safeValue(ticker, 'open'));
534
+ const high = this.parseAmount(this.safeValue(ticker, 'high'));
535
+ const low = this.parseAmount(this.safeValue(ticker, 'low'));
536
+ const close = this.parseAmount(this.safeValue(ticker, 'close'));
537
+ const avg = this.parseAmount(this.safeValue(ticker, 'avg'));
538
+ const vwap = this.parseAmount(this.safeValue(ticker, 'vwap'));
539
+ const baseVolume = this.parseAmount(this.safeValue(ticker, 'vol'));
540
+ const quoteVolume = this.parseAmount(this.safeValue(ticker, 'secvol'));
541
+ // const count = this.safeInteger(ticker, 'count'); not used
542
+ return this.safeTicker({
543
+ 'symbol': this.safeSymbol(undefined, market),
544
+ 'timestamp': timestamp,
545
+ 'datetime': this.iso8601(timestamp),
546
+ 'high': high,
547
+ 'low': low,
548
+ 'bid': undefined,
549
+ 'bidVolume': undefined,
550
+ 'ask': undefined,
551
+ 'askVolume': undefined,
552
+ 'vwap': vwap,
553
+ 'open': open,
554
+ 'close': close,
555
+ 'last': close,
556
+ 'previousClose': undefined,
557
+ 'change': undefined,
558
+ 'percentage': undefined,
559
+ 'average': avg,
560
+ 'baseVolume': baseVolume,
561
+ 'quoteVolume': quoteVolume,
562
+ 'info': ticker,
563
+ }, market);
564
+ }
565
+ /**
566
+ * @method
567
+ * @name ellipx#fetchOrderBook
568
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
569
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.bqmucewhkpdz
570
+ * @param {string} symbol unified symbol of the market to fetch the order book for
571
+ * @param {int} [limit] the maximum amount of order book entries to return the exchange not supported yet.
572
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
573
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
574
+ */
575
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
576
+ await this.loadMarkets();
577
+ const market = this.market(symbol);
578
+ const marketId = market['id'];
579
+ const request = {
580
+ 'currencyPair': marketId,
581
+ };
582
+ const response = await this.publicGetMarketCurrencyPairGetDepth(this.extend(request, params));
583
+ // {
584
+ // "data": {
585
+ // "asks": [
586
+ // {
587
+ // "price": {
588
+ // "v": "74941875231",
589
+ // "e": 6,
590
+ // "f": 74941.875231
591
+ // },
592
+ // "amount": {
593
+ // "v": "149",
594
+ // "e": 8,
595
+ // "f": 0.00000149
596
+ // }
597
+ // },
598
+ // {
599
+ // "price": {
600
+ // "v": "75063426037",
601
+ // "e": 6,
602
+ // "f": 75063.426037
603
+ // },
604
+ // "amount": {
605
+ // "v": "335",
606
+ // "e": 8,
607
+ // "f": 0.00000335
608
+ // }
609
+ // }
610
+ // ],
611
+ // "bids": [
612
+ // {
613
+ // "price": {
614
+ // "v": "64518711040",
615
+ // "e": 6,
616
+ // "f": 64518.71104
617
+ // },
618
+ // "amount": {
619
+ // "v": "132",
620
+ // "e": 8,
621
+ // "f": 0.00000132
622
+ // }
623
+ // },
624
+ // {
625
+ // "price": {
626
+ // "v": "64263569273",
627
+ // "e": 6,
628
+ // "f": 64263.569273
629
+ // },
630
+ // "amount": {
631
+ // "v": "210",
632
+ // "e": 8,
633
+ // "f": 0.0000021
634
+ // }
635
+ // }
636
+ // ],
637
+ // "market": "BTC_USDC"
638
+ // },
639
+ // "request_id": "71b7dffc-3120-4e46-a0bb-49ece5aea7e1",
640
+ // "result": "success",
641
+ // "time": 0.000074661
642
+ // }
643
+ const data = this.safeValue(response, 'data', {}); // exchange specific v e f params
644
+ const timestamp = this.milliseconds(); // the exchange does not provide timestamp for this.
645
+ const dataBidsLength = data['bids'].length;
646
+ const dataAsksLength = data['asks'].length;
647
+ for (let i = 0; i < dataBidsLength; i++) {
648
+ data['bids'][i]['price'] = this.parseAmount(data['bids'][i]['price']);
649
+ data['bids'][i]['amount'] = this.parseAmount(data['bids'][i]['amount']);
650
+ }
651
+ for (let i = 0; i < dataAsksLength; i++) {
652
+ data['asks'][i]['price'] = this.parseAmount(data['asks'][i]['price']);
653
+ data['asks'][i]['amount'] = this.parseAmount(data['asks'][i]['amount']);
654
+ }
655
+ return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'amount');
656
+ }
657
+ /**
658
+ * @method
659
+ * @name ellipx#fetchOHLCV
660
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market, default will return the last 24h period.
661
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.w65baeuhxwt8
662
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
663
+ * @param {string} timeframe the length of time each candle represents
664
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
665
+ * @param {int} [limit] the maximum amount of candles to fetch
666
+ * @param {object} [params] extra parameters specific to the API endpoint
667
+ * @returns {OHLCV[]} A list of candles ordered as timestamp, open, high, low, close, volume
668
+ */
669
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
670
+ await this.loadMarkets();
671
+ const methodName = 'fetchOHLCV';
672
+ let paginate = false;
673
+ [paginate, params] = this.handleOptionAndParams(params, methodName, 'paginate');
674
+ if (paginate) {
675
+ return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000);
676
+ }
677
+ const market = this.market(symbol);
678
+ const marketId = market['id'];
679
+ const time_frame = this.safeString(this.timeframes, timeframe, undefined);
680
+ const request = {
681
+ 'currencyPair': marketId,
682
+ 'interval': time_frame,
683
+ };
684
+ if (since !== undefined) {
685
+ request['start'] = Math.floor(since / 1000);
686
+ }
687
+ let until = undefined;
688
+ [until, params] = this.handleOptionAndParams(params, methodName, 'until');
689
+ if (until !== undefined) {
690
+ request['end'] = until;
691
+ }
692
+ // {
693
+ // "data": {
694
+ // "market": "BTC_USDC",
695
+ // "real_end": 1730970780,
696
+ // "requested_end": 1730970784,
697
+ // "start": 1730884200,
698
+ // "stats": [
699
+ // {
700
+ // "time": 1730884200,
701
+ // "count": 48,
702
+ // "high": {"v": "73898950000", "e": 6, "f": 73898.95},
703
+ // "low": {"v": "73642930000", "e": 6, "f": 73642.93},
704
+ // "open": {"v": "73830990000", "e": 6, "f": 73830.99},
705
+ // "close": {"v": "73682510000", "e": 6, "f": 73682.51},
706
+ // "vol": {"v": "88159", "e": 8, "f": 0.00088159}
707
+ // }
708
+ // ]
709
+ // }
710
+ // }
711
+ // No limit parameter supported by the API
712
+ const response = await this.publicGetMarketCurrencyPairGetGraph(this.extend(request, params));
713
+ const data = this.safeDict(response, 'data', {});
714
+ const ohlcv = this.safeList(data, 'stats', []);
715
+ return this.parseOHLCVs(ohlcv, market, timeframe, since, limit);
716
+ }
717
+ parseOHLCV(ohlcv, market = undefined) {
718
+ return [
719
+ this.safeInteger(ohlcv, 'time') * 1000,
720
+ this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'open'))),
721
+ this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'high'))),
722
+ this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'low'))),
723
+ this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'close'))),
724
+ this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'vol'))), // volume
725
+ ];
726
+ }
727
+ /**
728
+ * @method
729
+ * @name ellipx#fetchCurrencies
730
+ * @description fetches information on all currencies from the exchange, including deposit/withdrawal details and available chains
731
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.x65f9s9j74jf
732
+ * @param {object} [params] extra parameters specific to the ellipx API endpoint
733
+ * @param {string} [params.Can_Deposit] filter currencies by deposit availability, Y for available
734
+ * @param {number} [params.results_per_page] number of results per page, default 100
735
+ * @param {string} [params._expand] additional fields to expand in response, default '/Crypto_Token,/Crypto_Chain'
736
+ * @returns {Promise<Currencies>} An object of currency structures indexed by currency codes
737
+ */
738
+ async fetchCurrencies(params = {}) {
739
+ const response = await this._restGetCryptoTokenInfo(this.extend({
740
+ 'Can_Deposit': 'Y',
741
+ 'results_per_page': 100,
742
+ '_expand': '/Crypto_Token,/Crypto_Chain',
743
+ }, params));
744
+ const currencies = {};
745
+ const data = this.safeValue(response, 'data', []);
746
+ for (let i = 0; i < data.length; i++) {
747
+ const currency = this.parseCurrency(data[i]);
748
+ const code = this.safeString(currency, 'code');
749
+ if (code !== undefined) {
750
+ currencies[code] = currency;
751
+ }
752
+ }
753
+ return currencies;
754
+ }
755
+ parseCurrency(currency) {
756
+ const id = this.safeString(currency, 'Crypto_Token__');
757
+ const token = this.safeValue(currency, 'Crypto_Token', {});
758
+ const code = this.safeCurrencyCode(this.safeString(token, 'Symbol'));
759
+ const name = this.safeString(token, 'Name');
760
+ const active = this.safeString(currency, 'Status') === 'valid';
761
+ const deposit = this.safeString(currency, 'Can_Deposit') === 'Y';
762
+ const withdraw = this.safeString(currency, 'Status') === 'valid';
763
+ let fee = undefined;
764
+ if (currency['Withdraw_Fee'] !== undefined) {
765
+ fee = this.parseNumber(this.parseAmount(currency['Withdraw_Fee']));
766
+ }
767
+ const precision = this.parseNumber(this.parsePrecision(this.safeString(token, 'Decimals')));
768
+ let minDeposit = undefined;
769
+ if (currency['Minimum_Deposit'] !== undefined) {
770
+ minDeposit = this.parseAmount(currency['Minimum_Deposit']);
771
+ }
772
+ let minWithdraw = undefined;
773
+ if (currency['Minimum_Withdraw'] !== undefined) {
774
+ minWithdraw = this.parseAmount(currency['Minimum_Withdraw']);
775
+ }
776
+ const networkId = this.safeString(currency, 'Crypto_Chain__');
777
+ const networkData = this.safeValue(currency, 'Crypto_Chain', {});
778
+ const networkCode = this.safeString(networkData, 'Type', 'default');
779
+ const networks = {
780
+ 'string': undefined,
781
+ 'info': networkCode === 'default' ? {} : networkData,
782
+ 'id': networkId || id || '',
783
+ 'network': networkCode,
784
+ 'active': active,
785
+ 'deposit': deposit,
786
+ 'withdraw': withdraw,
787
+ 'fee': fee,
788
+ 'precision': precision,
789
+ 'limits': {
790
+ 'deposit': {
791
+ 'min': minDeposit,
792
+ 'max': undefined,
793
+ },
794
+ 'withdraw': {
795
+ 'min': minWithdraw,
796
+ 'max': undefined,
797
+ },
798
+ },
799
+ };
800
+ const result = {
801
+ 'info': currency,
802
+ 'id': id,
803
+ 'code': code,
804
+ 'name': name,
805
+ 'active': active,
806
+ 'deposit': deposit,
807
+ 'withdraw': withdraw,
808
+ 'fee': fee,
809
+ 'precision': precision,
810
+ 'type': undefined,
811
+ 'limits': {
812
+ 'amount': {
813
+ 'min': undefined,
814
+ 'max': undefined,
815
+ },
816
+ 'withdraw': {
817
+ 'min': minWithdraw,
818
+ 'max': undefined,
819
+ },
820
+ },
821
+ 'networks': networks,
822
+ };
823
+ return result;
824
+ }
825
+ /**
826
+ * @method
827
+ * @name ellipx#fetchTrades
828
+ * @description fetches all completed trades for a particular market/symbol
829
+ * @param {string} symbol unified market symbol (e.g. 'BTC/USDT')
830
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
831
+ * @param {int} [limit] the maximum amount of trades to fetch
832
+ * @param {object} [params] extra parameters specific to the EllipX API endpoint
833
+ * @param {string} [params.before] get trades before the given trade ID
834
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
835
+ */
836
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
837
+ await this.loadMarkets();
838
+ const market = this.market(symbol);
839
+ const marketId = market['id'];
840
+ const request = {
841
+ 'currencyPair': marketId,
842
+ };
843
+ // endpoint support before trade id.
844
+ // The actual endpoint URL will be: https://data.ellipx.com/Market/{currencyPair}:getTrades
845
+ // {
846
+ // "id": "BTC_USDC:1731053859:914141972:0",
847
+ // "pair": [
848
+ // "BTC",
849
+ // "USDC"
850
+ // ],
851
+ // "bid": {
852
+ // "id": "mktor-swishf-uv6n-hrzj-63ye-bdqnk33q",
853
+ // "iss": "ellipx:beta",
854
+ // "uniq": "order:1731053859:914141972:0"
855
+ // },
856
+ // "ask": {
857
+ // "id": "mktor-p3ozvt-qurz-gmzo-bf5n-g4rcuy6u",
858
+ // "iss": "ellipx:beta",
859
+ // "uniq": "order:1731053859:874659786:0"
860
+ // },
861
+ // "type": "bid",
862
+ // "amount": {
863
+ // "v": "412",
864
+ // "e": 8,
865
+ // "f": 0.00000412
866
+ // },
867
+ // "price": {
868
+ // "v": "75878090000",
869
+ // "e": 6,
870
+ // "f": 75878.09
871
+ // },
872
+ // "date": "2024-11-08T08:17:39.914141972Z"
873
+ // }
874
+ const response = await this.publicGetMarketCurrencyPairGetTrades(this.extend(request, params));
875
+ const data = this.safeDict(response, 'data', {});
876
+ const trades = this.safeList(data, 'trades', []);
877
+ return this.parseTrades(trades, market, since, limit);
878
+ }
879
+ parseTrade(trade, market = undefined) {
880
+ // Format of trade ID: "BTC_USDC:1731053859:914141972:0"
881
+ const id = this.safeString(trade, 'id');
882
+ // fetchTrades and fetchMyTrades return different trade structures
883
+ const date = this.safeDict(trade, 'date');
884
+ let timestamp = undefined;
885
+ if (date === undefined) {
886
+ timestamp = this.parse8601(this.safeString(trade, 'date'));
887
+ }
888
+ else {
889
+ timestamp = this.safeInteger(date, 'unixms');
890
+ }
891
+ const type = this.safeString(trade, 'type');
892
+ const side = (type === 'bid') ? 'buy' : 'sell';
893
+ const amount = this.safeDict(trade, 'amount');
894
+ const price = this.safeDict(trade, 'price');
895
+ const amountFloat = this.parseAmount(amount);
896
+ const priceFloat = this.parseAmount(price);
897
+ // fetchTrades and fetchMyTrades return different trade structures
898
+ const pair = this.safeList(trade, 'pair');
899
+ let marketSymbol = undefined;
900
+ if (pair === undefined) {
901
+ const symbol = this.safeString(trade, 'pair');
902
+ const [base, quote] = symbol.split('_');
903
+ marketSymbol = base + '/' + quote;
904
+ }
905
+ else {
906
+ marketSymbol = this.safeString(pair, 0) + '/' + this.safeString(pair, 1);
907
+ }
908
+ const bidOrder = this.safeDict(trade, 'bid');
909
+ const askOrder = this.safeDict(trade, 'ask');
910
+ const isBuy = (side === 'buy');
911
+ const orderId = isBuy ? this.safeString(bidOrder, 'id') : this.safeString(askOrder, 'id');
912
+ return this.safeTrade({
913
+ 'id': id,
914
+ 'info': trade,
915
+ 'timestamp': timestamp,
916
+ 'datetime': this.iso8601(timestamp),
917
+ 'symbol': marketSymbol,
918
+ 'type': undefined,
919
+ 'side': side,
920
+ 'order': orderId,
921
+ 'takerOrMaker': undefined,
922
+ 'price': priceFloat,
923
+ 'amount': amountFloat,
924
+ 'cost': undefined,
925
+ 'fee': undefined,
926
+ });
927
+ }
928
+ /**
929
+ * @method
930
+ * @name ellipx#fetchBalance
931
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
932
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.ihrjov144txg
933
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
934
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
935
+ */
936
+ async fetchBalance(params = {}) {
937
+ await this.loadMarkets();
938
+ const response = await this.privateGetUserWallet(params);
939
+ // {
940
+ // "User_Wallet__": "usw-vv7hzo-qel5-gupk-neqi-7f3wz5pq",
941
+ // "User__": "usr-...",
942
+ // "Realm__": "usrr-cb3c7n-qvxv-fdrb-uc2q-gpja2foi",
943
+ // "Unit__": "unit-aebkye-u35b-e5zm-zt22-2qvwhsqa",
944
+ // "Balance": {
945
+ // "value": "0.00006394",
946
+ // "value_int": "6394",
947
+ // "value_disp": "0.00006394",
948
+ // "value_xint": {
949
+ // "v": "6394",
950
+ // "e": 8,
951
+ // "f": 0.00006394
952
+ // },
953
+ // "display": "0.00006394BTC",
954
+ // "display_short": "0.00006394BTC",
955
+ // "currency": "BTC",
956
+ // "unit": "BTC",
957
+ // "has_vat": false,
958
+ // "tax_profile": null
959
+ // },
960
+ // "Balance_Date": {
961
+ // "unix": 1731128270,
962
+ // "us": 426208,
963
+ // "iso": "2024-11-09 04:57:50.426208",
964
+ // "tz": "UTC",
965
+ // "full": "1731128270426208",
966
+ // "unixms": "1731128270426"
967
+ // },
968
+ // "Liabilities": {
969
+ // "value": "0.00000000",
970
+ // "value_int": "0",
971
+ // "value_disp": "0.00000000",
972
+ // "value_xint": {
973
+ // "v": "0",
974
+ // "e": 8,
975
+ // "f": 0
976
+ // },
977
+ // "display": "0.00000000BTC",
978
+ // "display_short": "0.00000000BTC",
979
+ // "currency": "BTC",
980
+ // "unit": "BTC",
981
+ // "has_vat": false,
982
+ // "tax_profile": null
983
+ // },
984
+ // "Index": "5",
985
+ // "Backend": "virtual",
986
+ // "Disable_Limits": "N",
987
+ // "Unencumbered_Balance": {
988
+ // "value": "0.00006394",
989
+ // "value_int": "6394",
990
+ // "value_disp": "0.00006394",
991
+ // "value_xint": {
992
+ // "v": "6394",
993
+ // "e": 8,
994
+ // "f": 0.00006394
995
+ // },
996
+ // "display": "0.00006394BTC",
997
+ // "display_short": "0.00006394BTC",
998
+ // "currency": "BTC",
999
+ // "unit": "BTC",
1000
+ // "has_vat": false,
1001
+ // "tax_profile": null
1002
+ // }
1003
+ // }
1004
+ const result = {
1005
+ 'info': response,
1006
+ 'timestamp': undefined,
1007
+ 'datetime': undefined,
1008
+ };
1009
+ const dataArray = this.safeList(response, 'data', []);
1010
+ // Use first item's timestamp if available
1011
+ const dataArrayLength = dataArray.length;
1012
+ if (dataArrayLength > 0) {
1013
+ const firstItem = dataArray[0];
1014
+ const balanceDate = this.safeDict(firstItem, 'Balance_Date', {});
1015
+ result['timestamp'] = this.safeInteger(balanceDate, 'unixms');
1016
+ result['datetime'] = this.iso8601(result['timestamp']);
1017
+ }
1018
+ // Process each balance entry
1019
+ for (let i = 0; i < dataArray.length; i++) {
1020
+ const entry = dataArray[i];
1021
+ const balance = this.safeDict(entry, 'Balance', {});
1022
+ const currency = this.safeString(balance, 'currency');
1023
+ if (currency !== undefined) {
1024
+ const account = {
1025
+ 'free': this.parseAmount(entry['Unencumbered_Balance']['value_xint']),
1026
+ 'used': this.parseAmount(entry['Liabilities']['value_xint']),
1027
+ 'total': this.parseAmount(balance['value_xint']),
1028
+ };
1029
+ result[currency] = account;
1030
+ }
1031
+ }
1032
+ return this.safeBalance(result);
1033
+ }
1034
+ /**
1035
+ * @method
1036
+ * @name ellipx#createOrder
1037
+ * @description create a new order in a market
1038
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.yzfak2n2bwpo
1039
+ * @param {string} symbol unified market symbol (e.g. 'BTC/USDT')
1040
+ * @param {string} type order type - the exchange automatically sets type to 'limit' if price defined, 'market' if undefined
1041
+ * @param {string} side 'buy' or 'sell'
1042
+ * @param {float} [amount] amount of base currency to trade (can be undefined if using Spend_Limit)
1043
+ * @param {float} [price] price per unit of base currency for limit orders
1044
+ * @param {object} [params] extra parameters specific to the EllipX API endpoint
1045
+ * @param {float} [params.cost] maximum amount to spend in quote currency (required for market orders if amount undefined)
1046
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1047
+ */
1048
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
1049
+ await this.loadMarkets();
1050
+ const market = this.market(symbol);
1051
+ // the exchange automatically sets the type to 'limit' if the price is defined and to 'market' if it is not
1052
+ const marketId = market['id'];
1053
+ let orderType = 'bid';
1054
+ if (side === 'buy') {
1055
+ orderType = 'bid';
1056
+ }
1057
+ else {
1058
+ orderType = 'ask';
1059
+ }
1060
+ const request = {
1061
+ 'currencyPair': marketId,
1062
+ 'Type': orderType,
1063
+ };
1064
+ if (amount !== undefined) {
1065
+ request['Amount'] = this.amountToPrecision(symbol, amount);
1066
+ }
1067
+ if (price !== undefined) {
1068
+ request['Price'] = this.priceToPrecision(symbol, price);
1069
+ }
1070
+ const cost = this.safeString(params, 'cost');
1071
+ if (cost !== undefined) {
1072
+ params = this.omit(params, 'cost');
1073
+ request['Spend_Limit'] = this.priceToPrecision(symbol, cost);
1074
+ }
1075
+ const response = await this.privatePostMarketCurrencyPairOrder(this.extend(request, params));
1076
+ // {
1077
+ // "result": "success",
1078
+ // "data": {
1079
+ // "Market_Order__": "mktor-x2grmu-zwo5-fyxc-4gue-vd4ouvsa",
1080
+ // "Market__": "mkt-lrnp2e-eaor-eobj-ua73-75j6sjxe",
1081
+ // "User__": "usr-...",
1082
+ // "Uniq": "order:1728719021:583795548:0",
1083
+ // "Type": "bid",
1084
+ // "Status": "pending",
1085
+ // "Flags": {},
1086
+ // "Amount": {
1087
+ // "v": "100000000",
1088
+ // "e": 8,
1089
+ // "f": 1
1090
+ // },
1091
+ // "Price": null,
1092
+ // "Spend_Limit": {
1093
+ // "v": "1000000",
1094
+ // "e": 6,
1095
+ // "f": 1
1096
+ // },
1097
+ // "Executed": {
1098
+ // "v": "0",
1099
+ // "e": 0,
1100
+ // "f": 0
1101
+ // },
1102
+ // "Secured": {
1103
+ // "v": "1000000",
1104
+ // "e": 6,
1105
+ // "f": 1
1106
+ // },
1107
+ // "Version": "0",
1108
+ // "Created": {
1109
+ // "unix": 1728719020,
1110
+ // "us": 315195,
1111
+ // "iso": "2024-10-12 07:43:40.315195",
1112
+ // "tz": "UTC",
1113
+ // "full": "1728719020315195",
1114
+ // "unixms": "1728719020315"
1115
+ // },
1116
+ // "Updated": {
1117
+ // "unix": 1728719020,
1118
+ // "us": 315195,
1119
+ // "iso": "2024-10-12 07:43:40.315195",
1120
+ // "tz": "UTC",
1121
+ // "full": "1728719020315195",
1122
+ // "unixms": "1728719020315"
1123
+ // }
1124
+ // }
1125
+ // }
1126
+ const order = this.safeDict(response, 'data', {});
1127
+ return this.parseOrder(order, market);
1128
+ }
1129
+ /**
1130
+ * @method
1131
+ * @name ellipx#fetchOrder
1132
+ * @description fetches information on an order made by the user
1133
+ * @param {string} id the order ID as returned by createOrder or fetchOrders
1134
+ * @param {string|undefined} symbol not used by ellipx.fetchOrder
1135
+ * @param {object} [params] extra parameters specific to the EllipX API endpoint
1136
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1137
+ */
1138
+ async fetchOrder(id, symbol = undefined, params = {}) {
1139
+ await this.loadMarkets();
1140
+ const request = {
1141
+ 'orderUuid': id,
1142
+ };
1143
+ const response = await this.privateGetMarketOrderOrderUuid(this.extend(request, params));
1144
+ const data = this.safeDict(response, 'data', {});
1145
+ return this.parseOrder(data, undefined);
1146
+ }
1147
+ /**
1148
+ * @method
1149
+ * @name ellipx#fetchOrdersByStatus
1150
+ * @description fetches a list of orders placed on the exchange
1151
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.5z2nh2b5s81n
1152
+ * @param {string} status 'open' or 'closed', omit for all orders
1153
+ * @param {string} symbol unified market symbol
1154
+ * @param {int} [since] timestamp in ms of the earliest order
1155
+ * @param {int} [limit] the maximum amount of orders to fetch
1156
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1157
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1158
+ */
1159
+ async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1160
+ await this.loadMarkets();
1161
+ let market = undefined;
1162
+ const request = {};
1163
+ if (symbol !== undefined) {
1164
+ market = this.market(symbol);
1165
+ const marketId = market['id'];
1166
+ request['currencyPair'] = marketId;
1167
+ }
1168
+ if (status !== undefined) {
1169
+ request['Status'] = status;
1170
+ }
1171
+ const response = await this.privateGetMarketCurrencyPairOrder(this.extend(request, params));
1172
+ // {
1173
+ // "result": "success",
1174
+ // "data": [
1175
+ // {
1176
+ // "Market_Order__": "mktor-aglvd2-iy5v-enbj-nwrb-scqsnosa",
1177
+ // "Market__": "mkt-lrnp2e-eaor-eobj-ua73-75j6sjxe",
1178
+ // "User__": "usr-...",
1179
+ // "Uniq": "order:1728712511:964332600:0",
1180
+ // "Type": "ask",
1181
+ // "Status": "open",
1182
+ // "Flags": {},
1183
+ // "Amount": {
1184
+ // "v": "1",
1185
+ // "e": 8,
1186
+ // "f": 1.0e-8
1187
+ // },
1188
+ // "Price": {
1189
+ // "v": "63041306872",
1190
+ // "e": 6,
1191
+ // "f": 63041.306872
1192
+ // },
1193
+ // "Spend_Limit": null,
1194
+ // "Executed": {
1195
+ // "v": "892",
1196
+ // "e": 8,
1197
+ // "f": 8.92e-6
1198
+ // },
1199
+ // "Secured": null,
1200
+ // "Version": "3",
1201
+ // "Created": {
1202
+ // "unix": 1728712510,
1203
+ // "us": 669096,
1204
+ // "iso": "2024-10-12 05:55:10.669096",
1205
+ // "tz": "UTC",
1206
+ // "full": "1728712510669096",
1207
+ // "unixms": "1728712510669"
1208
+ // },
1209
+ // "Updated": {
1210
+ // "unix": 1728712510,
1211
+ // "us": 669096,
1212
+ // "iso": "2024-10-12 05:55:10.669096",
1213
+ // "tz": "UTC",
1214
+ // "full": "1728712510669096",
1215
+ // "unixms": "1728712510669"
1216
+ // }
1217
+ // }
1218
+ // ],
1219
+ // "paging": {
1220
+ // "page_no": 1,
1221
+ // "count": "1",
1222
+ // "page_max": 1,
1223
+ // "results_per_page": 20
1224
+ // }
1225
+ // }
1226
+ const data = this.safeValue(response, 'data', []);
1227
+ return this.parseOrders(data, market, since, limit);
1228
+ }
1229
+ /**
1230
+ * @method
1231
+ * @name ellipx#fetchOrders
1232
+ * @description fetches information on multiple orders made by the user
1233
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.5z2nh2b5s81n
1234
+ * @param {string} symbol unified market symbol of the market orders were made in
1235
+ * @param {int|undefined} since timestamp in ms of the earliest order
1236
+ * @param {int|undefined} limit the maximum amount of orders to fetch
1237
+ * @param {object} params extra parameters specific to the exchange API endpoint
1238
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1239
+ */
1240
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1241
+ if (symbol === undefined) {
1242
+ throw new errors.ArgumentsRequired(this.id + ' fetchOrders requires a symbol parameter');
1243
+ }
1244
+ return await this.fetchOrdersByStatus(undefined, symbol, since, limit, params);
1245
+ }
1246
+ /**
1247
+ * @method
1248
+ * @name ellipx#fetchOpenOrders
1249
+ * @description fetches information on open orders made by the user
1250
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.5z2nh2b5s81n
1251
+ * @param {string} symbol unified market symbol of the market orders were made in
1252
+ * @param {int|undefined} since timestamp in ms of the earliest order
1253
+ * @param {int|undefined} limit the maximum amount of orders to fetch
1254
+ * @param {object} params extra parameters specific to the exchange API endpoint
1255
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1256
+ */
1257
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1258
+ if (symbol === undefined) {
1259
+ throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders requires a symbol parameter');
1260
+ }
1261
+ return await this.fetchOrdersByStatus('open', symbol, since, limit, params);
1262
+ }
1263
+ parseOrder(order, market = undefined) {
1264
+ const id = this.safeString(order, 'Market_Order__');
1265
+ const timestamp = this.safeInteger(this.safeDict(order, 'Created'), 'unixms');
1266
+ const orderType = this.safeString(order, 'Type');
1267
+ let side = 'sell';
1268
+ if (orderType === 'bid') {
1269
+ side = 'buy';
1270
+ }
1271
+ const status = this.parseOrderStatus(this.safeString(order, 'Status'));
1272
+ const amount = this.parseNumber(this.parseAmount(this.safeDict(order, 'Amount')));
1273
+ const price = this.parseNumber(this.parseAmount(this.safeDict(order, 'Price')));
1274
+ const type = (price === undefined) ? 'market' : 'limit';
1275
+ const executed = this.parseNumber(this.parseAmount(this.safeDict(order, 'Executed')));
1276
+ const filled = executed;
1277
+ const remaining = this.parseNumber(this.parseAmount(this.safeDict(order, 'Secured')));
1278
+ const cost = this.parseNumber(this.parseAmount(this.safeDict(order, 'Total_Spent')));
1279
+ const symbol = market ? market['symbol'] : undefined;
1280
+ const clientOrderId = undefined;
1281
+ const timeInForce = 'GTC'; // default to Good Till Cancelled
1282
+ const postOnly = false;
1283
+ const updated = this.safeDict(order, 'Updated', {});
1284
+ const lastTradeTimestamp = this.safeInteger(updated, 'unixms', undefined);
1285
+ return this.safeOrder({
1286
+ 'id': id,
1287
+ 'clientOrderId': clientOrderId,
1288
+ 'info': order,
1289
+ 'timestamp': timestamp,
1290
+ 'datetime': this.iso8601(timestamp),
1291
+ 'lastTradeTimestamp': lastTradeTimestamp,
1292
+ 'status': this.parseOrderStatus(status),
1293
+ 'symbol': symbol,
1294
+ 'type': type,
1295
+ 'timeInForce': timeInForce,
1296
+ 'postOnly': postOnly,
1297
+ 'side': side,
1298
+ 'price': price,
1299
+ 'stopPrice': undefined,
1300
+ 'triggerPrice': undefined,
1301
+ 'average': undefined,
1302
+ 'cost': cost,
1303
+ 'amount': amount,
1304
+ 'filled': filled,
1305
+ 'remaining': remaining,
1306
+ 'fee': undefined,
1307
+ 'trades': undefined,
1308
+ }, market);
1309
+ }
1310
+ /**
1311
+ * @method
1312
+ * @name ellipx#cancelOrder
1313
+ * @description Cancels an open order on the exchange
1314
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.f1qu1pb1rebn
1315
+ * @param {string} id - The order ID to cancel (format: mktor-xxxxx-xxxx-xxxx-xxxx-xxxxxxxx)
1316
+ * @param {string} [symbol] - ellipx.cancelOrder does not use the symbol parameter
1317
+ * @param {object} [params] - Extra parameters specific to the exchange API
1318
+ * @returns {Promise<object>} A Promise that resolves to the canceled order info
1319
+ */
1320
+ async cancelOrder(id, symbol = undefined, params = {}) {
1321
+ await this.loadMarkets();
1322
+ const request = {
1323
+ 'orderUuid': id,
1324
+ };
1325
+ const response = await this.privateDeleteMarketOrderOrderUuid(this.extend(request, params));
1326
+ // {
1327
+ // result: "success",
1328
+ // request_id: "887dba33-d11b-43f0-8034-dd7890882cc5",
1329
+ // time: "0.8975801467895508",
1330
+ // data: true,
1331
+ // access: {
1332
+ // "mktor-rf5k5b-5fhf-dmde-wxqj-3y23jeii": {
1333
+ // required: "A",
1334
+ // available: "O",
1335
+ // },
1336
+ // },
1337
+ // }
1338
+ // this endpoint always returns true and a warning message if the order cancelled before.
1339
+ const warningResponse = this.safeValue(response, 'warning', undefined);
1340
+ const statusResponse = this.safeBool(response, 'data');
1341
+ let status = 'canceled';
1342
+ if (statusResponse !== true || warningResponse !== undefined) {
1343
+ status = 'closed';
1344
+ }
1345
+ return this.safeOrder({
1346
+ 'id': id,
1347
+ 'clientOrderId': undefined,
1348
+ 'info': this.json(response),
1349
+ 'timestamp': undefined,
1350
+ 'datetime': undefined,
1351
+ 'lastTradeTimestamp': undefined,
1352
+ 'status': status,
1353
+ 'symbol': undefined,
1354
+ 'type': undefined,
1355
+ 'timeInForce': undefined,
1356
+ 'postOnly': undefined,
1357
+ 'side': undefined,
1358
+ 'price': undefined,
1359
+ 'stopPrice': undefined,
1360
+ 'triggerPrice': undefined,
1361
+ 'average': undefined,
1362
+ 'cost': undefined,
1363
+ 'amount': undefined,
1364
+ 'filled': undefined,
1365
+ 'remaining': undefined,
1366
+ 'fee': undefined,
1367
+ 'trades': undefined,
1368
+ }, undefined);
1369
+ }
1370
+ /**
1371
+ * @method
1372
+ * @name ellipx#fetchOrderTrades
1373
+ * @description fetch all the trades made from a single order
1374
+ * @param {string} id order id
1375
+ * @param {string} symbol unified market symbol
1376
+ * @param {int} [since] the earliest time in ms to fetch trades for
1377
+ * @param {int} [limit] the maximum number of trades to retrieve
1378
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1379
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
1380
+ */
1381
+ async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1382
+ if (symbol === undefined) {
1383
+ throw new errors.ArgumentsRequired('fetchMyTrades requires a symbol parameter');
1384
+ }
1385
+ await this.loadMarkets();
1386
+ const market = this.market(symbol);
1387
+ const currencyPair = market['id'];
1388
+ const request = {
1389
+ 'Market_Order__': id,
1390
+ 'currencyPair': currencyPair,
1391
+ };
1392
+ const response = await this.privateGetMarketCurrencyPairTrade(this.extend(request, params));
1393
+ // {
1394
+ // "result": "success",
1395
+ // "request_id": "fc5be99d-d085-46f8-9228-e46d0996f112",
1396
+ // "time": 0.030913114547729492,
1397
+ // "data": [
1398
+ // {
1399
+ // "id": "DOGE_USDC:1731505789:911642994:0",
1400
+ // "pair": "DOGE_USDC",
1401
+ // "bid": {
1402
+ // "id": "mktor-xb3ne5-emm5-fx7e-xggk-fyfoiye4"
1403
+ // },
1404
+ // "ask": {
1405
+ // "id": "mktor-oxmac4-mtkf-gi3o-mamg-u2cboqe4"
1406
+ // },
1407
+ // "type": "bid",
1408
+ // "amount": {
1409
+ // "v": "334609419",
1410
+ // "e": 8,
1411
+ // "f": 3.34609419
1412
+ // },
1413
+ // "price": {
1414
+ // "v": "410673",
1415
+ // "e": 6,
1416
+ // "f": 0.410673
1417
+ // },
1418
+ // "date": {
1419
+ // "unix": 1731505789,
1420
+ // "us": 911642,
1421
+ // "iso": "2024-11-13 13:49:49.911642",
1422
+ // "tz": "UTC",
1423
+ // "full": "1731505789911642",
1424
+ // "unixms": "1731505789911"
1425
+ // }
1426
+ // },
1427
+ // {
1428
+ // "id": "DOGE_USDC:1731505789:911642994:4",
1429
+ // "pair": "DOGE_USDC",
1430
+ // "bid": {
1431
+ // "id": "mktor-xb3ne5-emm5-fx7e-xggk-fyfoiye4"
1432
+ // },
1433
+ // "ask": {
1434
+ // "id": "mktor-cmtztk-3z3n-gupp-uqdg-74g4wjfq"
1435
+ // },
1436
+ // "type": "bid",
1437
+ // "amount": {
1438
+ // "v": "145453950",
1439
+ // "e": 8,
1440
+ // "f": 1.4545395
1441
+ // },
1442
+ // "price": {
1443
+ // "v": "412589",
1444
+ // "e": 6,
1445
+ // "f": 0.412589
1446
+ // },
1447
+ // "date": {
1448
+ // "unix": 1731505789,
1449
+ // "us": 911642,
1450
+ // "iso": "2024-11-13 13:49:49.911642",
1451
+ // "tz": "UTC",
1452
+ // "full": "1731505789911642",
1453
+ // "unixms": "1731505789911"
1454
+ // }
1455
+ // },
1456
+ // {
1457
+ // "id": "DOGE_USDC:1731505789:911642994:2",
1458
+ // "pair": "DOGE_USDC",
1459
+ // "bid": {
1460
+ // "id": "mktor-xb3ne5-emm5-fx7e-xggk-fyfoiye4"
1461
+ // },
1462
+ // "ask": {
1463
+ // "id": "mktor-6tyslh-b33b-flnm-2ata-acjkco4y"
1464
+ // },
1465
+ // "type": "bid",
1466
+ // "amount": {
1467
+ // "v": "587627076",
1468
+ // "e": 8,
1469
+ // "f": 5.87627076
1470
+ // },
1471
+ // "price": {
1472
+ // "v": "411005",
1473
+ // "e": 6,
1474
+ // "f": 0.411005
1475
+ // },
1476
+ // "date": {
1477
+ // "unix": 1731505789,
1478
+ // "us": 911642,
1479
+ // "iso": "2024-11-13 13:49:49.911642",
1480
+ // "tz": "UTC",
1481
+ // "full": "1731505789911642",
1482
+ // "unixms": "1731505789911"
1483
+ // }
1484
+ // },
1485
+ // {
1486
+ // "id": "DOGE_USDC:1731505789:911642994:1",
1487
+ // "pair": "DOGE_USDC",
1488
+ // "bid": {
1489
+ // "id": "mktor-xb3ne5-emm5-fx7e-xggk-fyfoiye4"
1490
+ // },
1491
+ // "ask": {
1492
+ // "id": "mktor-ihpjlj-5ufj-dm5l-fmud-oftkqcgu"
1493
+ // },
1494
+ // "type": "bid",
1495
+ // "amount": {
1496
+ // "v": "475845734",
1497
+ // "e": 8,
1498
+ // "f": 4.75845734
1499
+ // },
1500
+ // "price": {
1501
+ // "v": "410830",
1502
+ // "e": 6,
1503
+ // "f": 0.41083
1504
+ // },
1505
+ // "date": {
1506
+ // "unix": 1731505789,
1507
+ // "us": 911642,
1508
+ // "iso": "2024-11-13 13:49:49.911642",
1509
+ // "tz": "UTC",
1510
+ // "full": "1731505789911642",
1511
+ // "unixms": "1731505789911"
1512
+ // }
1513
+ // },
1514
+ // {
1515
+ // "id": "DOGE_USDC:1731505789:911642994:3",
1516
+ // "pair": "DOGE_USDC",
1517
+ // "bid": {
1518
+ // "id": "mktor-xb3ne5-emm5-fx7e-xggk-fyfoiye4"
1519
+ // },
1520
+ // "ask": {
1521
+ // "id": "mktor-d2uyb3-nzsj-aevn-dikr-tq3sxhre"
1522
+ // },
1523
+ // "type": "bid",
1524
+ // "amount": {
1525
+ // "v": "641013461",
1526
+ // "e": 8,
1527
+ // "f": 6.41013461
1528
+ // },
1529
+ // "price": {
1530
+ // "v": "411846",
1531
+ // "e": 6,
1532
+ // "f": 0.411846
1533
+ // },
1534
+ // "date": {
1535
+ // "unix": 1731505789,
1536
+ // "us": 911642,
1537
+ // "iso": "2024-11-13 13:49:49.911642",
1538
+ // "tz": "UTC",
1539
+ // "full": "1731505789911642",
1540
+ // "unixms": "1731505789911"
1541
+ // }
1542
+ // }
1543
+ // ],
1544
+ // "access": {
1545
+ // "mkt-xrkg5l-akjz-cxxl-3a2e-mul5gfo4": {
1546
+ // "required": "r",
1547
+ // "available": "?"
1548
+ // },
1549
+ // "mktor-xb3ne5-emm5-fx7e-xggk-fyfoiye4": {
1550
+ // "required": "R",
1551
+ // "available": "O"
1552
+ // }
1553
+ // },
1554
+ // "paging": {
1555
+ // "page_no": 1,
1556
+ // "count": "5",
1557
+ // "page_max": 1,
1558
+ // "results_per_page": 20
1559
+ // }
1560
+ // }
1561
+ const data = this.safeList(response, 'data');
1562
+ return this.parseTrades(data, market, since, limit);
1563
+ }
1564
+ /**
1565
+ * @method
1566
+ * @name ellipx#fetchDepositAddress
1567
+ * @description fetches a crypto deposit address for a specific currency
1568
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.k7qe5aricayh
1569
+ * @param {string} code unified currency code (e.g. "BTC", "ETH", "USDT")
1570
+ * @param {object} [params] extra parameters specific to the EllipX API endpoint
1571
+ * @returns {object} an address structure {
1572
+ * 'currency': string, // unified currency code
1573
+ * 'address': string, // the address for deposits
1574
+ * 'tag': string|undefined, // tag/memo for deposits if needed
1575
+ * 'network': object, // network object from currency info
1576
+ * 'info': object // raw response from exchange
1577
+ * }
1578
+ * @throws {ExchangeError} if currency does not support deposits
1579
+ */
1580
+ async fetchDepositAddress(code, params = {}) {
1581
+ await this.loadMarkets();
1582
+ const currency = this.currency(code);
1583
+ const network = this.safeValue(currency['info'], 'Crypto_Chain', undefined);
1584
+ const request = {
1585
+ 'Crypto_Token__': this.safeString(network, 'Crypto_Token__'),
1586
+ 'Crypto_Chain__': this.safeString(network, 'Crypto_Chain__'),
1587
+ };
1588
+ const response = await this.privatePostCryptoAddressFetch(this.extend(request, params));
1589
+ const data = this.safeValue(response, 'data', {});
1590
+ const address = this.safeString(data, 'Address');
1591
+ const tag = this.safeString(data, 'memo');
1592
+ this.checkAddress(address);
1593
+ return {
1594
+ 'currency': code,
1595
+ 'address': address,
1596
+ 'tag': tag,
1597
+ 'network': network,
1598
+ 'info': response,
1599
+ };
1600
+ }
1601
+ /**
1602
+ * @method
1603
+ * @name ellipx#fetchTradingFee
1604
+ * @description Fetches the current trading fees (maker and taker) applicable to the user.
1605
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.kki5jay2c8it
1606
+ * @param {string} [symbol] Not used by EllipX as fees are not symbol-specific.
1607
+ * @param {object} [params] Extra parameters specific to the EllipX API endpoint.
1608
+ * @returns {Promise<object>} A promise resolving to a unified trading fee structure:
1609
+ * {
1610
+ * 'info': object, // the raw response from the exchange
1611
+ * 'symbol': undefined, // symbol is not used for this exchange
1612
+ * 'maker': number, // maker fee rate in decimal form
1613
+ * 'taker': number, // taker fee rate in decimal form
1614
+ * 'percentage': true, // indicates fees are in percentage
1615
+ * 'tierBased': false, // indicates fees do not vary by volume tiers
1616
+ * }
1617
+ */
1618
+ async fetchTradingFee(symbol = undefined, params = {}) {
1619
+ await this.loadMarkets();
1620
+ const response = await this.privateGetMarketTradeFeeQuery(params);
1621
+ //
1622
+ // Example response:
1623
+ // {
1624
+ // "result": "success",
1625
+ // "data": {
1626
+ // "maker": 15.0, // in basis points
1627
+ // "taker": 25.0, // in basis points
1628
+ // "volume": 123456.78,
1629
+ // "promo": {
1630
+ // // promotional discounts if any
1631
+ // }
1632
+ // }
1633
+ // }
1634
+ //
1635
+ const data = this.safeValue(response, 'data', {});
1636
+ const maker = this.safeNumber(data, 'maker'); // in basis points
1637
+ const taker = this.safeNumber(data, 'taker'); // in basis points
1638
+ const makerFee = (maker !== undefined) ? maker / 10000 : undefined;
1639
+ const takerFee = (taker !== undefined) ? taker / 10000 : undefined;
1640
+ return {
1641
+ 'info': response,
1642
+ 'symbol': undefined,
1643
+ 'maker': makerFee,
1644
+ 'taker': takerFee,
1645
+ 'percentage': true,
1646
+ 'tierBased': true, // fees can vary based on volume tiers
1647
+ };
1648
+ }
1649
+ /**
1650
+ * @method
1651
+ * @description Make a withdrawal request
1652
+ * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.zegupoa8g4t9
1653
+ * @param {string} code Currency code
1654
+ * @param {number} amount Amount to withdraw
1655
+ * @param {string} address Destination wallet address
1656
+ * @param {string} [tag] Additional tag/memo for currencies that require it
1657
+ * @param {object} params Extra parameters specific to the EllipX API endpoint (Crypto_Chain__, Unit__)
1658
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
1659
+ */
1660
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
1661
+ this.checkAddress(address);
1662
+ await this.loadMarkets();
1663
+ const currency = this.currency(code);
1664
+ const networks = this.safeValue(currency, 'networks');
1665
+ if (networks === undefined) {
1666
+ throw new errors.NotSupported(this.id + ' withdraw() for ' + code + ' is not supported');
1667
+ }
1668
+ const chainsResponse = await this.privateGetUnitCurrency({ 'currency': currency['code'] }); // fetch Unit__ params for currency
1669
+ const chainsData = this.safeValue(chainsResponse, 'data', []);
1670
+ const unit = this.safeString(chainsData, 'Unit__');
1671
+ // check params again and omit params
1672
+ this.omit(params, 'Unit__');
1673
+ this.omit(params, 'Crypto_Chain__');
1674
+ const amountString = amount.toString();
1675
+ const request = {
1676
+ 'Unit__': unit,
1677
+ 'amount': amountString,
1678
+ 'address': address,
1679
+ 'Crypto_Chain__': networks['id'],
1680
+ };
1681
+ if (tag !== undefined) {
1682
+ request['memo'] = tag;
1683
+ }
1684
+ const response = await this.privatePostCryptoDisbursementWithdraw(this.extend(request, params));
1685
+ // {
1686
+ // Crypto_Disbursement__: "crdsb-4pw3kg-ipn5-amvb-da4n-6xncy4r4",
1687
+ // Crypto_Token__: "crtok-dnehz4-wbgv-bunf-iyd3-m7gtsz2q",
1688
+ // Crypto_Chain__: "chain-kjfvwn-l2xn-eclc-ul5d-mb6fu5hm",
1689
+ // User__: "usr-5oint6-ozpr-alfp-2wxi-zgbm4osy",
1690
+ // Value: {
1691
+ // v: "1000000000",
1692
+ // e: "8",
1693
+ // f: "10",
1694
+ // },
1695
+ // Value_USD: "4.08723",
1696
+ // Address: "D6z62LUwyNBi3QbPkzW8C4m7VDAgu9wb2Z",
1697
+ // Status: "pending",
1698
+ // Transaction: null,
1699
+ // Requested: {
1700
+ // unix: "1731570982",
1701
+ // us: "203569",
1702
+ // iso: "2024-11-14 07:56:22.203569",
1703
+ // tz: "UTC",
1704
+ // full: "1731570982203569",
1705
+ // unixms: "1731570982203",
1706
+ // },
1707
+ // Scheduled: null,
1708
+ // Processed: null,
1709
+ // Amount: {
1710
+ // value: "10.00000000",
1711
+ // value_int: "1000000000",
1712
+ // value_disp: "10.00000000",
1713
+ // value_xint: {
1714
+ // v: "1000000000",
1715
+ // e: "8",
1716
+ // f: "10",
1717
+ // },
1718
+ // display: "10.00000000DOGE",
1719
+ // display_short: "10.00000000DOGE",
1720
+ // currency: "DOGE",
1721
+ // unit: "DOGE",
1722
+ // has_vat: false,
1723
+ // tax_profile: null,
1724
+ // raw: {
1725
+ // value: "10.00000000",
1726
+ // value_int: "1000000000",
1727
+ // value_disp: "10.00000000",
1728
+ // value_xint: {
1729
+ // v: "1000000000",
1730
+ // e: "8",
1731
+ // f: "10",
1732
+ // },
1733
+ // display: "10.00000000DOGE",
1734
+ // display_short: "10.00000000DOGE",
1735
+ // currency: "DOGE",
1736
+ // unit: "DOGE",
1737
+ // has_vat: false,
1738
+ // tax_profile: null,
1739
+ // },
1740
+ // tax: {
1741
+ // value: "10.00000000",
1742
+ // value_int: "1000000000",
1743
+ // value_disp: "10.00000000",
1744
+ // value_xint: {
1745
+ // v: "1000000000",
1746
+ // e: "8",
1747
+ // f: "10",
1748
+ // },
1749
+ // display: "10.00000000DOGE",
1750
+ // display_short: "10.00000000DOGE",
1751
+ // currency: "DOGE",
1752
+ // unit: "DOGE",
1753
+ // has_vat: true,
1754
+ // tax_profile: null,
1755
+ // },
1756
+ // tax_only: {
1757
+ // value: "0.000",
1758
+ // value_int: "0",
1759
+ // value_disp: "0",
1760
+ // value_xint: {
1761
+ // v: "0",
1762
+ // e: "3",
1763
+ // f: "0",
1764
+ // },
1765
+ // display: "¥0",
1766
+ // display_short: "¥0",
1767
+ // currency: "JPY",
1768
+ // unit: "JPY",
1769
+ // has_vat: false,
1770
+ // tax_profile: null,
1771
+ // },
1772
+ // tax_rate: "0",
1773
+ // },
1774
+ // }
1775
+ const data = this.safeDict(response, 'data');
1776
+ const amountResponse = this.safeDict(data, 'Amount');
1777
+ const requested = this.safeDict(data, 'Requested');
1778
+ const processed = this.safeDict(data, 'Processed');
1779
+ const withdrawId = this.safeString(data, 'Crypto_Disbursement__');
1780
+ const timestamp = this.safeInteger(requested, 'unixms');
1781
+ return {
1782
+ 'info': response,
1783
+ 'id': withdrawId,
1784
+ 'txid': undefined,
1785
+ 'timestamp': timestamp,
1786
+ 'datetime': this.iso8601(timestamp),
1787
+ 'network': this.safeString(data, 'Crypto_Chain__'),
1788
+ 'address': this.safeString(data, 'Address'),
1789
+ 'addressTo': this.safeString(data, 'Address'),
1790
+ 'addressFrom': undefined,
1791
+ 'tag': tag,
1792
+ 'tagTo': tag,
1793
+ 'tagFrom': undefined,
1794
+ 'type': 'withdrawal',
1795
+ 'amount': this.safeNumber(amountResponse, 'value'),
1796
+ 'currency': code,
1797
+ 'status': this.parseTransactionStatus(this.safeString(data, 'Status')),
1798
+ 'updated': this.safeTimestamp(processed, 'unix'),
1799
+ 'internal': false,
1800
+ 'comment': undefined,
1801
+ 'fee': {
1802
+ 'currency': code,
1803
+ 'cost': undefined,
1804
+ 'rate': undefined,
1805
+ },
1806
+ };
1807
+ }
1808
+ parseTransactionStatus(status) {
1809
+ const statuses = {
1810
+ 'pending': 'pending',
1811
+ 'completed': 'ok',
1812
+ 'failed': 'failed',
1813
+ 'cancelled': 'canceled',
1814
+ };
1815
+ return this.safeString(statuses, status, status);
1816
+ }
1817
+ parseOrderStatus(status) {
1818
+ const statuses = {
1819
+ 'pending': 'open',
1820
+ 'running': 'open',
1821
+ 'post-pending': 'open',
1822
+ 'open': 'open',
1823
+ 'stop': 'open',
1824
+ 'invalid': 'rejected',
1825
+ 'done': 'closed',
1826
+ 'cancel': 'canceled',
1827
+ 'canceled': 'canceled', // alternative spelling
1828
+ };
1829
+ return this.safeString(statuses, status, status);
1830
+ }
1831
+ parseAmount(amount) {
1832
+ const v = this.safeString(amount, 'v', undefined);
1833
+ const e = this.safeInteger(amount, 'e', undefined);
1834
+ if (v === undefined || e === undefined) {
1835
+ return undefined;
1836
+ }
1837
+ const preciseAmount = new Precise["default"](v);
1838
+ preciseAmount.decimals = e;
1839
+ preciseAmount.reduce();
1840
+ return preciseAmount.toString();
1841
+ }
1842
+ toAmount(amount, precision) {
1843
+ const v = amount.toString();
1844
+ const e = precision;
1845
+ return {
1846
+ 'v': v,
1847
+ 'e': e,
1848
+ };
1849
+ }
1850
+ handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1851
+ // {
1852
+ // "code": 404,
1853
+ // "error": "Not Found: Crypto\\Token(US)",
1854
+ // "exception": "Exception\\NotFound",
1855
+ // "message": "[I18N:error_not_found]",
1856
+ // "request": "cc83738a-2438-4f53-ae44-f15306c07f32",
1857
+ // "result": "error",
1858
+ // "time": 0.0089569091796875,
1859
+ // "token": "error_not_found"
1860
+ // }
1861
+ const errorCode = this.safeString(response, 'code');
1862
+ const message = this.safeString(response, 'message');
1863
+ if (errorCode !== undefined) {
1864
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, message);
1865
+ throw new errors.ExchangeError(this.id + ' ' + message);
1866
+ }
1867
+ return undefined;
1868
+ }
1869
+ }
1870
+
1871
+ module.exports = ellipx;