ccxt 4.4.80__py2.py3-none-any.whl → 4.4.85__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.
Files changed (104) hide show
  1. ccxt/__init__.py +1 -5
  2. ccxt/abstract/blofin.py +8 -0
  3. ccxt/abstract/btcbox.py +1 -0
  4. ccxt/apex.py +21 -30
  5. ccxt/ascendex.py +1 -1
  6. ccxt/async_support/__init__.py +1 -5
  7. ccxt/async_support/apex.py +21 -30
  8. ccxt/async_support/ascendex.py +1 -1
  9. ccxt/async_support/base/exchange.py +26 -3
  10. ccxt/async_support/base/ws/cache.py +6 -1
  11. ccxt/async_support/bigone.py +17 -14
  12. ccxt/async_support/bingx.py +13 -32
  13. ccxt/async_support/bitfinex.py +61 -48
  14. ccxt/async_support/bitget.py +7 -4
  15. ccxt/async_support/bitrue.py +14 -32
  16. ccxt/async_support/bitso.py +33 -0
  17. ccxt/async_support/bitstamp.py +33 -0
  18. ccxt/async_support/blofin.py +145 -14
  19. ccxt/async_support/btcbox.py +25 -5
  20. ccxt/async_support/bybit.py +20 -39
  21. ccxt/async_support/cex.py +2 -4
  22. ccxt/async_support/coinbase.py +56 -42
  23. ccxt/async_support/coinbaseexchange.py +141 -32
  24. ccxt/async_support/coincatch.py +14 -67
  25. ccxt/async_support/coinex.py +28 -29
  26. ccxt/async_support/coinlist.py +17 -16
  27. ccxt/async_support/coinmetro.py +20 -11
  28. ccxt/async_support/coinone.py +8 -10
  29. ccxt/async_support/coinsph.py +124 -2
  30. ccxt/async_support/cryptocom.py +109 -2
  31. ccxt/async_support/cryptomus.py +42 -80
  32. ccxt/async_support/delta.py +75 -36
  33. ccxt/async_support/derive.py +46 -10
  34. ccxt/async_support/ellipx.py +175 -77
  35. ccxt/async_support/gate.py +1 -1
  36. ccxt/async_support/gemini.py +3 -4
  37. ccxt/async_support/hitbtc.py +56 -65
  38. ccxt/async_support/htx.py +2 -2
  39. ccxt/async_support/hyperliquid.py +15 -2
  40. ccxt/async_support/kraken.py +27 -23
  41. ccxt/async_support/kucoinfutures.py +5 -0
  42. ccxt/async_support/lbank.py +1 -1
  43. ccxt/async_support/okx.py +1 -2
  44. ccxt/async_support/oxfun.py +21 -1
  45. ccxt/async_support/paradex.py +120 -4
  46. ccxt/base/errors.py +6 -0
  47. ccxt/base/exchange.py +40 -3
  48. ccxt/base/types.py +3 -0
  49. ccxt/bigone.py +17 -14
  50. ccxt/bingx.py +13 -32
  51. ccxt/bitfinex.py +61 -48
  52. ccxt/bitget.py +7 -4
  53. ccxt/bitrue.py +14 -32
  54. ccxt/bitso.py +33 -0
  55. ccxt/bitstamp.py +33 -0
  56. ccxt/blofin.py +145 -14
  57. ccxt/btcbox.py +24 -5
  58. ccxt/bybit.py +20 -39
  59. ccxt/cex.py +2 -4
  60. ccxt/coinbase.py +56 -42
  61. ccxt/coinbaseexchange.py +141 -32
  62. ccxt/coincatch.py +14 -67
  63. ccxt/coinex.py +28 -29
  64. ccxt/coinlist.py +17 -16
  65. ccxt/coinmetro.py +20 -11
  66. ccxt/coinone.py +8 -10
  67. ccxt/coinsph.py +124 -2
  68. ccxt/cryptocom.py +109 -2
  69. ccxt/cryptomus.py +42 -80
  70. ccxt/delta.py +75 -36
  71. ccxt/derive.py +46 -10
  72. ccxt/ellipx.py +175 -77
  73. ccxt/gate.py +1 -1
  74. ccxt/gemini.py +3 -4
  75. ccxt/hitbtc.py +56 -65
  76. ccxt/htx.py +2 -2
  77. ccxt/hyperliquid.py +15 -2
  78. ccxt/kraken.py +27 -23
  79. ccxt/kucoinfutures.py +5 -0
  80. ccxt/lbank.py +1 -1
  81. ccxt/okx.py +1 -2
  82. ccxt/oxfun.py +21 -1
  83. ccxt/paradex.py +120 -4
  84. ccxt/pro/__init__.py +69 -3
  85. ccxt/pro/binance.py +31 -33
  86. ccxt/pro/bithumb.py +5 -3
  87. ccxt/pro/coinbase.py +1 -1
  88. ccxt/pro/hyperliquid.py +10 -2
  89. ccxt/pro/kraken.py +249 -79
  90. ccxt/pro/mexc.py +252 -7
  91. ccxt/pro/poloniex.py +6 -2
  92. {ccxt-4.4.80.dist-info → ccxt-4.4.85.dist-info}/METADATA +7 -11
  93. {ccxt-4.4.80.dist-info → ccxt-4.4.85.dist-info}/RECORD +96 -104
  94. ccxt/abstract/bl3p.py +0 -19
  95. ccxt/abstract/idex.py +0 -26
  96. ccxt/async_support/base/ws/fast_client.py +0 -97
  97. ccxt/async_support/bl3p.py +0 -543
  98. ccxt/async_support/idex.py +0 -1889
  99. ccxt/bl3p.py +0 -543
  100. ccxt/idex.py +0 -1889
  101. ccxt/pro/idex.py +0 -687
  102. {ccxt-4.4.80.dist-info → ccxt-4.4.85.dist-info}/LICENSE.txt +0 -0
  103. {ccxt-4.4.80.dist-info → ccxt-4.4.85.dist-info}/WHEEL +0 -0
  104. {ccxt-4.4.80.dist-info → ccxt-4.4.85.dist-info}/top_level.txt +0 -0
@@ -1,1889 +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.async_support.base.exchange import Exchange
7
- from ccxt.abstract.idex import ImplicitAPI
8
- import hashlib
9
- from ccxt.base.types import Any, Balances, Currencies, Currency, DepositAddress, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, 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 BadRequest
14
- from ccxt.base.errors import InsufficientFunds
15
- from ccxt.base.errors import InvalidAddress
16
- from ccxt.base.errors import InvalidOrder
17
- from ccxt.base.errors import NotSupported
18
- from ccxt.base.errors import DDoSProtection
19
- from ccxt.base.errors import ExchangeNotAvailable
20
- from ccxt.base.decimal_to_precision import ROUND
21
- from ccxt.base.decimal_to_precision import TRUNCATE
22
- from ccxt.base.decimal_to_precision import TICK_SIZE
23
- from ccxt.base.decimal_to_precision import PAD_WITH_ZERO
24
- from ccxt.base.precise import Precise
25
-
26
-
27
- class idex(Exchange, ImplicitAPI):
28
-
29
- def describe(self) -> Any:
30
- return self.deep_extend(super(idex, self).describe(), {
31
- 'id': 'idex',
32
- 'name': 'IDEX',
33
- 'countries': ['US'],
34
- 'rateLimit': 1000,
35
- 'version': 'v3',
36
- 'pro': True,
37
- 'dex': True,
38
- 'certified': False,
39
- 'requiresWeb3': True,
40
- 'has': {
41
- 'CORS': None,
42
- 'spot': True,
43
- 'margin': False,
44
- 'swap': False,
45
- 'future': False,
46
- 'option': False,
47
- 'addMargin': False,
48
- 'cancelAllOrders': True,
49
- 'cancelOrder': True,
50
- 'cancelOrders': False,
51
- 'closeAllPositions': False,
52
- 'closePosition': False,
53
- 'createDepositAddress': False,
54
- 'createOrder': True,
55
- 'createReduceOnlyOrder': False,
56
- 'createStopLimitOrder': True,
57
- 'createStopMarketOrder': True,
58
- 'createStopOrder': True,
59
- 'fetchBalance': True,
60
- 'fetchBorrowRateHistories': False,
61
- 'fetchBorrowRateHistory': False,
62
- 'fetchClosedOrders': True,
63
- 'fetchCrossBorrowRate': False,
64
- 'fetchCrossBorrowRates': False,
65
- 'fetchCurrencies': True,
66
- 'fetchDeposit': True,
67
- 'fetchDepositAddress': True,
68
- 'fetchDepositAddresses': False,
69
- 'fetchDepositAddressesByNetwork': False,
70
- 'fetchDeposits': True,
71
- 'fetchFundingHistory': False,
72
- 'fetchFundingRate': False,
73
- 'fetchFundingRateHistory': False,
74
- 'fetchFundingRates': False,
75
- 'fetchIndexOHLCV': False,
76
- 'fetchIsolatedBorrowRate': False,
77
- 'fetchIsolatedBorrowRates': False,
78
- 'fetchLeverage': False,
79
- 'fetchLeverageTiers': False,
80
- 'fetchMarginMode': False,
81
- 'fetchMarkets': True,
82
- 'fetchMarkOHLCV': False,
83
- 'fetchMyTrades': True,
84
- 'fetchOHLCV': True,
85
- 'fetchOpenInterestHistory': False,
86
- 'fetchOpenOrders': True,
87
- 'fetchOrder': True,
88
- 'fetchOrderBook': True,
89
- 'fetchOrders': False,
90
- 'fetchPosition': False,
91
- 'fetchPositionHistory': False,
92
- 'fetchPositionMode': False,
93
- 'fetchPositions': False,
94
- 'fetchPositionsForSymbol': False,
95
- 'fetchPositionsHistory': False,
96
- 'fetchPositionsRisk': False,
97
- 'fetchPremiumIndexOHLCV': False,
98
- 'fetchStatus': True,
99
- 'fetchTicker': True,
100
- 'fetchTickers': True,
101
- 'fetchTime': True,
102
- 'fetchTrades': True,
103
- 'fetchTradingFee': False,
104
- 'fetchTradingFees': True,
105
- 'fetchTransactions': False,
106
- 'fetchWithdrawal': True,
107
- 'fetchWithdrawals': True,
108
- 'reduceMargin': False,
109
- 'sandbox': True,
110
- 'setLeverage': False,
111
- 'setMarginMode': False,
112
- 'setPositionMode': False,
113
- 'transfer': False,
114
- 'withdraw': True,
115
- },
116
- 'timeframes': {
117
- '1m': '1m',
118
- '5m': '5m',
119
- '15m': '15m',
120
- '30m': '30m',
121
- '1h': '1h',
122
- '6h': '6h',
123
- '1d': '1d',
124
- },
125
- 'urls': {
126
- 'test': {
127
- 'MATIC': 'https://api-sandbox-matic.idex.io',
128
- },
129
- 'logo': 'https://user-images.githubusercontent.com/51840849/94481303-2f222100-01e0-11eb-97dd-bc14c5943a86.jpg',
130
- 'api': {
131
- 'MATIC': 'https://api-matic.idex.io',
132
- },
133
- 'www': 'https://idex.io',
134
- 'doc': [
135
- 'https://api-docs-v3.idex.io/',
136
- ],
137
- },
138
- 'api': {
139
- 'public': {
140
- 'get': {
141
- 'ping': 1,
142
- 'time': 1,
143
- 'exchange': 1,
144
- 'assets': 1,
145
- 'markets': 1,
146
- 'tickers': 1,
147
- 'candles': 1,
148
- 'trades': 1,
149
- 'orderbook': 1,
150
- },
151
- },
152
- 'private': {
153
- 'get': {
154
- 'user': 1,
155
- 'wallets': 1,
156
- 'balances': 1,
157
- 'orders': 0.1,
158
- 'fills': 0.1,
159
- 'deposits': 1,
160
- 'withdrawals': 1,
161
- 'wsToken': 1,
162
- },
163
- 'post': {
164
- 'wallets': 1,
165
- 'orders': 0.1,
166
- 'orders/test': 0.1,
167
- 'withdrawals': 1,
168
- },
169
- 'delete': {
170
- 'orders': 0.1,
171
- },
172
- },
173
- },
174
- 'options': {
175
- 'defaultTimeInForce': 'gtc',
176
- 'defaultSelfTradePrevention': 'cn',
177
- 'network': 'MATIC',
178
- },
179
- 'features': {
180
- 'spot': {
181
- 'sandbox': False,
182
- 'createOrder': {
183
- 'marginMode': False,
184
- 'triggerPrice': True,
185
- # todo: revise
186
- 'triggerPriceType': {
187
- 'last': True,
188
- 'mark': True,
189
- 'index': True,
190
- },
191
- 'triggerDirection': False,
192
- 'stopLossPrice': False, # todo
193
- 'takeProfitPrice': False, # todo
194
- 'attachedStopLossTakeProfit': None,
195
- 'timeInForce': {
196
- 'IOC': True,
197
- 'FOK': True,
198
- 'PO': True,
199
- 'GTD': False,
200
- },
201
- 'hedged': False,
202
- 'selfTradePrevention': True, # todo implementation
203
- 'trailing': False,
204
- 'leverage': False,
205
- 'marketBuyByCost': False,
206
- 'marketBuyRequiresPrice': False,
207
- 'iceberg': False,
208
- },
209
- 'createOrders': None,
210
- 'fetchMyTrades': {
211
- 'marginMode': False,
212
- 'limit': 1000,
213
- 'daysBack': 100000, # todo
214
- 'untilDays': 100000, # todo
215
- 'symbolRequired': False,
216
- },
217
- 'fetchOrder': {
218
- 'marginMode': False,
219
- 'trigger': False,
220
- 'trailing': False,
221
- 'symbolRequired': False,
222
- },
223
- 'fetchOpenOrders': {
224
- 'marginMode': False,
225
- 'limit': 1000,
226
- 'trigger': False,
227
- 'trailing': False,
228
- 'symbolRequired': False,
229
- },
230
- 'fetchOrders': None,
231
- 'fetchClosedOrders': {
232
- 'marginMode': False,
233
- 'limit': 1000,
234
- 'daysBack': 1000000, # todo
235
- 'daysBackCanceled': 1, # todo
236
- 'untilDays': 1000000, # todo
237
- 'trigger': False,
238
- 'trailing': False,
239
- 'symbolRequired': False,
240
- },
241
- 'fetchOHLCV': {
242
- 'limit': 1000,
243
- },
244
- },
245
- 'swap': {
246
- 'linear': None,
247
- 'inverse': None,
248
- },
249
- 'future': {
250
- 'linear': None,
251
- 'inverse': None,
252
- },
253
- },
254
- 'exceptions': {
255
- 'exact': {
256
- 'INVALID_ORDER_QUANTITY': InvalidOrder,
257
- 'INSUFFICIENT_FUNDS': InsufficientFunds,
258
- 'SERVICE_UNAVAILABLE': ExchangeNotAvailable,
259
- 'EXCEEDED_RATE_LIMIT': DDoSProtection,
260
- 'INVALID_PARAMETER': BadRequest,
261
- 'WALLET_NOT_ASSOCIATED': InvalidAddress,
262
- 'INVALID_WALLET_SIGNATURE': AuthenticationError,
263
- },
264
- },
265
- 'requiredCredentials': {
266
- 'walletAddress': True,
267
- 'privateKey': True,
268
- 'apiKey': True,
269
- 'secret': True,
270
- },
271
- 'precisionMode': TICK_SIZE,
272
- 'paddingMode': PAD_WITH_ZERO,
273
- 'commonCurrencies': {},
274
- })
275
-
276
- def price_to_precision(self, symbol, price):
277
- #
278
- # we override priceToPrecision to fix the following issue
279
- # https://github.com/ccxt/ccxt/issues/13367
280
- # {"code":"INVALID_PARAMETER","message":"invalid value provided for request parameter \"price\": all quantities and prices must be below 100 billion, above 0, need to be provided, and always require 4 decimals ending with 4 zeroes"}
281
- #
282
- market = self.market(symbol)
283
- price = self.decimal_to_precision(price, ROUND, market['precision']['price'], self.precisionMode)
284
- return self.decimal_to_precision(price, TRUNCATE, market['precision']['quote'], TICK_SIZE, PAD_WITH_ZERO)
285
-
286
- async def fetch_markets(self, params={}) -> List[Market]:
287
- """
288
- retrieves data on all markets for idex
289
-
290
- https://api-docs-v3.idex.io/#get-markets
291
-
292
- :param dict [params]: extra parameters specific to the exchange API endpoint
293
- :returns dict[]: an array of objects representing market data
294
- """
295
- response = await self.publicGetMarkets(params)
296
- #
297
- # [
298
- # {
299
- # "market": "ETH-USDC",
300
- # "type": "hybrid",
301
- # "status": "activeHybrid",
302
- # "baseAsset": "ETH",
303
- # "baseAssetPrecision": "8",
304
- # "quoteAsset": "USDC",
305
- # "quoteAssetPrecision": "8",
306
- # "makerFeeRate": "0.0000",
307
- # "takerFeeRate": "0.2500",
308
- # "takerIdexFeeRate": "0.0500",
309
- # "takerLiquidityProviderFeeRate": "0.2000",
310
- # "tickSize": "0.01000000"
311
- # },
312
- # ]
313
- #
314
- response2 = await self.publicGetExchange()
315
- #
316
- # {
317
- # "timeZone": "UTC",
318
- # "serverTime": "1654460599952",
319
- # "maticDepositContractAddress": "0x3253a7e75539edaeb1db608ce6ef9aa1ac9126b6",
320
- # "maticCustodyContractAddress": "0x3bcc4eca0a40358558ca8d1bcd2d1dbde63eb468",
321
- # "maticUsdPrice": "0.60",
322
- # "gasPrice": "180",
323
- # "volume24hUsd": "10015814.46",
324
- # "totalVolumeUsd": "1589273533.28",
325
- # "totalTrades": "1534904",
326
- # "totalValueLockedUsd": "12041929.44",
327
- # "idexStakingValueLockedUsd": "20133816.98",
328
- # "idexTokenAddress": "0x9Cb74C8032b007466865f060ad2c46145d45553D",
329
- # "idexUsdPrice": "0.07",
330
- # "idexMarketCapUsd": "48012346.00",
331
- # "makerFeeRate": "0.0000",
332
- # "takerFeeRate": "0.0025",
333
- # "takerIdexFeeRate": "0.0005",
334
- # "takerLiquidityProviderFeeRate": "0.0020",
335
- # "makerTradeMinimum": "10.00000000",
336
- # "takerTradeMinimum": "1.00000000",
337
- # "withdrawMinimum": "0.50000000",
338
- # "liquidityAdditionMinimum": "0.50000000",
339
- # "liquidityRemovalMinimum": "0.40000000",
340
- # "blockConfirmationDelay": "64"
341
- # }
342
- #
343
- maker = self.safe_number(response2, 'makerFeeRate')
344
- taker = self.safe_number(response2, 'takerFeeRate')
345
- makerMin = self.safe_string(response2, 'makerTradeMinimum')
346
- takerMin = self.safe_string(response2, 'takerTradeMinimum')
347
- minCostETH = self.parse_number(Precise.string_min(makerMin, takerMin))
348
- result = []
349
- for i in range(0, len(response)):
350
- entry = response[i]
351
- marketId = self.safe_string(entry, 'market')
352
- baseId = self.safe_string(entry, 'baseAsset')
353
- quoteId = self.safe_string(entry, 'quoteAsset')
354
- base = self.safe_currency_code(baseId)
355
- quote = self.safe_currency_code(quoteId)
356
- basePrecision = self.parse_number(self.parse_precision(self.safe_string(entry, 'baseAssetPrecision')))
357
- quotePrecision = self.parse_number(self.parse_precision(self.safe_string(entry, 'quoteAssetPrecision')))
358
- status = self.safe_string(entry, 'status')
359
- minCost = None
360
- if quote == 'ETH':
361
- minCost = minCostETH
362
- result.append({
363
- 'id': marketId,
364
- 'symbol': base + '/' + quote,
365
- 'base': base,
366
- 'quote': quote,
367
- 'settle': None,
368
- 'baseId': baseId,
369
- 'quoteId': quoteId,
370
- 'settleId': None,
371
- 'type': 'spot',
372
- 'spot': True,
373
- 'margin': False,
374
- 'swap': False,
375
- 'future': False,
376
- 'option': False,
377
- 'active': (status != 'inactive'),
378
- 'contract': False,
379
- 'linear': None,
380
- 'inverse': None,
381
- 'taker': taker,
382
- 'maker': maker,
383
- 'contractSize': None,
384
- 'expiry': None,
385
- 'expiryDatetime': None,
386
- 'strike': None,
387
- 'optionType': None,
388
- 'precision': {
389
- 'amount': basePrecision,
390
- 'price': self.safe_number(entry, 'tickSize'),
391
- 'base': basePrecision,
392
- 'quote': quotePrecision,
393
- },
394
- 'limits': {
395
- 'leverage': {
396
- 'min': None,
397
- 'max': None,
398
- },
399
- 'amount': {
400
- 'min': basePrecision,
401
- 'max': None,
402
- },
403
- 'price': {
404
- 'min': quotePrecision,
405
- 'max': None,
406
- },
407
- 'cost': {
408
- 'min': minCost,
409
- 'max': None,
410
- },
411
- },
412
- 'created': None,
413
- 'info': entry,
414
- })
415
- return result
416
-
417
- async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
418
- """
419
- fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
420
-
421
- https://api-docs-v3.idex.io/#get-tickers
422
-
423
- :param str symbol: unified symbol of the market to fetch the ticker for
424
- :param dict [params]: extra parameters specific to the exchange API endpoint
425
- :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
426
- """
427
- await self.load_markets()
428
- market = self.market(symbol)
429
- request: dict = {
430
- 'market': market['id'],
431
- }
432
- # [
433
- # {
434
- # "market": "DIL-ETH",
435
- # "time": 1598367493008,
436
- # "open": "0.09695361",
437
- # "high": "0.10245881",
438
- # "low": "0.09572507",
439
- # "close": "0.09917079",
440
- # "closeQuantity": "0.71320950",
441
- # "baseVolume": "309.17380612",
442
- # "quoteVolume": "30.57633981",
443
- # "percentChange": "2.28",
444
- # "numTrades": 205,
445
- # "ask": "0.09910476",
446
- # "bid": "0.09688340",
447
- # "sequence": 3902
448
- # }
449
- # ]
450
- response = await self.publicGetTickers(self.extend(request, params))
451
- ticker = self.safe_dict(response, 0)
452
- return self.parse_ticker(ticker, market)
453
-
454
- async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
455
- """
456
- fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
457
-
458
- https://api-docs-v3.idex.io/#get-tickers
459
-
460
- :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
461
- :param dict [params]: extra parameters specific to the exchange API endpoint
462
- :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
463
- """
464
- await self.load_markets()
465
- # [
466
- # {
467
- # "market": "DIL-ETH",
468
- # "time": 1598367493008,
469
- # "open": "0.09695361",
470
- # "high": "0.10245881",
471
- # "low": "0.09572507",
472
- # "close": "0.09917079",
473
- # "closeQuantity": "0.71320950",
474
- # "baseVolume": "309.17380612",
475
- # "quoteVolume": "30.57633981",
476
- # "percentChange": "2.28",
477
- # "numTrades": 205,
478
- # "ask": "0.09910476",
479
- # "bid": "0.09688340",
480
- # "sequence": 3902
481
- # }, ...
482
- # ]
483
- response = await self.publicGetTickers(params)
484
- return self.parse_tickers(response, symbols)
485
-
486
- def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
487
- # {
488
- # "market": "DIL-ETH",
489
- # "time": 1598367493008,
490
- # "open": "0.09695361",
491
- # "high": "0.10245881",
492
- # "low": "0.09572507",
493
- # "close": "0.09917079",
494
- # "closeQuantity": "0.71320950",
495
- # "baseVolume": "309.17380612",
496
- # "quoteVolume": "30.57633981",
497
- # "percentChange": "2.28",
498
- # "numTrades": 205,
499
- # "ask": "0.09910476",
500
- # "bid": "0.09688340",
501
- # "sequence": 3902
502
- # }
503
- marketId = self.safe_string(ticker, 'market')
504
- market = self.safe_market(marketId, market, '-')
505
- symbol = market['symbol']
506
- timestamp = self.safe_integer(ticker, 'time')
507
- close = self.safe_string(ticker, 'close')
508
- return self.safe_ticker({
509
- 'symbol': symbol,
510
- 'timestamp': timestamp,
511
- 'datetime': self.iso8601(timestamp),
512
- 'high': self.safe_string(ticker, 'high'),
513
- 'low': self.safe_string(ticker, 'low'),
514
- 'bid': self.safe_string(ticker, 'bid'),
515
- 'bidVolume': None,
516
- 'ask': self.safe_string(ticker, 'ask'),
517
- 'askVolume': None,
518
- 'vwap': None,
519
- 'open': self.safe_string(ticker, 'open'),
520
- 'close': close,
521
- 'last': close,
522
- 'previousClose': None,
523
- 'change': None,
524
- 'percentage': self.safe_string(ticker, 'percentChange'),
525
- 'average': None,
526
- 'baseVolume': self.safe_string(ticker, 'baseVolume'),
527
- 'quoteVolume': self.safe_string(ticker, 'quoteVolume'),
528
- 'info': ticker,
529
- }, market)
530
-
531
- async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
532
- """
533
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
534
-
535
- https://api-docs-v3.idex.io/#get-candles
536
-
537
- :param str symbol: unified symbol of the market to fetch OHLCV data for
538
- :param str timeframe: the length of time each candle represents
539
- :param int [since]: timestamp in ms of the earliest candle to fetch
540
- :param int [limit]: the maximum amount of candles to fetch
541
- :param dict [params]: extra parameters specific to the exchange API endpoint
542
- :returns int[][]: A list of candles ordered, open, high, low, close, volume
543
- """
544
- await self.load_markets()
545
- market = self.market(symbol)
546
- request: dict = {
547
- 'market': market['id'],
548
- 'interval': timeframe,
549
- }
550
- if since is not None:
551
- request['start'] = since
552
- if limit is not None:
553
- request['limit'] = min(limit, 1000)
554
- response = await self.publicGetCandles(self.extend(request, params))
555
- if isinstance(response, list):
556
- # [
557
- # {
558
- # "start": 1598345580000,
559
- # "open": "0.09771286",
560
- # "high": "0.09771286",
561
- # "low": "0.09771286",
562
- # "close": "0.09771286",
563
- # "volume": "1.45340410",
564
- # "sequence": 3853
565
- # }, ...
566
- # ]
567
- return self.parse_ohlcvs(response, market, timeframe, since, limit)
568
- else:
569
- # {"nextTime":1595536440000}
570
- return []
571
-
572
- def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
573
- # {
574
- # "start": 1598345580000,
575
- # "open": "0.09771286",
576
- # "high": "0.09771286",
577
- # "low": "0.09771286",
578
- # "close": "0.09771286",
579
- # "volume": "1.45340410",
580
- # "sequence": 3853
581
- # }
582
- timestamp = self.safe_integer(ohlcv, 'start')
583
- open = self.safe_number(ohlcv, 'open')
584
- high = self.safe_number(ohlcv, 'high')
585
- low = self.safe_number(ohlcv, 'low')
586
- close = self.safe_number(ohlcv, 'close')
587
- volume = self.safe_number(ohlcv, 'volume')
588
- return [timestamp, open, high, low, close, volume]
589
-
590
- async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
591
- """
592
- get the list of most recent trades for a particular symbol
593
-
594
- https://api-docs-v3.idex.io/#get-trades
595
-
596
- :param str symbol: unified symbol of the market to fetch trades for
597
- :param int [since]: timestamp in ms of the earliest trade to fetch
598
- :param int [limit]: the maximum amount of trades to fetch
599
- :param dict [params]: extra parameters specific to the exchange API endpoint
600
- :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
601
- """
602
- await self.load_markets()
603
- market = self.market(symbol)
604
- request: dict = {
605
- 'market': market['id'],
606
- }
607
- if since is not None:
608
- request['start'] = since
609
- if limit is not None:
610
- request['limit'] = min(limit, 1000)
611
- # [
612
- # {
613
- # "fillId": "b5467d00-b13e-3fa9-8216-dd66735550fc",
614
- # "price": "0.09771286",
615
- # "quantity": "1.45340410",
616
- # "quoteQuantity": "0.14201627",
617
- # "time": 1598345638994,
618
- # "makerSide": "buy",
619
- # "sequence": 3853
620
- # }, ...
621
- # ]
622
- response = await self.publicGetTrades(self.extend(request, params))
623
- return self.parse_trades(response, market, since, limit)
624
-
625
- def parse_trade(self, trade: dict, market: Market = None) -> Trade:
626
- #
627
- # public trades
628
- # {
629
- # "fillId":"a4883704-850b-3c4b-8588-020b5e4c62f1",
630
- # "price":"0.20377008",
631
- # "quantity":"47.58448728",
632
- # "quoteQuantity":"9.69629509",
633
- # "time":1642091300873,
634
- # "makerSide":"buy",
635
- # "type":"hybrid", # one of either: "orderBook", "hybrid", or "pool"
636
- # "sequence":31876
637
- # }
638
- #
639
- # private trades
640
- # {
641
- # "fillId":"83429066-9334-3582-b710-78858b2f0d6b",
642
- # "price":"0.20717368",
643
- # "quantity":"15.00000000",
644
- # "quoteQuantity":"3.10760523",
645
- # "orderBookQuantity":"0.00000003",
646
- # "orderBookQuoteQuantity":"0.00000001",
647
- # "poolQuantity":"14.99999997",
648
- # "poolQuoteQuantity":"3.10760522",
649
- # "time":1642083351215,
650
- # "makerSide":"sell",
651
- # "sequence":31795,
652
- # "market":"IDEX-USDC",
653
- # "orderId":"4fe993f0-747b-11ec-bd08-79d4a0b6e47c",
654
- # "side":"buy",
655
- # "fee":"0.03749989",
656
- # "feeAsset":"IDEX",
657
- # "gas":"0.40507261",
658
- # "liquidity":"taker",
659
- # "type":"hybrid",
660
- # "txId":"0x69f6d82a762d12e3201efd0b3e9cc1969351e3c6ea3cf07c47c66bf24a459815",
661
- # "txStatus":"mined"
662
- # }
663
- #
664
- id = self.safe_string(trade, 'fillId')
665
- priceString = self.safe_string(trade, 'price')
666
- amountString = self.safe_string(trade, 'quantity')
667
- costString = self.safe_string(trade, 'quoteQuantity')
668
- timestamp = self.safe_integer(trade, 'time')
669
- marketId = self.safe_string(trade, 'market')
670
- symbol = self.safe_symbol(marketId, market, '-')
671
- # self code handles the duality of public vs private trades
672
- makerSide = self.safe_string(trade, 'makerSide')
673
- oppositeSide = 'sell' if (makerSide == 'buy') else 'buy'
674
- side = self.safe_string(trade, 'side', oppositeSide)
675
- takerOrMaker = self.safe_string(trade, 'liquidity', 'taker')
676
- feeCostString = self.safe_string(trade, 'fee')
677
- fee = None
678
- if feeCostString is not None:
679
- feeCurrencyId = self.safe_string(trade, 'feeAsset')
680
- fee = {
681
- 'cost': feeCostString,
682
- 'currency': self.safe_currency_code(feeCurrencyId),
683
- }
684
- orderId = self.safe_string(trade, 'orderId')
685
- return self.safe_trade({
686
- 'info': trade,
687
- 'timestamp': timestamp,
688
- 'datetime': self.iso8601(timestamp),
689
- 'symbol': symbol,
690
- 'id': id,
691
- 'order': orderId,
692
- 'type': 'limit',
693
- 'side': side,
694
- 'takerOrMaker': takerOrMaker,
695
- 'price': priceString,
696
- 'amount': amountString,
697
- 'cost': costString,
698
- 'fee': fee,
699
- }, market)
700
-
701
- async def fetch_trading_fees(self, params={}) -> TradingFees:
702
- """
703
- fetch the trading fees for multiple markets
704
-
705
- https://api-docs-v3.idex.io/#get-api-account
706
-
707
- :param dict [params]: extra parameters specific to the exchange API endpoint
708
- :returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
709
- """
710
- self.check_required_credentials()
711
- await self.load_markets()
712
- nonce = self.uuidv1()
713
- request: dict = {
714
- 'nonce': nonce,
715
- }
716
- response = None
717
- response = await self.privateGetUser(self.extend(request, params))
718
- #
719
- # {
720
- # "depositEnabled": True,
721
- # "orderEnabled": True,
722
- # "cancelEnabled": True,
723
- # "withdrawEnabled": True,
724
- # "totalPortfolioValueUsd": "0.00",
725
- # "makerFeeRate": "0.0000",
726
- # "takerFeeRate": "0.0025",
727
- # "takerIdexFeeRate": "0.0005",
728
- # "takerLiquidityProviderFeeRate": "0.0020"
729
- # }
730
- #
731
- maker = self.safe_number(response, 'makerFeeRate')
732
- taker = self.safe_number(response, 'takerFeeRate')
733
- result: dict = {}
734
- for i in range(0, len(self.symbols)):
735
- symbol = self.symbols[i]
736
- result[symbol] = {
737
- 'info': response,
738
- 'symbol': symbol,
739
- 'maker': maker,
740
- 'taker': taker,
741
- 'percentage': True,
742
- 'tierBased': False,
743
- }
744
- return result
745
-
746
- async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
747
- """
748
- fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
749
-
750
- https://api-docs-v3.idex.io/#get-order-books
751
-
752
- :param str symbol: unified symbol of the market to fetch the order book for
753
- :param int [limit]: the maximum amount of order book entries to return
754
- :param dict [params]: extra parameters specific to the exchange API endpoint
755
- :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
756
- """
757
- await self.load_markets()
758
- market = self.market(symbol)
759
- request: dict = {
760
- 'market': market['id'],
761
- 'level': 2,
762
- }
763
- if limit is not None:
764
- request['limit'] = limit
765
- # {
766
- # "sequence": 36416753,
767
- # "bids": [
768
- # ['0.09672815', "8.22284267", 1],
769
- # ['0.09672814', "1.83685554", 1],
770
- # ['0.09672143', "4.10962617", 1],
771
- # ['0.09658884', "4.03863759", 1],
772
- # ['0.09653781', "3.35730684", 1],
773
- # ['0.09624660', "2.54163586", 1],
774
- # ['0.09617490', "1.93065030", 1]
775
- # ],
776
- # "asks": [
777
- # ['0.09910476', "3.22840154", 1],
778
- # ['0.09940587', "3.39796593", 1],
779
- # ['0.09948189', "4.25088898", 1],
780
- # ['0.09958362', "2.42195784", 1],
781
- # ['0.09974393', "4.25234367", 1],
782
- # ['0.09995250', "3.40192141", 1]
783
- # ]
784
- # }
785
- response = await self.publicGetOrderbook(self.extend(request, params))
786
- nonce = self.safe_integer(response, 'sequence')
787
- return {
788
- 'symbol': symbol,
789
- 'timestamp': None,
790
- 'datetime': None,
791
- 'nonce': nonce,
792
- 'bids': self.parse_side(response, 'bids'),
793
- 'asks': self.parse_side(response, 'asks'),
794
- }
795
-
796
- def parse_side(self, book, side):
797
- bookSide = self.safe_value(book, side, [])
798
- result = []
799
- for i in range(0, len(bookSide)):
800
- order = bookSide[i]
801
- price = self.safe_number(order, 0)
802
- amount = self.safe_number(order, 1)
803
- orderCount = self.safe_integer(order, 2)
804
- result.append([price, amount, orderCount])
805
- descending = side == 'bids'
806
- return self.sort_by(result, 0, descending)
807
-
808
- async def fetch_currencies(self, params={}) -> Currencies:
809
- """
810
- fetches all available currencies on an exchange
811
-
812
- https://api-docs-v3.idex.io/#get-assets
813
-
814
- :param dict [params]: extra parameters specific to the exchange API endpoint
815
- :returns dict: an associative dictionary of currencies
816
- """
817
- response = await self.publicGetAssets(params)
818
- #
819
- # [
820
- # {
821
- # "name": "Ethereum",
822
- # "symbol": "ETH",
823
- # "contractAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
824
- # "assetDecimals": "18",
825
- # "exchangeDecimals": "8",
826
- # "maticPrice": "3029.38503483"
827
- # },
828
- # ]
829
- #
830
- result: dict = {}
831
- for i in range(0, len(response)):
832
- entry = response[i]
833
- name = self.safe_string(entry, 'name')
834
- currencyId = self.safe_string(entry, 'symbol')
835
- code = self.safe_currency_code(currencyId)
836
- precision = self.parse_number(self.parse_precision(self.safe_string(entry, 'exchangeDecimals')))
837
- result[code] = {
838
- 'id': currencyId,
839
- 'code': code,
840
- 'info': entry,
841
- 'type': None,
842
- 'name': name,
843
- 'active': None,
844
- 'deposit': None,
845
- 'withdraw': None,
846
- 'fee': None,
847
- 'precision': precision,
848
- 'limits': {
849
- 'amount': {'min': precision, 'max': None},
850
- 'withdraw': {'min': precision, 'max': None},
851
- },
852
- }
853
- return result
854
-
855
- def parse_balance(self, response) -> Balances:
856
- result: dict = {
857
- 'info': response,
858
- 'timestamp': None,
859
- 'datetime': None,
860
- }
861
- for i in range(0, len(response)):
862
- entry = response[i]
863
- currencyId = self.safe_string(entry, 'asset')
864
- code = self.safe_currency_code(currencyId)
865
- account = self.account()
866
- account['total'] = self.safe_string(entry, 'quantity')
867
- account['free'] = self.safe_string(entry, 'availableForTrade')
868
- account['used'] = self.safe_string(entry, 'locked')
869
- result[code] = account
870
- return self.safe_balance(result)
871
-
872
- async def fetch_balance(self, params={}) -> Balances:
873
- """
874
- query for balance and get the amount of funds available for trading or funds locked in orders
875
-
876
- https://api-docs-v3.idex.io/#get-balances
877
-
878
- :param dict [params]: extra parameters specific to the exchange API endpoint
879
- :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
880
- """
881
- self.check_required_credentials()
882
- await self.load_markets()
883
- nonce1 = self.uuidv1()
884
- request: dict = {
885
- 'nonce': nonce1,
886
- 'wallet': self.walletAddress,
887
- }
888
- # [
889
- # {
890
- # "asset": "DIL",
891
- # "quantity": "0.00000000",
892
- # "availableForTrade": "0.00000000",
893
- # "locked": "0.00000000",
894
- # "usdValue": null
895
- # }, ...
896
- # ]
897
- extendedRequest = self.extend(request, params)
898
- if extendedRequest['wallet'] is None:
899
- raise BadRequest(self.id + ' fetchBalance() wallet is None, set self.walletAddress or "address" in params')
900
- response = None
901
- try:
902
- response = await self.privateGetBalances(extendedRequest)
903
- except Exception as e:
904
- if isinstance(e, InvalidAddress):
905
- walletAddress = extendedRequest['wallet']
906
- await self.associate_wallet(walletAddress)
907
- response = await self.privateGetBalances(extendedRequest)
908
- else:
909
- raise e
910
- return self.parse_balance(response)
911
-
912
- async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
913
- """
914
- fetch all trades made by the user
915
-
916
- https://api-docs-v3.idex.io/#get-fills
917
-
918
- :param str symbol: unified market symbol
919
- :param int [since]: the earliest time in ms to fetch trades for
920
- :param int [limit]: the maximum number of trades structures to retrieve
921
- :param dict [params]: extra parameters specific to the exchange API endpoint
922
- :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
923
- """
924
- self.check_required_credentials()
925
- await self.load_markets()
926
- market = None
927
- request: dict = {
928
- 'nonce': self.uuidv1(),
929
- 'wallet': self.walletAddress,
930
- }
931
- if symbol is not None:
932
- market = self.market(symbol)
933
- request['market'] = market['id']
934
- if since is not None:
935
- request['start'] = since
936
- if limit is not None:
937
- request['limit'] = limit
938
- # [
939
- # {
940
- # "fillId": "48582d10-b9bb-3c4b-94d3-e67537cf2472",
941
- # "price": "0.09905990",
942
- # "quantity": "0.40000000",
943
- # "quoteQuantity": "0.03962396",
944
- # "time": 1598873478762,
945
- # "makerSide": "sell",
946
- # "sequence": 5053,
947
- # "market": "DIL-ETH",
948
- # "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
949
- # "side": "buy",
950
- # "fee": "0.00080000",
951
- # "feeAsset": "DIL",
952
- # "gas": "0.00857497",
953
- # "liquidity": "taker",
954
- # "txId": "0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65",
955
- # "txStatus": "mined"
956
- # }
957
- # ]
958
- extendedRequest = self.extend(request, params)
959
- if extendedRequest['wallet'] is None:
960
- raise BadRequest(self.id + ' fetchMyTrades() walletAddress is None, set self.walletAddress or "address" in params')
961
- response = None
962
- try:
963
- response = await self.privateGetFills(extendedRequest)
964
- except Exception as e:
965
- if isinstance(e, InvalidAddress):
966
- walletAddress = extendedRequest['wallet']
967
- await self.associate_wallet(walletAddress)
968
- response = await self.privateGetFills(extendedRequest)
969
- else:
970
- raise e
971
- return self.parse_trades(response, market, since, limit)
972
-
973
- async def fetch_order(self, id: str, symbol: Str = None, params={}):
974
- """
975
- fetches information on an order made by the user
976
-
977
- https://api-docs-v3.idex.io/#get-orders
978
-
979
- :param str id: order id
980
- :param str symbol: unified symbol of the market the order was made in
981
- :param dict [params]: extra parameters specific to the exchange API endpoint
982
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
983
- """
984
- request: dict = {
985
- 'orderId': id,
986
- }
987
- return await self.fetch_orders_helper(symbol, None, None, self.extend(request, params))
988
-
989
- async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
990
- """
991
- fetch all unfilled currently open orders
992
-
993
- https://api-docs-v3.idex.io/#get-orders
994
-
995
- :param str symbol: unified market symbol
996
- :param int [since]: the earliest time in ms to fetch open orders for
997
- :param int [limit]: the maximum number of open orders structures to retrieve
998
- :param dict [params]: extra parameters specific to the exchange API endpoint
999
- :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1000
- """
1001
- request: dict = {
1002
- 'closed': False,
1003
- }
1004
- return await self.fetch_orders_helper(symbol, since, limit, self.extend(request, params))
1005
-
1006
- async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1007
- """
1008
- fetches information on multiple closed orders made by the user
1009
-
1010
- https://api-docs-v3.idex.io/#get-orders
1011
-
1012
- :param str symbol: unified market symbol of the market orders were made in
1013
- :param int [since]: the earliest time in ms to fetch orders for
1014
- :param int [limit]: the maximum number of order structures to retrieve
1015
- :param dict [params]: extra parameters specific to the exchange API endpoint
1016
- :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1017
- """
1018
- request: dict = {
1019
- 'closed': True,
1020
- }
1021
- return await self.fetch_orders_helper(symbol, since, limit, self.extend(request, params))
1022
-
1023
- async def fetch_orders_helper(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1024
- await self.load_markets()
1025
- request: dict = {
1026
- 'nonce': self.uuidv1(),
1027
- 'wallet': self.walletAddress,
1028
- }
1029
- market = None
1030
- if symbol is not None:
1031
- market = self.market(symbol)
1032
- request['market'] = market['id']
1033
- if since is not None:
1034
- request['start'] = since
1035
- if limit is not None:
1036
- request['limit'] = limit
1037
- response = await self.privateGetOrders(self.extend(request, params))
1038
- # fetchClosedOrders / fetchOpenOrders
1039
- # [
1040
- # {
1041
- # "market": "DIL-ETH",
1042
- # "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
1043
- # "wallet": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
1044
- # "time": 1598873478650,
1045
- # "status": "filled",
1046
- # "type": "limit",
1047
- # "side": "buy",
1048
- # "originalQuantity": "0.40000000",
1049
- # "executedQuantity": "0.40000000",
1050
- # "cumulativeQuoteQuantity": "0.03962396",
1051
- # "avgExecutionPrice": "0.09905990",
1052
- # "price": "1.00000000",
1053
- # "fills": [
1054
- # {
1055
- # "fillId": "48582d10-b9bb-3c4b-94d3-e67537cf2472",
1056
- # "price": "0.09905990",
1057
- # "quantity": "0.40000000",
1058
- # "quoteQuantity": "0.03962396",
1059
- # "time": 1598873478650,
1060
- # "makerSide": "sell",
1061
- # "sequence": 5053,
1062
- # "fee": "0.00080000",
1063
- # "feeAsset": "DIL",
1064
- # "gas": "0.00857497",
1065
- # "liquidity": "taker",
1066
- # "txId": "0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65",
1067
- # "txStatus": "mined"
1068
- # }
1069
- # ]
1070
- # }
1071
- # ]
1072
- # fetchOrder
1073
- # {market: "DIL-ETH",
1074
- # "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
1075
- # "wallet": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
1076
- # "time": 1598873478650,
1077
- # "status": "filled",
1078
- # "type": "limit",
1079
- # "side": "buy",
1080
- # "originalQuantity": "0.40000000",
1081
- # "executedQuantity": "0.40000000",
1082
- # "cumulativeQuoteQuantity": "0.03962396",
1083
- # "avgExecutionPrice": "0.09905990",
1084
- # "price": "1.00000000",
1085
- # "fills":
1086
- # [{fillId: "48582d10-b9bb-3c4b-94d3-e67537cf2472",
1087
- # "price": "0.09905990",
1088
- # "quantity": "0.40000000",
1089
- # "quoteQuantity": "0.03962396",
1090
- # "time": 1598873478650,
1091
- # "makerSide": "sell",
1092
- # "sequence": 5053,
1093
- # "fee": "0.00080000",
1094
- # "feeAsset": "DIL",
1095
- # "gas": "0.00857497",
1096
- # "liquidity": "taker",
1097
- # "txId": "0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65",
1098
- # "txStatus": "mined"}]}
1099
- if isinstance(response, list):
1100
- return self.parse_orders(response, market, since, limit)
1101
- else:
1102
- return self.parse_order(response, market)
1103
-
1104
- def parse_order_status(self, status: Str):
1105
- # https://docs.idex.io/#order-states-amp-lifecycle
1106
- statuses: dict = {
1107
- 'active': 'open',
1108
- 'partiallyFilled': 'open',
1109
- 'rejected': 'canceled',
1110
- 'filled': 'closed',
1111
- }
1112
- return self.safe_string(statuses, status, status)
1113
-
1114
- def parse_order(self, order: dict, market: Market = None) -> Order:
1115
- #
1116
- # {
1117
- # "market": "DIL-ETH",
1118
- # "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
1119
- # "wallet": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
1120
- # "time": 1598873478650,
1121
- # "status": "filled",
1122
- # "type": "limit",
1123
- # "side": "buy",
1124
- # "originalQuantity": "0.40000000",
1125
- # "executedQuantity": "0.40000000",
1126
- # "cumulativeQuoteQuantity": "0.03962396",
1127
- # "avgExecutionPrice": "0.09905990",
1128
- # "price": "1.00000000",
1129
- # "fills": [
1130
- # {
1131
- # "fillId": "48582d10-b9bb-3c4b-94d3-e67537cf2472",
1132
- # "price": "0.09905990",
1133
- # "quantity": "0.40000000",
1134
- # "quoteQuantity": "0.03962396",
1135
- # "time": 1598873478650,
1136
- # "makerSide": "sell",
1137
- # "sequence": 5053,
1138
- # "fee": "0.00080000",
1139
- # "feeAsset": "DIL",
1140
- # "gas": "0.00857497",
1141
- # "liquidity": "taker",
1142
- # "txId": "0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65",
1143
- # "txStatus": "mined"
1144
- # }
1145
- # ]
1146
- # }
1147
- #
1148
- timestamp = self.safe_integer(order, 'time')
1149
- fills = self.safe_value(order, 'fills', [])
1150
- id = self.safe_string(order, 'orderId')
1151
- clientOrderId = self.safe_string(order, 'clientOrderId')
1152
- marketId = self.safe_string(order, 'market')
1153
- side = self.safe_string(order, 'side')
1154
- symbol = self.safe_symbol(marketId, market, '-')
1155
- type = self.safe_string(order, 'type')
1156
- amount = self.safe_string(order, 'originalQuantity')
1157
- filled = self.safe_string(order, 'executedQuantity')
1158
- average = self.safe_string(order, 'avgExecutionPrice')
1159
- price = self.safe_string(order, 'price')
1160
- rawStatus = self.safe_string(order, 'status')
1161
- timeInForce = self.safe_string_upper(order, 'timeInForce')
1162
- status = self.parse_order_status(rawStatus)
1163
- return self.safe_order({
1164
- 'info': order,
1165
- 'id': id,
1166
- 'clientOrderId': clientOrderId,
1167
- 'timestamp': timestamp,
1168
- 'datetime': self.iso8601(timestamp),
1169
- 'lastTradeTimestamp': None,
1170
- 'symbol': symbol,
1171
- 'type': type,
1172
- 'timeInForce': timeInForce,
1173
- 'postOnly': None,
1174
- 'side': side,
1175
- 'price': price,
1176
- 'triggerPrice': None,
1177
- 'amount': amount,
1178
- 'cost': None,
1179
- 'average': average,
1180
- 'filled': filled,
1181
- 'remaining': None,
1182
- 'status': status,
1183
- 'fee': None,
1184
- 'trades': fills,
1185
- }, market)
1186
-
1187
- async def associate_wallet(self, walletAddress, params={}):
1188
- nonce = self.uuidv1()
1189
- noPrefix = self.remove0x_prefix(walletAddress)
1190
- byteArray = [
1191
- self.base16_to_binary(nonce),
1192
- self.base16_to_binary(noPrefix),
1193
- ]
1194
- binary = self.binary_concat_array(byteArray)
1195
- hash = self.hash(binary, 'keccak', 'hex')
1196
- signature = self.sign_message_string(hash, self.privateKey)
1197
- # {
1198
- # "address": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
1199
- # "totalPortfolioValueUsd": "0.00",
1200
- # "time": 1598468353626
1201
- # }
1202
- request: dict = {
1203
- 'parameters': {
1204
- 'nonce': nonce,
1205
- 'wallet': walletAddress,
1206
- },
1207
- 'signature': signature,
1208
- }
1209
- result = await self.privatePostWallets(request)
1210
- return result
1211
-
1212
- async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1213
- """
1214
- create a trade order, https://docs.idex.io/#create-order
1215
-
1216
- https://api-docs-v3.idex.io/#create-order
1217
-
1218
- :param str symbol: unified symbol of the market to create an order in
1219
- :param str type: 'market' or 'limit'
1220
- :param str side: 'buy' or 'sell'
1221
- :param float amount: how much of currency you want to trade in units of base currency
1222
- :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1223
- :param dict [params]: extra parameters specific to the exchange API endpoint
1224
- :param bool [params.test]: set to True to test an order, no order will be created but the request will be validated
1225
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1226
- """
1227
- self.check_required_credentials()
1228
- await self.load_markets()
1229
- testOrder = self.safe_bool(params, 'test', False)
1230
- params = self.omit(params, 'test')
1231
- market = self.market(symbol)
1232
- nonce = self.uuidv1()
1233
- typeEnum = None
1234
- stopLossTypeEnums: dict = {
1235
- 'stopLoss': 3,
1236
- 'stopLossLimit': 4,
1237
- 'takeProfit': 5,
1238
- 'takeProfitLimit': 6,
1239
- }
1240
- triggerPrice = self.safe_string(params, 'triggerPrice', 'stopPrice')
1241
- triggerPriceString = None
1242
- if (type == 'stopLossLimit') or (type == 'takeProfitLimit'):
1243
- if triggerPrice is None:
1244
- raise BadRequest(self.id + ' createOrder() triggerPrice is a required parameter for ' + type + 'orders')
1245
- triggerPriceString = self.price_to_precision(symbol, triggerPrice)
1246
- limitTypeEnums: dict = {
1247
- 'limit': 1,
1248
- 'limitMaker': 2,
1249
- }
1250
- priceString = None
1251
- typeLower = type.lower()
1252
- limitOrder = typeLower.find('limit') >= 0
1253
- if type in limitTypeEnums:
1254
- typeEnum = limitTypeEnums[type]
1255
- priceString = self.price_to_precision(symbol, price)
1256
- elif type in stopLossTypeEnums:
1257
- typeEnum = stopLossTypeEnums[type]
1258
- priceString = self.price_to_precision(symbol, price)
1259
- elif type == 'market':
1260
- typeEnum = 0
1261
- else:
1262
- raise BadRequest(self.id + ' ' + type + ' is not a valid order type')
1263
- amountEnum = 0 # base quantity
1264
- if 'quoteOrderQuantity' in params:
1265
- if type != 'market':
1266
- raise NotSupported(self.id + ' createOrder() quoteOrderQuantity is not supported for ' + type + ' orders, only supported for market orders')
1267
- amountEnum = 1
1268
- amount = self.safe_number(params, 'quoteOrderQuantity')
1269
- sideEnum = 0 if (side == 'buy') else 1
1270
- walletBytes = self.remove0x_prefix(self.walletAddress)
1271
- network = self.safe_string(self.options, 'network', 'ETH')
1272
- orderVersion = self.get_supported_mapping(network, {
1273
- 'ETH': 1,
1274
- 'BSC': 2,
1275
- 'MATIC': 4,
1276
- })
1277
- amountString = self.amount_to_precision(symbol, amount)
1278
- # https://docs.idex.io/#time-in-force
1279
- timeInForceEnums: dict = {
1280
- 'gtc': 0,
1281
- 'ioc': 2,
1282
- 'fok': 3,
1283
- }
1284
- defaultTimeInForce = self.safe_string(self.options, 'defaultTimeInForce', 'gtc')
1285
- timeInForce = self.safe_string(params, 'timeInForce', defaultTimeInForce)
1286
- timeInForceEnum = None
1287
- if timeInForce in timeInForceEnums:
1288
- timeInForceEnum = timeInForceEnums[timeInForce]
1289
- else:
1290
- allOptions = list(timeInForceEnums.keys())
1291
- asString = ', '.join(allOptions)
1292
- raise BadRequest(self.id + ' ' + timeInForce + ' is not a valid timeInForce, please choose one of ' + asString)
1293
- # https://docs.idex.io/#self-trade-prevention
1294
- selfTradePreventionEnums: dict = {
1295
- 'dc': 0,
1296
- 'co': 1,
1297
- 'cn': 2,
1298
- 'cb': 3,
1299
- }
1300
- defaultSelfTradePrevention = self.safe_string(self.options, 'defaultSelfTradePrevention', 'cn')
1301
- selfTradePrevention = self.safe_string(params, 'selfTradePrevention', defaultSelfTradePrevention)
1302
- selfTradePreventionEnum = None
1303
- if selfTradePrevention in selfTradePreventionEnums:
1304
- selfTradePreventionEnum = selfTradePreventionEnums[selfTradePrevention]
1305
- else:
1306
- allOptions = list(selfTradePreventionEnums.keys())
1307
- asString = ', '.join(allOptions)
1308
- raise BadRequest(self.id + ' ' + selfTradePrevention + ' is not a valid selfTradePrevention, please choose one of ' + asString)
1309
- byteArray = [
1310
- self.number_to_be(orderVersion, 1),
1311
- self.base16_to_binary(nonce),
1312
- self.base16_to_binary(walletBytes),
1313
- self.encode(market['id']),
1314
- self.number_to_be(typeEnum, 1),
1315
- self.number_to_be(sideEnum, 1),
1316
- self.encode(amountString),
1317
- self.number_to_be(amountEnum, 1),
1318
- ]
1319
- if limitOrder:
1320
- encodedPrice = self.encode(priceString)
1321
- byteArray.append(encodedPrice)
1322
- if type in stopLossTypeEnums:
1323
- encodedPrice = self.encode(triggerPriceString or priceString)
1324
- byteArray.append(encodedPrice)
1325
- clientOrderId = self.safe_string(params, 'clientOrderId')
1326
- if clientOrderId is not None:
1327
- byteArray.append(self.encode(clientOrderId))
1328
- after = [
1329
- self.number_to_be(timeInForceEnum, 1),
1330
- self.number_to_be(selfTradePreventionEnum, 1),
1331
- self.number_to_be(0, 8), # unused
1332
- ]
1333
- allBytes = self.array_concat(byteArray, after)
1334
- binary = self.binary_concat_array(allBytes)
1335
- hash = self.hash(binary, 'keccak', 'hex')
1336
- signature = self.sign_message_string(hash, self.privateKey)
1337
- request: dict = {
1338
- 'parameters': {
1339
- 'nonce': nonce,
1340
- 'market': market['id'],
1341
- 'side': side,
1342
- 'type': type,
1343
- 'wallet': self.walletAddress,
1344
- 'selfTradePrevention': selfTradePrevention,
1345
- },
1346
- 'signature': signature,
1347
- }
1348
- if type != 'market':
1349
- request['parameters']['timeInForce'] = timeInForce
1350
- if limitOrder:
1351
- request['parameters']['price'] = priceString
1352
- if type in stopLossTypeEnums:
1353
- request['parameters']['stopPrice'] = triggerPriceString or priceString
1354
- if amountEnum == 0:
1355
- request['parameters']['quantity'] = amountString
1356
- else:
1357
- request['parameters']['quoteOrderQuantity'] = amountString
1358
- if clientOrderId is not None:
1359
- request['parameters']['clientOrderId'] = clientOrderId
1360
- # {
1361
- # "market": "DIL-ETH",
1362
- # "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
1363
- # "wallet": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
1364
- # "time": 1598873478650,
1365
- # "status": "filled",
1366
- # "type": "limit",
1367
- # "side": "buy",
1368
- # "originalQuantity": "0.40000000",
1369
- # "executedQuantity": "0.40000000",
1370
- # "cumulativeQuoteQuantity": "0.03962396",
1371
- # "price": "1.00000000",
1372
- # "fills": [
1373
- # {
1374
- # "fillId": "48582d10-b9bb-3c4b-94d3-e67537cf2472",
1375
- # "price": "0.09905990",
1376
- # "quantity": "0.40000000",
1377
- # "quoteQuantity": "0.03962396",
1378
- # "time": 1598873478650,
1379
- # "makerSide": "sell",
1380
- # "sequence": 5053,
1381
- # "fee": "0.00080000",
1382
- # "feeAsset": "DIL",
1383
- # "gas": "0.00857497",
1384
- # "liquidity": "taker",
1385
- # "txStatus": "pending"
1386
- # }
1387
- # ],
1388
- # "avgExecutionPrice": "0.09905990"
1389
- # }
1390
- # we don't use self.extend here because it is a signed endpoint
1391
- response = None
1392
- if testOrder:
1393
- response = await self.privatePostOrdersTest(request)
1394
- else:
1395
- response = await self.privatePostOrders(request)
1396
- return self.parse_order(response, market)
1397
-
1398
- async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
1399
- """
1400
- make a withdrawal
1401
-
1402
- https://api-docs-v3.idex.io/#withdraw-funds
1403
-
1404
- :param str code: unified currency code
1405
- :param float amount: the amount to withdraw
1406
- :param str address: the address to withdraw to
1407
- :param str tag:
1408
- :param dict [params]: extra parameters specific to the exchange API endpoint
1409
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1410
- """
1411
- tag, params = self.handle_withdraw_tag_and_params(tag, params)
1412
- self.check_required_credentials()
1413
- await self.load_markets()
1414
- nonce = self.uuidv1()
1415
- amountString = self.currency_to_precision(code, amount)
1416
- currency = self.currency(code)
1417
- walletBytes = self.remove0x_prefix(self.walletAddress)
1418
- byteArray = [
1419
- self.base16_to_binary(nonce),
1420
- self.base16_to_binary(walletBytes),
1421
- self.encode(currency['id']),
1422
- self.encode(amountString),
1423
- self.number_to_be(1, 1), # bool set to True
1424
- ]
1425
- binary = self.binary_concat_array(byteArray)
1426
- hash = self.hash(binary, 'keccak', 'hex')
1427
- signature = self.sign_message_string(hash, self.privateKey)
1428
- request: dict = {
1429
- 'parameters': {
1430
- 'nonce': nonce,
1431
- 'wallet': address,
1432
- 'asset': currency['id'],
1433
- 'quantity': amountString,
1434
- },
1435
- 'signature': signature,
1436
- }
1437
- response = await self.privatePostWithdrawals(request)
1438
- #
1439
- # {
1440
- # "withdrawalId": "a61dcff0-ec4d-11ea-8b83-c78a6ecb3180",
1441
- # "asset": "ETH",
1442
- # "assetContractAddress": "0x0000000000000000000000000000000000000000",
1443
- # "quantity": "0.20000000",
1444
- # "time": 1598962883190,
1445
- # "fee": "0.00024000",
1446
- # "txStatus": "pending",
1447
- # "txId": null
1448
- # }
1449
- #
1450
- return self.parse_transaction(response, currency)
1451
-
1452
- async def cancel_all_orders(self, symbol: Str = None, params={}):
1453
- """
1454
- cancel all open orders
1455
-
1456
- https://api-docs-v3.idex.io/#cancel-order
1457
-
1458
- :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
1459
- :param dict [params]: extra parameters specific to the exchange API endpoint
1460
- :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1461
- """
1462
- self.check_required_credentials()
1463
- await self.load_markets()
1464
- market = None
1465
- if symbol is not None:
1466
- market = self.market(symbol)
1467
- nonce = self.uuidv1()
1468
- request: dict = {
1469
- 'parameters': {
1470
- 'nonce': nonce,
1471
- 'wallet': self.walletAddress,
1472
- },
1473
- }
1474
- walletBytes = self.remove0x_prefix(self.walletAddress)
1475
- byteArray = [
1476
- self.base16_to_binary(nonce),
1477
- self.base16_to_binary(walletBytes),
1478
- ]
1479
- if market is not None:
1480
- byteArray.append(self.encode(market['id']))
1481
- request['parameters']['market'] = market['id']
1482
- binary = self.binary_concat_array(byteArray)
1483
- hash = self.hash(binary, 'keccak', 'hex')
1484
- signature = self.sign_message_string(hash, self.privateKey)
1485
- request['signature'] = signature
1486
- # [{orderId: "688336f0-ec50-11ea-9842-b332f8a34d0e"}]
1487
- response = await self.privateDeleteOrders(self.extend(request, params))
1488
- return self.parse_orders(response, market)
1489
-
1490
- async def cancel_order(self, id: str, symbol: Str = None, params={}):
1491
- """
1492
- cancels an open order
1493
-
1494
- https://api-docs-v3.idex.io/#cancel-order
1495
-
1496
- :param str id: order id
1497
- :param str symbol: unified symbol of the market the order was made in
1498
- :param dict [params]: extra parameters specific to the exchange API endpoint
1499
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1500
- """
1501
- self.check_required_credentials()
1502
- await self.load_markets()
1503
- market = None
1504
- if symbol is not None:
1505
- market = self.market(symbol)
1506
- nonce = self.uuidv1()
1507
- walletBytes = self.remove0x_prefix(self.walletAddress)
1508
- byteArray = [
1509
- self.base16_to_binary(nonce),
1510
- self.base16_to_binary(walletBytes),
1511
- self.encode(id),
1512
- ]
1513
- binary = self.binary_concat_array(byteArray)
1514
- hash = self.hash(binary, 'keccak', 'hex')
1515
- signature = self.sign_message_string(hash, self.privateKey)
1516
- request: dict = {
1517
- 'parameters': {
1518
- 'nonce': nonce,
1519
- 'wallet': self.walletAddress,
1520
- 'orderId': id,
1521
- },
1522
- 'signature': signature,
1523
- }
1524
- # [{orderId: "688336f0-ec50-11ea-9842-b332f8a34d0e"}]
1525
- response = await self.privateDeleteOrders(self.extend(request, params))
1526
- canceledOrder = self.safe_dict(response, 0)
1527
- return self.parse_order(canceledOrder, market)
1528
-
1529
- def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
1530
- errorCode = self.safe_string(response, 'code')
1531
- message = self.safe_string(response, 'message')
1532
- if errorCode is not None:
1533
- self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, message)
1534
- raise ExchangeError(self.id + ' ' + message)
1535
- return None
1536
-
1537
- async def fetch_deposit(self, id: str, code: Str = None, params={}):
1538
- """
1539
- fetch information on a deposit
1540
-
1541
- https://api-docs-v3.idex.io/#get-deposits
1542
-
1543
- :param str id: deposit id
1544
- :param str code: not used by idex fetchDeposit()
1545
- :param dict [params]: extra parameters specific to the exchange API endpoint
1546
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1547
- """
1548
- await self.load_markets()
1549
- nonce = self.uuidv1()
1550
- request: dict = {
1551
- 'nonce': nonce,
1552
- 'wallet': self.walletAddress,
1553
- 'depositId': id,
1554
- }
1555
- response = await self.privateGetDeposits(self.extend(request, params))
1556
- return self.parse_transaction(response)
1557
-
1558
- async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1559
- """
1560
- fetch all deposits made to an account
1561
-
1562
- https://api-docs-v3.idex.io/#get-deposits
1563
-
1564
- :param str code: unified currency code
1565
- :param int [since]: the earliest time in ms to fetch deposits for
1566
- :param int [limit]: the maximum number of deposits structures to retrieve
1567
- :param dict [params]: extra parameters specific to the exchange API endpoint
1568
- :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1569
- """
1570
- params = self.extend({
1571
- 'method': 'privateGetDeposits',
1572
- }, params)
1573
- return await self.fetch_transactions_helper(code, since, limit, params)
1574
-
1575
- async def fetch_status(self, params={}):
1576
- """
1577
- the latest known information on the availability of the exchange API
1578
-
1579
- https://api-docs-v3.idex.io/#get-ping
1580
-
1581
- :param dict [params]: extra parameters specific to the exchange API endpoint
1582
- :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
1583
- """
1584
- response = await self.publicGetPing(params)
1585
- return {
1586
- 'status': 'ok', # if there's no Errors, status = 'ok'
1587
- 'updated': None,
1588
- 'eta': None,
1589
- 'url': None,
1590
- 'info': response,
1591
- }
1592
-
1593
- async def fetch_time(self, params={}) -> Int:
1594
- """
1595
- fetches the current integer timestamp in milliseconds from the exchange server
1596
-
1597
- https://api-docs-v3.idex.io/#get-time
1598
-
1599
- :param dict [params]: extra parameters specific to the exchange API endpoint
1600
- :returns int: the current integer timestamp in milliseconds from the exchange server
1601
- """
1602
- response = await self.publicGetTime(params)
1603
- #
1604
- # {serverTime: "1655258263236"}
1605
- #
1606
- return self.safe_integer(response, 'serverTime')
1607
-
1608
- async def fetch_withdrawal(self, id: str, code: Str = None, params={}):
1609
- """
1610
- fetch data on a currency withdrawal via the withdrawal id
1611
-
1612
- https://api-docs-v3.idex.io/#get-withdrawals
1613
-
1614
- :param str id: withdrawal id
1615
- :param str code: not used by idex.fetchWithdrawal
1616
- :param dict [params]: extra parameters specific to the exchange API endpoint
1617
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1618
- """
1619
- await self.load_markets()
1620
- nonce = self.uuidv1()
1621
- request: dict = {
1622
- 'nonce': nonce,
1623
- 'wallet': self.walletAddress,
1624
- 'withdrawalId': id,
1625
- }
1626
- response = await self.privateGetWithdrawals(self.extend(request, params))
1627
- return self.parse_transaction(response)
1628
-
1629
- async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1630
- """
1631
- fetch all withdrawals made from an account
1632
-
1633
- https://api-docs-v3.idex.io/#get-withdrawals
1634
-
1635
- :param str code: unified currency code
1636
- :param int [since]: the earliest time in ms to fetch withdrawals for
1637
- :param int [limit]: the maximum number of withdrawals structures to retrieve
1638
- :param dict [params]: extra parameters specific to the exchange API endpoint
1639
- :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1640
- """
1641
- params = self.extend({
1642
- 'method': 'privateGetWithdrawals',
1643
- }, params)
1644
- return await self.fetch_transactions_helper(code, since, limit, params)
1645
-
1646
- async def fetch_transactions_helper(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
1647
- await self.load_markets()
1648
- nonce = self.uuidv1()
1649
- request: dict = {
1650
- 'nonce': nonce,
1651
- 'wallet': self.walletAddress,
1652
- }
1653
- currency = None
1654
- if code is not None:
1655
- currency = self.currency(code)
1656
- request['asset'] = currency['id']
1657
- if since is not None:
1658
- request['start'] = since
1659
- if limit is not None:
1660
- request['limit'] = limit
1661
- # [
1662
- # {
1663
- # "depositId": "e9970cc0-eb6b-11ea-9e89-09a5ebc1f98e",
1664
- # "asset": "ETH",
1665
- # "quantity": "1.00000000",
1666
- # "txId": "0xcd4aac3171d7131cc9e795568c67938675185ac17641553ef54c8a7c294c8142",
1667
- # "txTime": 1598865853000,
1668
- # "confirmationTime": 1598865930231
1669
- # }
1670
- # ]
1671
- method = params['method']
1672
- params = self.omit(params, 'method')
1673
- response = None
1674
- if method == 'privateGetDeposits':
1675
- response = await self.privateGetDeposits(self.extend(request, params))
1676
- elif method == 'privateGetWithdrawals':
1677
- response = await self.privateGetWithdrawals(self.extend(request, params))
1678
- else:
1679
- raise NotSupported(self.id + ' fetchTransactionsHelper() not support self method')
1680
- return self.parse_transactions(response, currency, since, limit)
1681
-
1682
- def parse_transaction_status(self, status: Str):
1683
- statuses: dict = {
1684
- 'mined': 'ok',
1685
- }
1686
- return self.safe_string(statuses, status, status)
1687
-
1688
- def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
1689
- #
1690
- # fetchDeposits
1691
- #
1692
- # {
1693
- # "depositId": "e9970cc0-eb6b-11ea-9e89-09a5ebc1f98f",
1694
- # "asset": "ETH",
1695
- # "quantity": "1.00000000",
1696
- # "txId": "0xcd4aac3171d7131cc9e795568c67938675185ac17641553ef54c8a7c294c8142",
1697
- # "txTime": 1598865853000,
1698
- # "confirmationTime": 1598865930231
1699
- # }
1700
- #
1701
- # fetchWithdrwalas
1702
- #
1703
- # {
1704
- # "withdrawalId": "a62d8760-ec4d-11ea-9fa6-47904c19499b",
1705
- # "asset": "ETH",
1706
- # "assetContractAddress": "0x0000000000000000000000000000000000000000",
1707
- # "quantity": "0.20000000",
1708
- # "time": 1598962883288,
1709
- # "fee": "0.00024000",
1710
- # "txId": "0x305e9cdbaa85ad029f50578d13d31d777c085de573ed5334d95c19116d8c03ce",
1711
- # "txStatus": "mined"
1712
- # }
1713
- #
1714
- # withdraw
1715
- #
1716
- # {
1717
- # "withdrawalId": "a61dcff0-ec4d-11ea-8b83-c78a6ecb3180",
1718
- # "asset": "ETH",
1719
- # "assetContractAddress": "0x0000000000000000000000000000000000000000",
1720
- # "quantity": "0.20000000",
1721
- # "time": 1598962883190,
1722
- # "fee": "0.00024000",
1723
- # "txStatus": "pending",
1724
- # "txId": null
1725
- # }
1726
- #
1727
- type = None
1728
- if 'depositId' in transaction:
1729
- type = 'deposit'
1730
- elif ('withdrawId' in transaction) or ('withdrawalId' in transaction):
1731
- type = 'withdrawal'
1732
- id = self.safe_string_2(transaction, 'depositId', 'withdrawId')
1733
- id = self.safe_string(transaction, 'withdrawalId', id)
1734
- code = self.safe_currency_code(self.safe_string(transaction, 'asset'), currency)
1735
- amount = self.safe_number(transaction, 'quantity')
1736
- txid = self.safe_string(transaction, 'txId')
1737
- timestamp = self.safe_integer_2(transaction, 'txTime', 'time')
1738
- fee = None
1739
- if 'fee' in transaction:
1740
- fee = {
1741
- 'cost': self.safe_number(transaction, 'fee'),
1742
- 'currency': 'ETH',
1743
- }
1744
- rawStatus = self.safe_string(transaction, 'txStatus')
1745
- status = self.parse_transaction_status(rawStatus)
1746
- updated = self.safe_integer(transaction, 'confirmationTime')
1747
- return {
1748
- 'info': transaction,
1749
- 'id': id,
1750
- 'txid': txid,
1751
- 'timestamp': timestamp,
1752
- 'datetime': self.iso8601(timestamp),
1753
- 'network': None,
1754
- 'address': None,
1755
- 'addressTo': None,
1756
- 'addressFrom': None,
1757
- 'tag': None,
1758
- 'tagTo': None,
1759
- 'tagFrom': None,
1760
- 'type': type,
1761
- 'amount': amount,
1762
- 'currency': code,
1763
- 'status': status,
1764
- 'updated': updated,
1765
- 'comment': None,
1766
- 'internal': None,
1767
- 'fee': fee,
1768
- }
1769
-
1770
- def calculate_rate_limiter_cost(self, api, method, path, params, config={}):
1771
- hasApiKey = (self.apiKey is not None)
1772
- hasSecret = (self.secret is not None)
1773
- hasWalletAddress = (self.walletAddress is not None)
1774
- hasPrivateKey = (self.privateKey is not None)
1775
- defaultCost = self.safe_value(config, 'cost', 1)
1776
- authenticated = hasApiKey and hasSecret and hasWalletAddress and hasPrivateKey
1777
- return(defaultCost / 2) if authenticated else defaultCost
1778
-
1779
- async def fetch_deposit_address(self, code: Str, params={}) -> DepositAddress:
1780
- """
1781
- fetch the Polygon address of the wallet
1782
-
1783
- https://api-docs-v3.idex.io/#get-wallets
1784
-
1785
- :param str code: not used by idex
1786
- :param dict [params]: extra parameters specific to the exchange API endpoint
1787
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1788
- """
1789
- request: dict = {}
1790
- request['nonce'] = self.uuidv1()
1791
- response = await self.privateGetWallets(self.extend(request, params))
1792
- #
1793
- # [
1794
- # {
1795
- # address: "0x37A1827CA64C94A26028bDCb43FBDCB0bf6DAf5B",
1796
- # totalPortfolioValueUsd: "0.00",
1797
- # time: "1678342148086"
1798
- # },
1799
- # {
1800
- # address: "0x0Ef3456E616552238B0c562d409507Ed6051A7b3",
1801
- # totalPortfolioValueUsd: "15.90",
1802
- # time: "1691697811659"
1803
- # }
1804
- # ]
1805
- #
1806
- return self.parse_deposit_address(response)
1807
-
1808
- def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
1809
- #
1810
- # [
1811
- # {
1812
- # address: "0x37A1827CA64C94A26028bDCb43FBDCB0bf6DAf5B",
1813
- # totalPortfolioValueUsd: "0.00",
1814
- # time: "1678342148086"
1815
- # },
1816
- # {
1817
- # address: "0x0Ef3456E616552238B0c562d409507Ed6051A7b3",
1818
- # totalPortfolioValueUsd: "15.90",
1819
- # time: "1691697811659"
1820
- # }
1821
- # ]
1822
- #
1823
- length = len(depositAddress)
1824
- entry = self.safe_dict(depositAddress, length - 1)
1825
- address = self.safe_string(entry, 'address')
1826
- self.check_address(address)
1827
- return {
1828
- 'info': depositAddress,
1829
- 'currency': None,
1830
- 'network': 'MATIC',
1831
- 'address': address,
1832
- 'tag': None,
1833
- }
1834
-
1835
- def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
1836
- network = self.safe_string(self.options, 'network', 'ETH')
1837
- version = self.safe_string(self.options, 'version', 'v1')
1838
- url = self.urls['api'][network] + '/' + version + '/' + path
1839
- keys = list(params.keys())
1840
- length = len(keys)
1841
- query = None
1842
- if length > 0:
1843
- if method == 'GET':
1844
- query = self.urlencode(params)
1845
- url = url + '?' + query
1846
- else:
1847
- body = self.json(params)
1848
- headers = {
1849
- 'Content-Type': 'application/json',
1850
- }
1851
- if self.apiKey is not None:
1852
- headers['IDEX-API-Key'] = self.apiKey
1853
- if api == 'private':
1854
- payload = None
1855
- if method == 'GET':
1856
- payload = query
1857
- else:
1858
- payload = body
1859
- headers['IDEX-HMAC-Signature'] = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256, 'hex')
1860
- return {'url': url, 'method': method, 'body': body, 'headers': headers}
1861
-
1862
- def remove0x_prefix(self, hexData):
1863
- if hexData[0:2] == '0x':
1864
- return hexData[2:]
1865
- else:
1866
- return hexData
1867
-
1868
- def hash_message(self, message):
1869
- # takes a hex encoded message
1870
- binaryMessage = self.base16_to_binary(self.remove0x_prefix(message))
1871
- prefix = self.encode('\x19Ethereum Signed Message:\n' + binaryMessage.byteLength)
1872
- return '0x' + self.hash(self.binary_concat(prefix, binaryMessage), 'keccak', 'hex')
1873
-
1874
- def sign_hash(self, hash, privateKey):
1875
- signature = self.ecdsa(hash[-64:], privateKey[-64:], 'secp256k1', None)
1876
- return {
1877
- 'r': '0x' + signature['r'],
1878
- 's': '0x' + signature['s'],
1879
- 'v': 27 + signature['v'],
1880
- }
1881
-
1882
- def sign_message(self, message, privateKey):
1883
- return self.sign_hash(self.hash_message(message), privateKey[-64:])
1884
-
1885
- def sign_message_string(self, message, privateKey):
1886
- # still takes the input hex string
1887
- # same but returns a string instead of an object
1888
- signature = self.sign_message(message, privateKey)
1889
- return signature['r'] + self.remove0x_prefix(signature['s']) + self.binary_to_base16(self.number_to_be(signature['v'], 1))