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
ccxt/pro/idex.py DELETED
@@ -1,687 +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
- import ccxt.async_support
7
- from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
- from ccxt.base.types import Any, Int, Order, OrderBook, Str, Ticker, Trade
9
- from ccxt.async_support.base.ws.client import Client
10
- from typing import List
11
- from ccxt.base.errors import InvalidNonce
12
- from ccxt.base.precise import Precise
13
-
14
-
15
- class idex(ccxt.async_support.idex):
16
-
17
- def describe(self) -> Any:
18
- return self.deep_extend(super(idex, self).describe(), {
19
- 'has': {
20
- 'ws': True,
21
- 'watchOrderBook': True,
22
- 'watchTrades': True,
23
- 'watchOHLCV': True,
24
- 'watchTicker': True,
25
- 'watchTickers': False, # for now
26
- 'watchOrders': True,
27
- 'watchTransactions': True,
28
- },
29
- 'urls': {
30
- 'test': {
31
- 'ws': 'wss://websocket-matic.idex.io/v1',
32
- },
33
- 'api': {},
34
- },
35
- 'options': {
36
- 'tradesLimit': 1000,
37
- 'ordersLimit': 1000,
38
- 'OHLCVLimit': 1000,
39
- 'watchOrderBookLimit': 1000, # default limit
40
- 'orderBookSubscriptions': {},
41
- 'token': None,
42
- 'watchOrderBook': {
43
- 'maxRetries': 3,
44
- },
45
- 'fetchOrderBookSnapshotMaxAttempts': 10,
46
- 'fetchOrderBookSnapshotMaxDelay': 10000, # raise if there are no orders in 10 seconds
47
- },
48
- })
49
-
50
- async def subscribe(self, subscribeObject, messageHash, subscription=True):
51
- url = self.urls['test']['ws']
52
- request: dict = {
53
- 'method': 'subscribe',
54
- 'subscriptions': [
55
- subscribeObject,
56
- ],
57
- }
58
- return await self.watch(url, messageHash, request, messageHash, subscription)
59
-
60
- async def subscribe_private(self, subscribeObject, messageHash):
61
- token = await self.authenticate()
62
- url = self.urls['test']['ws']
63
- request: dict = {
64
- 'method': 'subscribe',
65
- 'token': token,
66
- 'subscriptions': [
67
- subscribeObject,
68
- ],
69
- }
70
- return await self.watch(url, messageHash, request, messageHash)
71
-
72
- async def watch_ticker(self, symbol: str, params={}) -> Ticker:
73
- """
74
- watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
75
-
76
- https://api-docs-v4.idex.io/#tickers
77
-
78
- :param str symbol: unified symbol of the market to fetch the ticker for
79
- :param dict [params]: extra parameters specific to the exchange API endpoint
80
- :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
81
- """
82
- await self.load_markets()
83
- market = self.market(symbol)
84
- name = 'tickers'
85
- subscribeObject: dict = {
86
- 'name': name,
87
- 'markets': [market['id']],
88
- }
89
- messageHash = name + ':' + market['id']
90
- return await self.subscribe(self.extend(subscribeObject, params), messageHash)
91
-
92
- def handle_ticker(self, client: Client, message):
93
- # {type: "tickers",
94
- # "data":
95
- # {m: "DIL-ETH",
96
- # "t": 1599213946045,
97
- # "o": "0.09699020",
98
- # "h": "0.10301548",
99
- # "l": "0.09577222",
100
- # "c": "0.09907311",
101
- # "Q": "1.32723120",
102
- # "v": "297.80667468",
103
- # "q": "29.52142669",
104
- # "P": "2.14",
105
- # "n": 197,
106
- # "a": "0.09912245",
107
- # "b": "0.09686980",
108
- # "u": 5870}}
109
- type = self.safe_string(message, 'type')
110
- data = self.safe_value(message, 'data')
111
- marketId = self.safe_string(data, 'm')
112
- symbol = self.safe_symbol(marketId)
113
- messageHash = type + ':' + marketId
114
- timestamp = self.safe_integer(data, 't')
115
- close = self.safe_string(data, 'c')
116
- percentage = self.safe_string(data, 'P')
117
- change = None
118
- if (percentage is not None) and (close is not None):
119
- change = Precise.string_mul(close, percentage)
120
- ticker = self.safe_ticker({
121
- 'symbol': symbol,
122
- 'timestamp': timestamp,
123
- 'datetime': self.iso8601(timestamp),
124
- 'high': self.safe_string(data, 'h'),
125
- 'low': self.safe_string(data, 'l'),
126
- 'bid': self.safe_string(data, 'b'),
127
- 'bidVolume': None,
128
- 'ask': self.safe_string(data, 'a'),
129
- 'askVolume': None,
130
- 'vwap': None,
131
- 'open': self.safe_string(data, 'o'),
132
- 'close': close,
133
- 'last': close,
134
- 'previousClose': None,
135
- 'change': change,
136
- 'percentage': percentage,
137
- 'average': None,
138
- 'baseVolume': self.safe_string(data, 'v'),
139
- 'quoteVolume': self.safe_string(data, 'q'),
140
- 'info': message,
141
- })
142
- client.resolve(ticker, messageHash)
143
-
144
- async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
145
- """
146
- get the list of most recent trades for a particular symbol
147
-
148
- https://api-docs-v4.idex.io/#trades
149
-
150
- :param str symbol: unified symbol of the market to fetch trades for
151
- :param int [since]: timestamp in ms of the earliest trade to fetch
152
- :param int [limit]: the maximum amount of trades to fetch
153
- :param dict [params]: extra parameters specific to the exchange API endpoint
154
- :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
155
- """
156
- await self.load_markets()
157
- market = self.market(symbol)
158
- symbol = market['symbol']
159
- name = 'trades'
160
- subscribeObject: dict = {
161
- 'name': name,
162
- 'markets': [market['id']],
163
- }
164
- messageHash = name + ':' + market['id']
165
- trades = await self.subscribe(subscribeObject, messageHash)
166
- if self.newUpdates:
167
- limit = trades.getLimit(symbol, limit)
168
- return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
169
-
170
- def handle_trade(self, client: Client, message):
171
- type = self.safe_string(message, 'type')
172
- data = self.safe_value(message, 'data')
173
- marketId = self.safe_string(data, 'm')
174
- messageHash = type + ':' + marketId
175
- trade = self.parse_ws_trade(data)
176
- keys = list(self.trades.keys())
177
- length = len(keys)
178
- if length == 0:
179
- limit = self.safe_integer(self.options, 'tradesLimit')
180
- self.trades = ArrayCacheBySymbolById(limit)
181
- trades = self.trades
182
- trades.append(trade)
183
- client.resolve(trades, messageHash)
184
-
185
- def parse_ws_trade(self, trade, market=None):
186
- # public trades
187
- # {m: "DIL-ETH",
188
- # "i": "897ecae6-4b75-368a-ac00-be555e6ad65f",
189
- # "p": "0.09696995",
190
- # "q": "2.00000000",
191
- # "Q": "0.19393990",
192
- # "t": 1599504616247,
193
- # "s": "buy",
194
- # "u": 6620}
195
- # private trades
196
- # {i: "ee253d78-88be-37ed-a61c-a36395c2ce48",
197
- # "p": "0.09925382",
198
- # "q": "0.15000000",
199
- # "Q": "0.01488807",
200
- # "t": 1599499129369,
201
- # "s": "sell",
202
- # "u": 6603,
203
- # "f": "0.00030000",
204
- # "a": "DIL",
205
- # "g": "0.00856110",
206
- # "l": "maker",
207
- # "S": "pending"}
208
- marketId = self.safe_string(trade, 'm')
209
- symbol = self.safe_symbol(marketId)
210
- id = self.safe_string(trade, 'i')
211
- price = self.safe_string(trade, 'p')
212
- amount = self.safe_string(trade, 'q')
213
- cost = self.safe_string(trade, 'Q')
214
- timestamp = self.safe_integer(trade, 't')
215
- side = self.safe_string(trade, 's')
216
- fee = {
217
- 'currency': self.safe_string(trade, 'a'),
218
- 'cost': self.safe_string(trade, 'f'),
219
- }
220
- takerOrMarker = self.safe_string(trade, 'l')
221
- return self.safe_trade({
222
- 'info': trade,
223
- 'timestamp': timestamp,
224
- 'datetime': self.iso8601(timestamp),
225
- 'symbol': symbol,
226
- 'id': id,
227
- 'order': None,
228
- 'type': None,
229
- 'takerOrMaker': takerOrMarker,
230
- 'side': side,
231
- 'price': price,
232
- 'amount': amount,
233
- 'cost': cost,
234
- 'fee': fee,
235
- })
236
-
237
- async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
238
- """
239
- watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
240
-
241
- https://api-docs-v4.idex.io/#candles
242
-
243
- :param str symbol: unified symbol of the market to fetch OHLCV data for
244
- :param str timeframe: the length of time each candle represents
245
- :param int [since]: timestamp in ms of the earliest candle to fetch
246
- :param int [limit]: the maximum amount of candles to fetch
247
- :param dict [params]: extra parameters specific to the exchange API endpoint
248
- :returns int[][]: A list of candles ordered, open, high, low, close, volume
249
- """
250
- await self.load_markets()
251
- market = self.market(symbol)
252
- symbol = market['symbol']
253
- name = 'candles'
254
- interval = self.safe_string(self.timeframes, timeframe, timeframe)
255
- subscribeObject: dict = {
256
- 'name': name,
257
- 'markets': [market['id']],
258
- 'interval': interval,
259
- }
260
- messageHash = name + ':' + market['id']
261
- ohlcv = await self.subscribe(subscribeObject, messageHash)
262
- if self.newUpdates:
263
- limit = ohlcv.getLimit(symbol, limit)
264
- return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
265
-
266
- def handle_ohlcv(self, client: Client, message):
267
- # {type: "candles",
268
- # "data":
269
- # {m: "DIL-ETH",
270
- # "t": 1599477340109,
271
- # "i": "1m",
272
- # "s": 1599477300000,
273
- # "e": 1599477360000,
274
- # "o": "0.09911040",
275
- # "h": "0.09911040",
276
- # "l": "0.09911040",
277
- # "c": "0.09911040",
278
- # "v": "0.15000000",
279
- # "n": 1,
280
- # "u": 6531}}
281
- type = self.safe_string(message, 'type')
282
- data = self.safe_value(message, 'data')
283
- marketId = self.safe_string(data, 'm')
284
- messageHash = type + ':' + marketId
285
- parsed = [
286
- self.safe_integer(data, 's'),
287
- self.safe_float(data, 'o'),
288
- self.safe_float(data, 'h'),
289
- self.safe_float(data, 'l'),
290
- self.safe_float(data, 'c'),
291
- self.safe_float(data, 'v'),
292
- ]
293
- symbol = self.safe_symbol(marketId)
294
- interval = self.safe_string(data, 'i')
295
- timeframe = self.find_timeframe(interval)
296
- # TODO: move to base class
297
- self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
298
- stored = self.safe_value(self.ohlcvs[symbol], timeframe)
299
- if stored is None:
300
- limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
301
- stored = ArrayCacheByTimestamp(limit)
302
- self.ohlcvs[symbol][timeframe] = stored
303
- stored.append(parsed)
304
- client.resolve(stored, messageHash)
305
-
306
- def handle_subscribe_message(self, client: Client, message):
307
- # {
308
- # "type": "subscriptions",
309
- # "subscriptions": [
310
- # {
311
- # "name": "l2orderbook",
312
- # "markets": [
313
- # "DIL-ETH"
314
- # ]
315
- # }
316
- # ]
317
- # }
318
- subscriptions = self.safe_value(message, 'subscriptions')
319
- for i in range(0, len(subscriptions)):
320
- subscription = subscriptions[i]
321
- name = self.safe_string(subscription, 'name')
322
- if name == 'l2orderbook':
323
- markets = self.safe_value(subscription, 'markets')
324
- for j in range(0, len(markets)):
325
- marketId = markets[j]
326
- orderBookSubscriptions = self.safe_value(self.options, 'orderBookSubscriptions', {})
327
- if not (marketId in orderBookSubscriptions):
328
- symbol = self.safe_symbol(marketId)
329
- if not (symbol in self.orderbooks):
330
- orderbook = self.counted_order_book({})
331
- # orderbook.cache = [] # cache is never used?
332
- self.orderbooks[symbol] = orderbook
333
- self.spawn(self.fetch_order_book_snapshot, client, symbol)
334
- break
335
-
336
- async def fetch_order_book_snapshot(self, client, symbol, params={}):
337
- orderbook = self.orderbooks[symbol]
338
- market = self.market(symbol)
339
- messageHash = 'l2orderbook' + ':' + market['id']
340
- subscription = client.subscriptions[messageHash]
341
- if not subscription['fetchingOrderBookSnapshot']:
342
- subscription['startTime'] = self.milliseconds()
343
- subscription['fetchingOrderBookSnapshot'] = True
344
- maxAttempts = self.safe_integer(self.options, 'fetchOrderBookSnapshotMaxAttempts', 10)
345
- maxDelay = self.safe_integer(self.options, 'fetchOrderBookSnapshotMaxDelay', 10000)
346
- try:
347
- limit = self.safe_integer(subscription, 'limit', 0)
348
- # 3. Request a level-2 order book snapshot for the market from the REST API Order Books endpoint with limit set to 0.
349
- snapshot = await self.fetch_rest_order_book_safe(symbol, limit)
350
- firstBuffered = self.safe_value(orderbook.cache, 0)
351
- firstData = self.safe_value(firstBuffered, 'data')
352
- firstNonce = self.safe_integer(firstData, 'u')
353
- length = len(orderbook.cache)
354
- lastBuffered = self.safe_value(orderbook.cache, length - 1)
355
- lastData = self.safe_value(lastBuffered, 'data')
356
- lastNonce = self.safe_integer(lastData, 'u')
357
- bothExist = (firstNonce is not None) and (lastNonce is not None)
358
- # ensure the snapshot is inside the range of our cached messages
359
- # for example if the snapshot nonce is 100
360
- # the first nonce must be less than or equal to 101 and the last nonce must be greater than 101
361
- if bothExist and (firstNonce <= snapshot['nonce'] + 1) and (lastNonce > snapshot['nonce']):
362
- orderbook.reset(snapshot)
363
- for i in range(0, len(orderbook.cache)):
364
- message = orderbook.cache[i]
365
- data = self.safe_value(message, 'data')
366
- u = self.safe_integer(data, 'u')
367
- if u > orderbook['nonce']:
368
- # 5. Discard all order book update messages with sequence numbers less than or equal to the snapshot sequence number.
369
- # 6. Apply the remaining buffered order book update messages and any incoming order book update messages to the order book snapshot.
370
- self.handle_order_book_message(client, message, orderbook)
371
- subscription['fetchingOrderBookSnapshot'] = False
372
- client.resolve(orderbook, messageHash)
373
- else:
374
- # 4. If the sequence in the order book snapshot is less than the sequence of the
375
- # first buffered order book update message, discard the order book snapshot and retry step 3.
376
- # self will continue to recurse until we have a buffered message
377
- # since updates the order book endpoint depend on order events
378
- # so it will eventually raise if there are no orders on a pair
379
- subscription['numAttempts'] = subscription['numAttempts'] + 1
380
- timeElapsed = self.milliseconds() - subscription['startTime']
381
- maxAttemptsValid = subscription['numAttempts'] < maxAttempts
382
- timeElapsedValid = timeElapsed < maxDelay
383
- if maxAttemptsValid and timeElapsedValid:
384
- self.delay(self.rateLimit, self.fetch_order_book_snapshot, client, symbol)
385
- else:
386
- endpart = ' in ' + str(maxAttempts) + ' attempts' if (not maxAttemptsValid) else ' after ' + str(maxDelay) + ' milliseconds'
387
- raise InvalidNonce(self.id + ' failed to synchronize WebSocket feed with the snapshot for symbol ' + symbol + endpart)
388
- except Exception as e:
389
- subscription['fetchingOrderBookSnapshot'] = False
390
- client.reject(e, messageHash)
391
-
392
- async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
393
- """
394
- watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
395
-
396
- https://api-docs-v4.idex.io/#l2-order-book
397
-
398
- :param str symbol: unified symbol of the market to fetch the order book for
399
- :param int [limit]: the maximum amount of order book entries to return
400
- :param dict [params]: extra parameters specific to the exchange API endpoint
401
- :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
402
- """
403
- await self.load_markets()
404
- market = self.market(symbol)
405
- name = 'l2orderbook'
406
- subscribeObject: dict = {
407
- 'name': name,
408
- 'markets': [market['id']],
409
- }
410
- messageHash = name + ':' + market['id']
411
- subscription: dict = {
412
- 'fetchingOrderBookSnapshot': False,
413
- 'numAttempts': 0,
414
- 'startTime': None,
415
- }
416
- if limit is None:
417
- subscription['limit'] = 1000
418
- else:
419
- subscription['limit'] = limit
420
- # 1. Connect to the WebSocket API endpoint and subscribe to the L2 Order Book for the target market.
421
- orderbook = await self.subscribe(subscribeObject, messageHash, subscription)
422
- return orderbook.limit()
423
-
424
- def handle_order_book(self, client: Client, message):
425
- data = self.safe_value(message, 'data')
426
- marketId = self.safe_string(data, 'm')
427
- symbol = self.safe_symbol(marketId)
428
- orderbook = self.orderbooks[symbol]
429
- if orderbook['nonce'] is None:
430
- # 2. Buffer the incoming order book update subscription messages.
431
- orderbook.cache.append(message)
432
- else:
433
- self.handle_order_book_message(client, message, orderbook)
434
-
435
- def handle_order_book_message(self, client: Client, message, orderbook):
436
- # {
437
- # "type": "l2orderbook",
438
- # "data": {
439
- # "m": "DIL-ETH",
440
- # "t": 1600197205037,
441
- # "u": 94116643,
442
- # "b": [
443
- # [
444
- # "0.09662187",
445
- # "0.00000000",
446
- # 0
447
- # ]
448
- # ],
449
- # "a": []
450
- # }
451
- # }
452
- type = self.safe_string(message, 'type')
453
- data = self.safe_value(message, 'data')
454
- marketId = self.safe_string(data, 'm')
455
- messageHash = type + ':' + marketId
456
- nonce = self.safe_integer(data, 'u')
457
- timestamp = self.safe_integer(data, 't')
458
- bids = self.safe_value(data, 'b')
459
- asks = self.safe_value(data, 'a')
460
- self.handle_deltas(orderbook['bids'], bids)
461
- self.handle_deltas(orderbook['asks'], asks)
462
- orderbook['nonce'] = nonce
463
- orderbook['timestamp'] = timestamp
464
- orderbook['datetime'] = self.iso8601(timestamp)
465
- client.resolve(orderbook, messageHash)
466
-
467
- def handle_delta(self, bookside, delta):
468
- price = self.safe_float(delta, 0)
469
- amount = self.safe_float(delta, 1)
470
- count = self.safe_integer(delta, 2)
471
- bookside.storeArray([price, amount, count])
472
-
473
- def handle_deltas(self, bookside, deltas):
474
- for i in range(0, len(deltas)):
475
- self.handle_delta(bookside, deltas[i])
476
-
477
- async def authenticate(self, params={}):
478
- time = self.seconds()
479
- lastAuthenticatedTime = self.safe_integer(self.options, 'lastAuthenticatedTime', 0)
480
- if time - lastAuthenticatedTime > 900:
481
- request: dict = {
482
- 'wallet': self.walletAddress,
483
- 'nonce': self.uuidv1(),
484
- }
485
- response = await self.privateGetWsToken(self.extend(request, params))
486
- self.options['lastAuthenticatedTime'] = time
487
- self.options['token'] = self.safe_string(response, 'token')
488
- return self.options['token']
489
-
490
- async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
491
- """
492
- watches information on multiple orders made by the user
493
-
494
- https://api-docs-v4.idex.io/#orders
495
-
496
- :param str symbol: unified market symbol of the market orders were made in
497
- :param int [since]: the earliest time in ms to fetch orders for
498
- :param int [limit]: the maximum number of order structures to retrieve
499
- :param dict [params]: extra parameters specific to the exchange API endpoint
500
- :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
501
- """
502
- await self.load_markets()
503
- name = 'orders'
504
- subscribeObject: dict = {
505
- 'name': name,
506
- }
507
- messageHash = name
508
- if symbol is not None:
509
- symbol = self.symbol(symbol)
510
- marketId = self.market_id(symbol)
511
- subscribeObject['markets'] = [marketId]
512
- messageHash = name + ':' + marketId
513
- orders = await self.subscribe_private(subscribeObject, messageHash)
514
- if self.newUpdates:
515
- limit = orders.getLimit(symbol, limit)
516
- return self.filter_by_since_limit(orders, since, limit, 'timestamp', True)
517
-
518
- def handle_order(self, client: Client, message):
519
- # {
520
- # "type": "orders",
521
- # "data": {
522
- # "m": "DIL-ETH",
523
- # "i": "8f75dd30-f12d-11ea-b63c-df3381b4b5b4",
524
- # "w": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
525
- # "t": 1599498857138,
526
- # "T": 1599498857092,
527
- # "x": "fill",
528
- # "X": "filled",
529
- # "u": 67695627,
530
- # "o": "limit",
531
- # "S": "buy",
532
- # "q": "0.15000000",
533
- # "z": "0.15000000",
534
- # "Z": "0.01486286",
535
- # "v": "0.09908573",
536
- # "p": "1.00000000",
537
- # "f": "gtc",
538
- # "V": "2",
539
- # "F": [
540
- # {
541
- # "i": "5cdc6d14-bc35-3279-ab5e-40d654ca1523",
542
- # "p": "0.09908577",
543
- # "q": "0.15000000",
544
- # "Q": "0.01486286",
545
- # "t": 1599498857092,
546
- # "s": "sell",
547
- # "u": 6600,
548
- # "f": "0.00030000",
549
- # "a": "DIL",
550
- # "g": "0.00856977",
551
- # "l": "maker",
552
- # "S": "pending"
553
- # }
554
- # ]
555
- # }
556
- # }
557
- type = self.safe_string(message, 'type')
558
- order = self.safe_value(message, 'data')
559
- marketId = self.safe_string(order, 'm')
560
- symbol = self.safe_symbol(marketId)
561
- timestamp = self.safe_integer(order, 't')
562
- fills = self.safe_value(order, 'F', [])
563
- trades = []
564
- for i in range(0, len(fills)):
565
- trades.append(self.parse_ws_trade(fills[i]))
566
- id = self.safe_string(order, 'i')
567
- side = self.safe_string(order, 's')
568
- orderType = self.safe_string(order, 'o')
569
- amount = self.safe_string(order, 'q')
570
- filled = self.safe_string(order, 'z')
571
- average = self.safe_string(order, 'v')
572
- price = self.safe_string(order, 'price', average) # for market orders
573
- rawStatus = self.safe_string(order, 'X')
574
- status = self.parse_order_status(rawStatus)
575
- fee = {
576
- 'currency': None,
577
- 'cost': None,
578
- }
579
- lastTrade = None
580
- for i in range(0, len(trades)):
581
- lastTrade = trades[i]
582
- fee['currency'] = lastTrade['fee']['currency']
583
- stringLastTradeFee = lastTrade['fee']['cost']
584
- fee['cost'] = Precise.string_add(fee['cost'], stringLastTradeFee)
585
- lastTradeTimestamp = self.safe_integer(lastTrade, 'timestamp')
586
- parsedOrder = self.safe_order({
587
- 'info': message,
588
- 'id': id,
589
- 'clientOrderId': None,
590
- 'timestamp': timestamp,
591
- 'datetime': self.iso8601(timestamp),
592
- 'lastTradeTimestamp': lastTradeTimestamp,
593
- 'symbol': symbol,
594
- 'type': orderType,
595
- 'side': side,
596
- 'price': self.parse_number(price),
597
- 'stopPrice': None,
598
- 'triggerPrice': None,
599
- 'amount': self.parse_number(amount),
600
- 'cost': None,
601
- 'average': self.parse_number(average),
602
- 'filled': self.parse_number(filled),
603
- 'remaining': None,
604
- 'status': status,
605
- 'fee': fee,
606
- 'trades': trades,
607
- })
608
- if self.orders is None:
609
- limit = self.safe_integer(self.options, 'ordersLimit', 1000)
610
- self.orders = ArrayCacheBySymbolById(limit)
611
- orders = self.orders
612
- orders.append(parsedOrder)
613
- symbolSpecificMessageHash = type + ':' + marketId
614
- client.resolve(orders, symbolSpecificMessageHash)
615
- client.resolve(orders, type)
616
-
617
- async def watch_transactions(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
618
- await self.load_markets()
619
- name = 'balances'
620
- subscribeObject: dict = {
621
- 'name': name,
622
- }
623
- messageHash = name
624
- if code is not None:
625
- messageHash = name + ':' + code
626
- transactions = await self.subscribe_private(subscribeObject, messageHash)
627
- if self.newUpdates:
628
- limit = transactions.getLimit(code, limit)
629
- return self.filter_by_since_limit(transactions, since, limit, 'timestamp')
630
-
631
- def handle_transaction(self, client: Client, message):
632
- # Update Speed: Real time, updates on any deposit or withdrawal of the wallet
633
- # {type: "balances",
634
- # "data":
635
- # {w: "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
636
- # "a": "ETH",
637
- # "q": "0.11198667",
638
- # "f": "0.11198667",
639
- # "l": "0.00000000",
640
- # "d": "0.00"}}
641
- type = self.safe_string(message, 'type')
642
- data = self.safe_value(message, 'data')
643
- currencyId = self.safe_string(data, 'a')
644
- messageHash = type + ':' + currencyId
645
- code = self.safe_currency_code(currencyId)
646
- address = self.safe_string(data, 'w')
647
- transaction: dict = {
648
- 'info': message,
649
- 'id': None,
650
- 'currency': code,
651
- 'amount': None,
652
- 'address': address,
653
- 'addressTo': None,
654
- 'addressFrom': None,
655
- 'tag': None,
656
- 'tagTo': None,
657
- 'tagFrom': None,
658
- 'status': 'ok',
659
- 'type': None,
660
- 'updated': None,
661
- 'txid': None,
662
- 'timestamp': None,
663
- 'datetime': None,
664
- 'fee': None,
665
- }
666
- if not (code in self.transactions):
667
- limit = self.safe_integer(self.options, 'transactionsLimit', 1000)
668
- self.transactions[code] = ArrayCache(limit)
669
- transactions = self.transactions[code]
670
- transactions.append(transaction)
671
- client.resolve(transactions, messageHash)
672
- client.resolve(transactions, type)
673
-
674
- def handle_message(self, client: Client, message):
675
- type = self.safe_string(message, 'type')
676
- methods: dict = {
677
- 'tickers': self.handle_ticker,
678
- 'trades': self.handle_trade,
679
- 'subscriptions': self.handle_subscribe_message,
680
- 'candles': self.handle_ohlcv,
681
- 'l2orderbook': self.handle_order_book,
682
- 'balances': self.handle_transaction,
683
- 'orders': self.handle_order,
684
- }
685
- if type in methods:
686
- method = methods[type]
687
- method(client, message)
File without changes