ccxt 4.5.1__py2.py3-none-any.whl → 4.5.2__py2.py3-none-any.whl

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