ccxt 4.4.35__py2.py3-none-any.whl → 4.4.37__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 (55) hide show
  1. ccxt/__init__.py +5 -3
  2. ccxt/abstract/bitfinex.py +136 -65
  3. ccxt/abstract/bitfinex1.py +69 -0
  4. ccxt/abstract/bitopro.py +1 -0
  5. ccxt/abstract/bybit.py +15 -0
  6. ccxt/abstract/defx.py +69 -0
  7. ccxt/abstract/deribit.py +1 -0
  8. ccxt/abstract/gate.py +14 -0
  9. ccxt/abstract/gateio.py +14 -0
  10. ccxt/async_support/__init__.py +5 -3
  11. ccxt/async_support/base/exchange.py +1 -1
  12. ccxt/async_support/bitfinex.py +3005 -1084
  13. ccxt/async_support/bitfinex1.py +1704 -0
  14. ccxt/async_support/bitfinex2.py +18 -13
  15. ccxt/async_support/bitmex.py +103 -1
  16. ccxt/async_support/bitopro.py +21 -4
  17. ccxt/async_support/bitso.py +2 -1
  18. ccxt/async_support/bybit.py +21 -1
  19. ccxt/async_support/coinbase.py +86 -0
  20. ccxt/async_support/defx.py +1981 -0
  21. ccxt/async_support/deribit.py +27 -12
  22. ccxt/async_support/gate.py +15 -1
  23. ccxt/async_support/htx.py +11 -2
  24. ccxt/async_support/hyperliquid.py +124 -14
  25. ccxt/async_support/kraken.py +39 -41
  26. ccxt/async_support/paradex.py +2 -2
  27. ccxt/base/exchange.py +6 -2
  28. ccxt/bitfinex.py +3005 -1084
  29. ccxt/bitfinex1.py +1703 -0
  30. ccxt/bitfinex2.py +18 -13
  31. ccxt/bitmex.py +103 -1
  32. ccxt/bitopro.py +21 -4
  33. ccxt/bitso.py +2 -1
  34. ccxt/bybit.py +21 -1
  35. ccxt/coinbase.py +86 -0
  36. ccxt/defx.py +1980 -0
  37. ccxt/deribit.py +27 -12
  38. ccxt/gate.py +15 -1
  39. ccxt/htx.py +11 -2
  40. ccxt/hyperliquid.py +124 -14
  41. ccxt/kraken.py +39 -41
  42. ccxt/paradex.py +2 -2
  43. ccxt/pro/__init__.py +5 -3
  44. ccxt/pro/bitfinex.py +725 -274
  45. ccxt/pro/bitfinex1.py +635 -0
  46. ccxt/pro/defx.py +832 -0
  47. ccxt/pro/probit.py +1 -0
  48. ccxt/test/tests_async.py +15 -1
  49. ccxt/test/tests_sync.py +15 -1
  50. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/METADATA +11 -10
  51. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/RECORD +54 -47
  52. ccxt/abstract/bitfinex2.py +0 -140
  53. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/LICENSE.txt +0 -0
  54. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/WHEEL +0 -0
  55. {ccxt-4.4.35.dist-info → ccxt-4.4.37.dist-info}/top_level.txt +0 -0
ccxt/pro/defx.py ADDED
@@ -0,0 +1,832 @@
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 Balances, Int, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
9
+ from ccxt.async_support.base.ws.client import Client
10
+ from typing import List
11
+ from typing import Any
12
+ from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import ArgumentsRequired
14
+
15
+
16
+ class defx(ccxt.async_support.defx):
17
+
18
+ def describe(self):
19
+ return self.deep_extend(super(defx, self).describe(), {
20
+ 'has': {
21
+ 'ws': True,
22
+ 'watchBalance': True,
23
+ 'watchTicker': True,
24
+ 'watchTickers': True,
25
+ 'watchBidsAsks': True,
26
+ 'watchTrades': True,
27
+ 'watchTradesForSymbols': True,
28
+ 'watchMyTrades': False,
29
+ 'watchOrders': True,
30
+ 'watchOrderBook': True,
31
+ 'watchOrderBookForSymbols': True,
32
+ 'watchOHLCV': True,
33
+ 'watchOHLCVForSymbols': True,
34
+ },
35
+ 'urls': {
36
+ 'test': {
37
+ 'ws': {
38
+ 'public': 'wss://stream.testnet.defx.com/pricefeed',
39
+ 'private': 'wss://ws.testnet.defx.com/user',
40
+ },
41
+ },
42
+ 'api': {
43
+ 'ws': {
44
+ 'public': 'wss://marketfeed.api.defx.com/pricefeed',
45
+ 'private': 'wss://userfeed.api.defx.com/user',
46
+ },
47
+ },
48
+ },
49
+ 'options': {
50
+ 'listenKeyRefreshRate': 3540000, # 1 hour(59 mins so we have 1min to renew the token)
51
+ 'ws': {
52
+ 'timeframes': {
53
+ '1m': '1m',
54
+ '3m': '3m',
55
+ '5m': '5m',
56
+ '15m': '15m',
57
+ '30m': '30m',
58
+ '1h': '1h',
59
+ '2h': '2h',
60
+ '4h': '4h',
61
+ '12h': '12h',
62
+ '1d': '1d',
63
+ '1w': '1w',
64
+ '1M': '1M',
65
+ },
66
+ },
67
+ },
68
+ 'streaming': {
69
+ },
70
+ 'exceptions': {
71
+ },
72
+ })
73
+
74
+ async def watch_public(self, topics, messageHashes, params={}):
75
+ await self.load_markets()
76
+ url = self.urls['api']['ws']['public']
77
+ request: dict = {
78
+ 'method': 'SUBSCRIBE',
79
+ 'topics': topics,
80
+ }
81
+ message = self.extend(request, params)
82
+ return await self.watch_multiple(url, messageHashes, message, messageHashes)
83
+
84
+ async def un_watch_public(self, topics, messageHashes, params={}):
85
+ await self.load_markets()
86
+ url = self.urls['api']['ws']['public']
87
+ request: dict = {
88
+ 'method': 'UNSUBSCRIBE',
89
+ 'topics': topics,
90
+ }
91
+ message = self.extend(request, params)
92
+ return await self.watch_multiple(url, messageHashes, message, messageHashes)
93
+
94
+ async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
95
+ """
96
+ watches historical candlestick data containing the open, high, low, close price, and the volume of a market
97
+
98
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
99
+
100
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
101
+ :param str timeframe: the length of time each candle represents
102
+ :param int [since]: timestamp in ms of the earliest candle to fetch
103
+ :param int [limit]: the maximum amount of candles to fetch
104
+ :param dict [params]: extra parameters specific to the exchange API endpoint
105
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
106
+ """
107
+ result = await self.watch_ohlcv_for_symbols([[symbol, timeframe]], since, limit, params)
108
+ return result[symbol][timeframe]
109
+
110
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
111
+ """
112
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
113
+
114
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
115
+
116
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
117
+ :param str timeframe: the length of time each candle represents
118
+ :param dict [params]: extra parameters specific to the exchange API endpoint
119
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
120
+ """
121
+ return await self.un_watch_ohlcv_for_symbols([[symbol, timeframe]], params)
122
+
123
+ async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
124
+ """
125
+ watches historical candlestick data containing the open, high, low, close price, and the volume of a market
126
+
127
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
128
+
129
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
130
+ :param int [since]: timestamp in ms of the earliest candle to fetch
131
+ :param int [limit]: the maximum amount of candles to fetch
132
+ :param dict [params]: extra parameters specific to the exchange API endpoint
133
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
134
+ """
135
+ symbolsLength = len(symbolsAndTimeframes)
136
+ if symbolsLength == 0 or not isinstance(symbolsAndTimeframes[0], list):
137
+ raise ArgumentsRequired(self.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]")
138
+ await self.load_markets()
139
+ topics = []
140
+ messageHashes = []
141
+ for i in range(0, len(symbolsAndTimeframes)):
142
+ symbolAndTimeframe = symbolsAndTimeframes[i]
143
+ marketId = self.safe_string(symbolAndTimeframe, 0)
144
+ market = self.market(marketId)
145
+ tf = self.safe_string(symbolAndTimeframe, 1)
146
+ interval = self.safe_string(self.timeframes, tf, tf)
147
+ topics.append('symbol:' + market['id'] + ':ohlc:' + interval)
148
+ messageHashes.append('candles:' + interval + ':' + market['symbol'])
149
+ symbol, timeframe, candles = await self.watch_public(topics, messageHashes, params)
150
+ if self.newUpdates:
151
+ limit = candles.getLimit(symbol, limit)
152
+ filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
153
+ return self.create_ohlcv_object(symbol, timeframe, filtered)
154
+
155
+ async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}) -> Any:
156
+ """
157
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
158
+
159
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
160
+
161
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
162
+ :param dict [params]: extra parameters specific to the exchange API endpoint
163
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
164
+ """
165
+ symbolsLength = len(symbolsAndTimeframes)
166
+ if symbolsLength == 0 or not isinstance(symbolsAndTimeframes[0], list):
167
+ raise ArgumentsRequired(self.id + " unWatchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]")
168
+ await self.load_markets()
169
+ topics = []
170
+ messageHashes = []
171
+ for i in range(0, len(symbolsAndTimeframes)):
172
+ symbolAndTimeframe = symbolsAndTimeframes[i]
173
+ marketId = self.safe_string(symbolAndTimeframe, 0)
174
+ market = self.market(marketId)
175
+ tf = self.safe_string(symbolAndTimeframe, 1)
176
+ interval = self.safe_string(self.timeframes, tf, tf)
177
+ topics.append('symbol:' + market['id'] + ':ohlc:' + interval)
178
+ messageHashes.append('candles:' + interval + ':' + market['symbol'])
179
+ return await self.un_watch_public(topics, messageHashes, params)
180
+
181
+ def handle_ohlcv(self, client: Client, message):
182
+ #
183
+ # {
184
+ # "topic": "symbol:BTC_USDC:ohlc:3m",
185
+ # "event": "ohlc",
186
+ # "timestamp": 1730794277104,
187
+ # "data": {
188
+ # "symbol": "BTC_USDC",
189
+ # "window": "3m",
190
+ # "open": "57486.90000000",
191
+ # "high": "57486.90000000",
192
+ # "low": "57486.90000000",
193
+ # "close": "57486.90000000",
194
+ # "volume": "0.000",
195
+ # "quoteAssetVolume": "0.00000000",
196
+ # "takerBuyAssetVolume": "0.000",
197
+ # "takerBuyQuoteAssetVolume": "0.00000000",
198
+ # "numberOfTrades": 0,
199
+ # "start": 1730794140000,
200
+ # "end": 1730794320000,
201
+ # "isClosed": False
202
+ # }
203
+ # }
204
+ #
205
+ data = self.safe_dict(message, 'data', {})
206
+ marketId = self.safe_string(data, 'symbol')
207
+ market = self.market(marketId)
208
+ symbol = market['symbol']
209
+ timeframe = self.safe_string(data, 'window')
210
+ if not (symbol in self.ohlcvs):
211
+ self.ohlcvs[symbol] = {}
212
+ if not (timeframe in self.ohlcvs[symbol]):
213
+ limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
214
+ stored = ArrayCacheByTimestamp(limit)
215
+ self.ohlcvs[symbol][timeframe] = stored
216
+ ohlcv = self.ohlcvs[symbol][timeframe]
217
+ parsed = self.parse_ohlcv(data)
218
+ ohlcv.append(parsed)
219
+ messageHash = 'candles:' + timeframe + ':' + symbol
220
+ client.resolve([symbol, timeframe, ohlcv], messageHash)
221
+
222
+ async def watch_ticker(self, symbol: str, params={}) -> Ticker:
223
+ """
224
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
225
+
226
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
227
+
228
+ :param str symbol: unified symbol of the market to fetch the ticker for
229
+ :param dict [params]: extra parameters specific to the exchange API endpoint
230
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
231
+ """
232
+ await self.load_markets()
233
+ market = self.market(symbol)
234
+ symbol = market['symbol']
235
+ topic = 'symbol:' + market['id'] + ':24hrTicker'
236
+ messageHash = 'ticker:' + symbol
237
+ return await self.watch_public([topic], [messageHash], params)
238
+
239
+ async def un_watch_ticker(self, symbol: str, params={}) -> Any:
240
+ """
241
+ unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
242
+
243
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
244
+
245
+ :param str symbol: unified symbol of the market to fetch the ticker for
246
+ :param dict [params]: extra parameters specific to the exchange API endpoint
247
+ :param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
248
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
249
+ """
250
+ return await self.un_watch_tickers([symbol], params)
251
+
252
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
253
+ """
254
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
255
+
256
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
257
+
258
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
259
+ :param dict [params]: extra parameters specific to the exchange API endpoint
260
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
261
+ """
262
+ await self.load_markets()
263
+ symbols = self.market_symbols(symbols, None, False)
264
+ topics = []
265
+ messageHashes = []
266
+ for i in range(0, len(symbols)):
267
+ symbol = symbols[i]
268
+ marketId = self.market_id(symbol)
269
+ topics.append('symbol:' + marketId + ':24hrTicker')
270
+ messageHashes.append('ticker:' + symbol)
271
+ await self.watch_public(topics, messageHashes, params)
272
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
273
+
274
+ async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any:
275
+ """
276
+ unWatches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
277
+
278
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
279
+
280
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
281
+ :param dict [params]: extra parameters specific to the exchange API endpoint
282
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
283
+ """
284
+ await self.load_markets()
285
+ symbols = self.market_symbols(symbols, None, False)
286
+ topics = []
287
+ messageHashes = []
288
+ for i in range(0, len(symbols)):
289
+ symbol = symbols[i]
290
+ marketId = self.market_id(symbol)
291
+ topics.append('symbol:' + marketId + ':24hrTicker')
292
+ messageHashes.append('ticker:' + symbol)
293
+ return await self.un_watch_public(topics, messageHashes, params)
294
+
295
+ def handle_ticker(self, client: Client, message):
296
+ #
297
+ # {
298
+ # "topic": "symbol:BTC_USDC:24hrTicker",
299
+ # "event": "24hrTicker",
300
+ # "timestamp": 1730862543095,
301
+ # "data": {
302
+ # "symbol": "BTC_USDC",
303
+ # "priceChange": "17114.70000000",
304
+ # "priceChangePercent": "29.77",
305
+ # "weightedAvgPrice": "6853147668",
306
+ # "lastPrice": "74378.90000000",
307
+ # "lastQty": "0.107",
308
+ # "bestBidPrice": "61987.60000000",
309
+ # "bestBidQty": "0.005",
310
+ # "bestAskPrice": "84221.60000000",
311
+ # "bestAskQty": "0.015",
312
+ # "openPrice": "57486.90000000",
313
+ # "highPrice": "88942.60000000",
314
+ # "lowPrice": "47364.20000000",
315
+ # "volume": "28.980",
316
+ # "quoteVolume": "1986042.19424035",
317
+ # "openTime": 1730776080000,
318
+ # "closeTime": 1730862540000,
319
+ # "openInterestBase": "67.130",
320
+ # "openInterestQuote": "5008005.40800000"
321
+ # }
322
+ # }
323
+ #
324
+ self.handle_bid_ask(client, message)
325
+ data = self.safe_dict(message, 'data', {})
326
+ parsedTicker = self.parse_ticker(data)
327
+ symbol = parsedTicker['symbol']
328
+ timestamp = self.safe_integer(message, 'timestamp')
329
+ parsedTicker['timestamp'] = timestamp
330
+ parsedTicker['datetime'] = self.iso8601(timestamp)
331
+ self.tickers[symbol] = parsedTicker
332
+ messageHash = 'ticker:' + symbol
333
+ client.resolve(parsedTicker, messageHash)
334
+
335
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
336
+ """
337
+ watches best bid & ask for symbols
338
+
339
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
340
+
341
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
342
+ :param dict [params]: extra parameters specific to the exchange API endpoint
343
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
344
+ """
345
+ await self.load_markets()
346
+ symbols = self.market_symbols(symbols, None, False)
347
+ topics = []
348
+ messageHashes = []
349
+ for i in range(0, len(symbols)):
350
+ symbol = symbols[i]
351
+ marketId = self.market_id(symbol)
352
+ topics.append('symbol:' + marketId + ':24hrTicker')
353
+ messageHashes.append('bidask:' + symbol)
354
+ await self.watch_public(topics, messageHashes, params)
355
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
356
+
357
+ def handle_bid_ask(self, client: Client, message):
358
+ data = self.safe_dict(message, 'data', {})
359
+ parsedTicker = self.parse_ws_bid_ask(data)
360
+ symbol = parsedTicker['symbol']
361
+ timestamp = self.safe_integer(message, 'timestamp')
362
+ parsedTicker['timestamp'] = timestamp
363
+ parsedTicker['datetime'] = self.iso8601(timestamp)
364
+ self.bidsasks[symbol] = parsedTicker
365
+ messageHash = 'bidask:' + symbol
366
+ client.resolve(parsedTicker, messageHash)
367
+
368
+ def parse_ws_bid_ask(self, ticker, market=None):
369
+ marketId = self.safe_string(ticker, 'symbol')
370
+ market = self.safe_market(marketId, market)
371
+ symbol = self.safe_string(market, 'symbol')
372
+ return self.safe_ticker({
373
+ 'symbol': symbol,
374
+ 'timestamp': None,
375
+ 'datetime': None,
376
+ 'ask': self.safe_string(ticker, 'bestAskPrice'),
377
+ 'askVolume': self.safe_string(ticker, 'bestAskQty'),
378
+ 'bid': self.safe_string(ticker, 'bestBidPrice'),
379
+ 'bidVolume': self.safe_string(ticker, 'bestBidQty'),
380
+ 'info': ticker,
381
+ }, market)
382
+
383
+ async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
384
+ """
385
+ watches information on multiple trades made in a market
386
+
387
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
388
+
389
+ :param str symbol: unified symbol of the market to fetch the ticker for
390
+ :param int [since]: the earliest time in ms to fetch trades for
391
+ :param int [limit]: the maximum number of trade structures to retrieve
392
+ :param dict [params]: extra parameters specific to the exchange API endpoint
393
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
394
+ """
395
+ return await self.watch_trades_for_symbols([symbol], since, limit, params)
396
+
397
+ async def un_watch_trades(self, symbol: str, params={}) -> Any:
398
+ """
399
+ unWatches from the stream channel
400
+
401
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
402
+
403
+ :param str symbol: unified symbol of the market to fetch trades for
404
+ :param dict [params]: extra parameters specific to the exchange API endpoint
405
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
406
+ """
407
+ return await self.un_watch_trades_for_symbols([symbol], params)
408
+
409
+ async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
410
+ """
411
+ watches information on multiple trades made in a market
412
+
413
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
414
+
415
+ :param str[] symbols: unified symbol of the market to fetch trades for
416
+ :param int [since]: the earliest time in ms to fetch trades for
417
+ :param int [limit]: the maximum number of trade structures to retrieve
418
+ :param dict [params]: extra parameters specific to the exchange API endpoint
419
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
420
+ """
421
+ await self.load_markets()
422
+ symbols = self.market_symbols(symbols)
423
+ symbolsLength = len(symbols)
424
+ if symbolsLength == 0:
425
+ raise ArgumentsRequired(self.id + ' watchTradesForSymbols() requires a non-empty array of symbols')
426
+ topics = []
427
+ messageHashes = []
428
+ for i in range(0, len(symbols)):
429
+ symbol = symbols[i]
430
+ marketId = self.market_id(symbol)
431
+ topics.append('symbol:' + marketId + ':trades')
432
+ messageHashes.append('trade:' + symbol)
433
+ trades = await self.watch_public(topics, messageHashes, params)
434
+ if self.newUpdates:
435
+ first = self.safe_value(trades, 0)
436
+ tradeSymbol = self.safe_string(first, 'symbol')
437
+ limit = trades.getLimit(tradeSymbol, limit)
438
+ return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
439
+
440
+ async def un_watch_trades_for_symbols(self, symbols: List[str], params={}) -> Any:
441
+ """
442
+ unWatches from the stream channel
443
+
444
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
445
+
446
+ :param str[] symbols: unified symbol of the market to fetch trades for
447
+ :param dict [params]: extra parameters specific to the exchange API endpoint
448
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
449
+ """
450
+ await self.load_markets()
451
+ symbols = self.market_symbols(symbols)
452
+ symbolsLength = len(symbols)
453
+ if symbolsLength == 0:
454
+ raise ArgumentsRequired(self.id + ' unWatchTradesForSymbols() requires a non-empty array of symbols')
455
+ topics = []
456
+ messageHashes = []
457
+ for i in range(0, len(symbols)):
458
+ symbol = symbols[i]
459
+ marketId = self.market_id(symbol)
460
+ topics.append('symbol:' + marketId + ':trades')
461
+ messageHashes.append('trade:' + symbol)
462
+ return await self.un_watch_public(topics, messageHashes, params)
463
+
464
+ def handle_trades(self, client: Client, message):
465
+ #
466
+ # {
467
+ # "topic": "symbol:SOL_USDC:trades",
468
+ # "event": "trades",
469
+ # "timestamp": 1730967426331,
470
+ # "data": {
471
+ # "buyerMaker": True,
472
+ # "price": "188.38700000",
473
+ # "qty": "1.00",
474
+ # "symbol": "SOL_USDC",
475
+ # "timestamp": 1730967426328
476
+ # }
477
+ # }
478
+ #
479
+ data = self.safe_dict(message, 'data', {})
480
+ parsedTrade = self.parse_trade(data)
481
+ symbol = parsedTrade['symbol']
482
+ if not (symbol in self.trades):
483
+ limit = self.safe_integer(self.options, 'tradesLimit', 1000)
484
+ stored = ArrayCache(limit)
485
+ self.trades[symbol] = stored
486
+ trades = self.trades[symbol]
487
+ trades.append(parsedTrade)
488
+ messageHash = 'trade:' + symbol
489
+ client.resolve(trades, messageHash)
490
+
491
+ async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
492
+ """
493
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
494
+
495
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
496
+
497
+ :param str symbol: unified symbol of the market to fetch the order book for
498
+ :param int [limit]: the maximum amount of order book entries to return
499
+ :param dict [params]: extra parameters specific to the exchange API endpoint
500
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
501
+ """
502
+ return await self.watch_order_book_for_symbols([symbol], limit, params)
503
+
504
+ async def un_watch_order_book(self, symbol: str, params={}) -> Any:
505
+ """
506
+ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
507
+
508
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
509
+
510
+ :param str symbol: unified array of symbols
511
+ :param dict [params]: extra parameters specific to the exchange API endpoint
512
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
513
+ """
514
+ return await self.un_watch_order_book_for_symbols([symbol], params)
515
+
516
+ async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
517
+ """
518
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
519
+
520
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
521
+
522
+ :param str[] symbols: unified array of symbols
523
+ :param int [limit]: the maximum amount of order book entries to return
524
+ :param dict [params]: extra parameters specific to the exchange API endpoint
525
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
526
+ """
527
+ await self.load_markets()
528
+ symbolsLength = len(symbols)
529
+ if symbolsLength == 0:
530
+ raise ArgumentsRequired(self.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols')
531
+ symbols = self.market_symbols(symbols)
532
+ topics = []
533
+ messageHashes = []
534
+ for i in range(0, len(symbols)):
535
+ symbol = symbols[i]
536
+ marketId = self.market_id(symbol)
537
+ topics.append('symbol:' + marketId + ':depth:20:0.001')
538
+ messageHashes.append('orderbook:' + symbol)
539
+ orderbook = await self.watch_public(topics, messageHashes, params)
540
+ return orderbook.limit()
541
+
542
+ async def un_watch_order_book_for_symbols(self, symbols: List[str], params={}) -> Any:
543
+ """
544
+ unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
545
+
546
+ https://www.postman.com/defxcode/defx-public-apis/collection/667939a1b5d8069c13d614e9
547
+
548
+ :param str[] symbols: unified array of symbols
549
+ :param dict [params]: extra parameters specific to the exchange API endpoint
550
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
551
+ """
552
+ await self.load_markets()
553
+ symbolsLength = len(symbols)
554
+ if symbolsLength == 0:
555
+ raise ArgumentsRequired(self.id + ' unWatchOrderBookForSymbols() requires a non-empty array of symbols')
556
+ symbols = self.market_symbols(symbols)
557
+ topics = []
558
+ messageHashes = []
559
+ for i in range(0, len(symbols)):
560
+ symbol = symbols[i]
561
+ marketId = self.market_id(symbol)
562
+ topics.append('symbol:' + marketId + ':depth:20:0.001')
563
+ messageHashes.append('orderbook:' + symbol)
564
+ return await self.un_watch_public(topics, messageHashes, params)
565
+
566
+ def handle_order_book(self, client: Client, message):
567
+ #
568
+ # {
569
+ # "topic": "symbol:SOL_USDC:depth:20:0.01",
570
+ # "event": "depth",
571
+ # "timestamp": 1731030695319,
572
+ # "data": {
573
+ # "symbol": "SOL_USDC",
574
+ # "timestamp": 1731030695319,
575
+ # "lastTradeTimestamp": 1731030275258,
576
+ # "level": "20",
577
+ # "slab": "0.01",
578
+ # "bids": [
579
+ # {
580
+ # "price": "198.27000000",
581
+ # "qty": "1.52"
582
+ # }
583
+ # ],
584
+ # "asks": [
585
+ # {
586
+ # "price": "198.44000000",
587
+ # "qty": "6.61"
588
+ # }
589
+ # ]
590
+ # }
591
+ # }
592
+ #
593
+ data = self.safe_dict(message, 'data', {})
594
+ marketId = self.safe_string(data, 'symbol')
595
+ market = self.market(marketId)
596
+ symbol = market['symbol']
597
+ timestamp = self.safe_integer(data, 'timestamp')
598
+ snapshot = self.parse_order_book(data, symbol, timestamp, 'bids', 'asks', 'price', 'qty')
599
+ if not (symbol in self.orderbooks):
600
+ ob = self.order_book(snapshot)
601
+ self.orderbooks[symbol] = ob
602
+ orderbook = self.orderbooks[symbol]
603
+ orderbook.reset(snapshot)
604
+ messageHash = 'orderbook:' + symbol
605
+ client.resolve(orderbook, messageHash)
606
+
607
+ async def keep_alive_listen_key(self, params={}):
608
+ listenKey = self.safe_string(self.options, 'listenKey')
609
+ if listenKey is None:
610
+ # A network error happened: we can't renew a listen key that does not exist.
611
+ return
612
+ try:
613
+ await self.v1PrivatePutApiUsersSocketListenKeysListenKey({'listenKey': listenKey}) # self.extend the expiry
614
+ except Exception as error:
615
+ url = self.urls['api']['ws']['private'] + '?listenKey=' + listenKey
616
+ client = self.client(url)
617
+ messageHashes = list(client.futures.keys())
618
+ for j in range(0, len(messageHashes)):
619
+ messageHash = messageHashes[j]
620
+ client.reject(error, messageHash)
621
+ self.options['listenKey'] = None
622
+ self.options['lastAuthenticatedTime'] = 0
623
+ return
624
+ # whether or not to schedule another listenKey keepAlive request
625
+ listenKeyRefreshRate = self.safe_integer(self.options, 'listenKeyRefreshRate', 3540000)
626
+ self.delay(listenKeyRefreshRate, self.keep_alive_listen_key, params)
627
+
628
+ async def authenticate(self, params={}):
629
+ time = self.milliseconds()
630
+ lastAuthenticatedTime = self.safe_integer(self.options, 'lastAuthenticatedTime', 0)
631
+ listenKeyRefreshRate = self.safe_integer(self.options, 'listenKeyRefreshRate', 3540000) # 1 hour
632
+ if time - lastAuthenticatedTime > listenKeyRefreshRate:
633
+ response = await self.v1PrivatePostApiUsersSocketListenKeys()
634
+ self.options['listenKey'] = self.safe_string(response, 'listenKey')
635
+ self.options['lastAuthenticatedTime'] = time
636
+ self.delay(listenKeyRefreshRate, self.keep_alive_listen_key, params)
637
+
638
+ async def watch_balance(self, params={}) -> Balances:
639
+ """
640
+ query for balance and get the amount of funds available for trading or funds locked in orders
641
+
642
+ https://www.postman.com/defxcode/defx-public-apis/ws-raw-request/667939b2f00f79161bb47809
643
+
644
+ :param dict [params]: extra parameters specific to the exchange API endpoint
645
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
646
+ """
647
+ await self.load_markets()
648
+ await self.authenticate()
649
+ baseUrl = self.urls['api']['ws']['private']
650
+ messageHash = 'WALLET_BALANCE_UPDATE'
651
+ url = baseUrl + '?listenKey=' + self.options['listenKey']
652
+ return await self.watch(url, messageHash, None, messageHash)
653
+
654
+ def handle_balance(self, client: Client, message):
655
+ #
656
+ # {
657
+ # "event": "WALLET_BALANCE_UPDATE",
658
+ # "timestamp": 1711015961397,
659
+ # "data": {
660
+ # "asset": "USDC", "balance": "27.64712963"
661
+ # }
662
+ # }
663
+ #
664
+ messageHash = self.safe_string(message, 'event')
665
+ data = self.safe_dict(message, 'data', [])
666
+ timestamp = self.safe_integer(message, 'timestamp')
667
+ if self.balance is None:
668
+ self.balance = {}
669
+ self.balance['info'] = data
670
+ self.balance['timestamp'] = timestamp
671
+ self.balance['datetime'] = self.iso8601(timestamp)
672
+ currencyId = self.safe_string(data, 'asset')
673
+ code = self.safe_currency_code(currencyId)
674
+ account = self.balance[code] if (code in self.balance) else self.account()
675
+ account['free'] = self.safe_string(data, 'balance')
676
+ self.balance[code] = account
677
+ self.balance = self.safe_balance(self.balance)
678
+ client.resolve(self.balance, messageHash)
679
+
680
+ async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
681
+ """
682
+ watches information on multiple orders made by the user
683
+
684
+ https://www.postman.com/defxcode/defx-public-apis/ws-raw-request/667939b2f00f79161bb47809
685
+
686
+ :param str [symbol]: unified market symbol of the market the orders were made in
687
+ :param int [since]: the earliest time in ms to fetch orders for
688
+ :param int [limit]: the maximum number of order structures to retrieve
689
+ :param dict [params]: extra parameters specific to the exchange API endpoint
690
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
691
+ """
692
+ await self.load_markets()
693
+ await self.authenticate()
694
+ baseUrl = self.urls['api']['ws']['private']
695
+ messageHash = 'orders'
696
+ if symbol is not None:
697
+ market = self.market(symbol)
698
+ messageHash += ':' + market['symbol']
699
+ url = baseUrl + '?listenKey=' + self.options['listenKey']
700
+ orders = await self.watch(url, messageHash, None, messageHash)
701
+ if self.newUpdates:
702
+ limit = orders.getLimit(symbol, limit)
703
+ return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
704
+
705
+ def handle_order(self, client: Client, message):
706
+ #
707
+ # {
708
+ # "event": "ORDER_UPDATE",
709
+ # "timestamp": 1731417961446,
710
+ # "data": {
711
+ # "orderId": "766738557656630928",
712
+ # "symbol": "SOL_USDC",
713
+ # "side": "SELL",
714
+ # "type": "MARKET",
715
+ # "status": "FILLED",
716
+ # "clientOrderId": "0193208d-717b-7811-a80e-c036e220ad9b",
717
+ # "reduceOnly": False,
718
+ # "postOnly": False,
719
+ # "timeInForce": "GTC",
720
+ # "isTriggered": False,
721
+ # "createdAt": "2024-11-12T13:26:00.829Z",
722
+ # "updatedAt": "2024-11-12T13:26:01.436Z",
723
+ # "avgPrice": "209.60000000",
724
+ # "cumulativeQuote": "104.80000000",
725
+ # "totalFee": "0.05764000",
726
+ # "executedQty": "0.50",
727
+ # "origQty": "0.50",
728
+ # "role": "TAKER",
729
+ # "pnl": "0.00000000",
730
+ # "lastFillPnL": "0.00000000",
731
+ # "lastFillPrice": "209.60000000",
732
+ # "lastFillQty": "0.50",
733
+ # "linkedOrderParentType": null,
734
+ # "workingType": null
735
+ # }
736
+ # }
737
+ #
738
+ channel = 'orders'
739
+ data = self.safe_dict(message, 'data', {})
740
+ if self.orders is None:
741
+ limit = self.safe_integer(self.options, 'ordersLimit', 1000)
742
+ self.orders = ArrayCacheBySymbolById(limit)
743
+ orders = self.orders
744
+ parsedOrder = self.parse_order(data)
745
+ orders.append(parsedOrder)
746
+ messageHash = channel + ':' + parsedOrder['symbol']
747
+ client.resolve(orders, channel)
748
+ client.resolve(orders, messageHash)
749
+
750
+ async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
751
+ """
752
+ watch all open positions
753
+
754
+ https://www.postman.com/defxcode/defx-public-apis/ws-raw-request/667939b2f00f79161bb47809
755
+
756
+ :param str[]|None symbols: list of unified market symbols
757
+ :param number [since]: since timestamp
758
+ :param number [limit]: limit
759
+ :param dict params: extra parameters specific to the exchange API endpoint
760
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
761
+ """
762
+ await self.load_markets()
763
+ await self.authenticate()
764
+ symbols = self.market_symbols(symbols)
765
+ baseUrl = self.urls['api']['ws']['private']
766
+ channel = 'positions'
767
+ url = baseUrl + '?listenKey=' + self.options['listenKey']
768
+ newPosition = None
769
+ if symbols is not None:
770
+ messageHashes = []
771
+ for i in range(0, len(symbols)):
772
+ symbol = symbols[i]
773
+ messageHashes.append(channel + ':' + symbol)
774
+ newPosition = await self.watch_multiple(url, messageHashes, None, messageHashes)
775
+ else:
776
+ newPosition = await self.watch(url, channel, None, channel)
777
+ if self.newUpdates:
778
+ return newPosition
779
+ return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True)
780
+
781
+ def handle_positions(self, client, message):
782
+ #
783
+ # {
784
+ # "event": "POSITION_UPDATE",
785
+ # "timestamp": 1731417961456,
786
+ # "data": {
787
+ # "positionId": "0193208d-735d-7fe9-90bd-8bc6d6bc1eda",
788
+ # "createdAt": 1289847904328,
789
+ # "symbol": "SOL_USDC",
790
+ # "positionSide": "SHORT",
791
+ # "entryPrice": "209.60000000",
792
+ # "quantity": "0.50",
793
+ # "status": "ACTIVE",
794
+ # "marginAsset": "USDC",
795
+ # "marginAmount": "15.17475649",
796
+ # "realizedPnL": "0.00000000"
797
+ # }
798
+ # }
799
+ #
800
+ channel = 'positions'
801
+ data = self.safe_dict(message, 'data', {})
802
+ if self.positions is None:
803
+ self.positions = ArrayCacheBySymbolById()
804
+ cache = self.positions
805
+ parsedPosition = self.parse_position(data)
806
+ timestamp = self.safe_integer(message, 'timestamp')
807
+ parsedPosition['timestamp'] = timestamp
808
+ parsedPosition['datetime'] = self.iso8601(timestamp)
809
+ cache.append(parsedPosition)
810
+ messageHash = channel + ':' + parsedPosition['symbol']
811
+ client.resolve([parsedPosition], channel)
812
+ client.resolve([parsedPosition], messageHash)
813
+
814
+ def handle_message(self, client: Client, message):
815
+ error = self.safe_string(message, 'code')
816
+ if error is not None:
817
+ errorMsg = self.safe_string(message, 'msg')
818
+ raise ExchangeError(self.id + ' ' + errorMsg)
819
+ event = self.safe_string(message, 'event')
820
+ if event is not None:
821
+ methods: dict = {
822
+ 'ohlc': self.handle_ohlcv,
823
+ '24hrTicker': self.handle_ticker,
824
+ 'trades': self.handle_trades,
825
+ 'depth': self.handle_order_book,
826
+ 'WALLET_BALANCE_UPDATE': self.handle_balance,
827
+ 'ORDER_UPDATE': self.handle_order,
828
+ 'POSITION_UPDATE': self.handle_positions,
829
+ }
830
+ exacMethod = self.safe_value(methods, event)
831
+ if exacMethod is not None:
832
+ exacMethod(client, message)