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