ccxt 4.4.2__py2.py3-none-any.whl → 4.4.4__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 (87) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bitmart.py +1 -0
  3. ccxt/async_support/__init__.py +1 -1
  4. ccxt/async_support/base/exchange.py +24 -13
  5. ccxt/async_support/base/ws/cache.py +1 -0
  6. ccxt/async_support/binance.py +50 -25
  7. ccxt/async_support/bingx.py +1 -0
  8. ccxt/async_support/bitfinex2.py +10 -9
  9. ccxt/async_support/bitget.py +13 -9
  10. ccxt/async_support/bitmart.py +3 -1
  11. ccxt/async_support/bitmex.py +14 -13
  12. ccxt/async_support/bitso.py +8 -7
  13. ccxt/async_support/bitstamp.py +36 -48
  14. ccxt/async_support/blofin.py +24 -26
  15. ccxt/async_support/bybit.py +26 -23
  16. ccxt/async_support/coinbase.py +31 -10
  17. ccxt/async_support/coinbaseexchange.py +14 -14
  18. ccxt/async_support/coinlist.py +9 -8
  19. ccxt/async_support/coinmetro.py +6 -6
  20. ccxt/async_support/cryptocom.py +12 -9
  21. ccxt/async_support/currencycom.py +9 -9
  22. ccxt/async_support/delta.py +8 -8
  23. ccxt/async_support/digifinex.py +11 -9
  24. ccxt/async_support/gate.py +9 -8
  25. ccxt/async_support/hashkey.py +12 -10
  26. ccxt/async_support/htx.py +16 -19
  27. ccxt/async_support/hyperliquid.py +70 -117
  28. ccxt/async_support/kraken.py +12 -10
  29. ccxt/async_support/kucoin.py +12 -11
  30. ccxt/async_support/luno.py +13 -12
  31. ccxt/async_support/mexc.py +49 -2
  32. ccxt/async_support/ndax.py +9 -8
  33. ccxt/async_support/okcoin.py +21 -30
  34. ccxt/async_support/okx.py +21 -29
  35. ccxt/async_support/woo.py +10 -9
  36. ccxt/async_support/woofipro.py +11 -9
  37. ccxt/async_support/xt.py +12 -7
  38. ccxt/async_support/zonda.py +9 -8
  39. ccxt/base/exchange.py +3 -1
  40. ccxt/binance.py +50 -25
  41. ccxt/bingx.py +1 -0
  42. ccxt/bitfinex2.py +10 -9
  43. ccxt/bitget.py +13 -9
  44. ccxt/bitmart.py +3 -1
  45. ccxt/bitmex.py +14 -13
  46. ccxt/bitso.py +8 -7
  47. ccxt/bitstamp.py +36 -48
  48. ccxt/blofin.py +24 -26
  49. ccxt/bybit.py +26 -23
  50. ccxt/coinbase.py +31 -10
  51. ccxt/coinbaseexchange.py +14 -14
  52. ccxt/coinlist.py +9 -8
  53. ccxt/coinmetro.py +6 -6
  54. ccxt/cryptocom.py +12 -9
  55. ccxt/currencycom.py +9 -9
  56. ccxt/delta.py +8 -8
  57. ccxt/digifinex.py +11 -9
  58. ccxt/gate.py +9 -8
  59. ccxt/hashkey.py +12 -10
  60. ccxt/htx.py +16 -19
  61. ccxt/hyperliquid.py +70 -117
  62. ccxt/kraken.py +12 -10
  63. ccxt/kucoin.py +12 -11
  64. ccxt/luno.py +13 -12
  65. ccxt/mexc.py +48 -2
  66. ccxt/ndax.py +9 -8
  67. ccxt/okcoin.py +21 -30
  68. ccxt/okx.py +21 -29
  69. ccxt/pro/__init__.py +1 -1
  70. ccxt/pro/bybit.py +51 -0
  71. ccxt/pro/cryptocom.py +181 -22
  72. ccxt/pro/mexc.py +154 -4
  73. ccxt/pro/okx.py +5 -3
  74. ccxt/pro/oxfun.py +70 -0
  75. ccxt/pro/phemex.py +41 -2
  76. ccxt/pro/woofipro.py +64 -0
  77. ccxt/test/tests_async.py +1 -1
  78. ccxt/test/tests_sync.py +1 -1
  79. ccxt/woo.py +10 -9
  80. ccxt/woofipro.py +11 -9
  81. ccxt/xt.py +12 -7
  82. ccxt/zonda.py +9 -8
  83. {ccxt-4.4.2.dist-info → ccxt-4.4.4.dist-info}/METADATA +5 -5
  84. {ccxt-4.4.2.dist-info → ccxt-4.4.4.dist-info}/RECORD +87 -87
  85. {ccxt-4.4.2.dist-info → ccxt-4.4.4.dist-info}/LICENSE.txt +0 -0
  86. {ccxt-4.4.2.dist-info → ccxt-4.4.4.dist-info}/WHEEL +0 -0
  87. {ccxt-4.4.2.dist-info → ccxt-4.4.4.dist-info}/top_level.txt +0 -0
ccxt/pro/cryptocom.py CHANGED
@@ -6,7 +6,7 @@
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Int, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Trade
9
+ from ccxt.base.types import Balances, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from typing import Any
@@ -24,7 +24,8 @@ class cryptocom(ccxt.async_support.cryptocom):
24
24
  'ws': True,
25
25
  'watchBalance': True,
26
26
  'watchTicker': True,
27
- 'watchTickers': False,
27
+ 'watchTickers': True,
28
+ 'watchBidsAsks': True,
28
29
  'watchMyTrades': True,
29
30
  'watchTrades': True,
30
31
  'watchTradesForSymbols': True,
@@ -443,40 +444,198 @@ class cryptocom(ccxt.async_support.cryptocom):
443
444
  messageHash = 'unsubscribe:ticker:' + market['symbol']
444
445
  return await self.un_watch_public_multiple('ticker', [market['symbol']], [messageHash], [subMessageHash], [subMessageHash], params)
445
446
 
447
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
448
+ """
449
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
450
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#ticker-instrument_name
451
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
452
+ :param dict [params]: extra parameters specific to the exchange API endpoint
453
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
454
+ """
455
+ await self.load_markets()
456
+ symbols = self.market_symbols(symbols, None, False)
457
+ messageHashes = []
458
+ marketIds = self.market_ids(symbols)
459
+ for i in range(0, len(marketIds)):
460
+ marketId = marketIds[i]
461
+ messageHashes.append('ticker.' + marketId)
462
+ url = self.urls['api']['ws']['public']
463
+ id = self.nonce()
464
+ request: dict = {
465
+ 'method': 'subscribe',
466
+ 'params': {
467
+ 'channels': messageHashes,
468
+ },
469
+ 'nonce': id,
470
+ }
471
+ ticker = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
472
+ if self.newUpdates:
473
+ result: dict = {}
474
+ result[ticker['symbol']] = ticker
475
+ return result
476
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
477
+
478
+ async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any:
479
+ """
480
+ unWatches a price ticker
481
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#ticker-instrument_name
482
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
483
+ :param dict [params]: extra parameters specific to the exchange API endpoint
484
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
485
+ """
486
+ await self.load_markets()
487
+ symbols = self.market_symbols(symbols, None, False)
488
+ messageHashes = []
489
+ subMessageHashes = []
490
+ marketIds = self.market_ids(symbols)
491
+ for i in range(0, len(marketIds)):
492
+ marketId = marketIds[i]
493
+ symbol = symbols[i]
494
+ subMessageHashes.append('ticker.' + marketId)
495
+ messageHashes.append('unsubscribe:ticker:' + symbol)
496
+ return await self.un_watch_public_multiple('ticker', symbols, messageHashes, subMessageHashes, subMessageHashes, params)
497
+
446
498
  def handle_ticker(self, client: Client, message):
447
499
  #
448
- # {
449
- # "info":{
450
- # "instrument_name":"BTC_USDT",
451
- # "subscription":"ticker.BTC_USDT",
452
- # "channel":"ticker",
453
- # "data":[
454
- # {
455
- # "i":"BTC_USDT",
456
- # "b":43063.19,
457
- # "k":43063.2,
458
- # "a":43063.19,
459
- # "t":1648121165658,
460
- # "v":43573.912409,
461
- # "h":43498.51,
462
- # "l":41876.58,
463
- # "c":1087.43
464
- # }
465
- # ]
500
+ # {
501
+ # "instrument_name": "ETHUSD-PERP",
502
+ # "subscription": "ticker.ETHUSD-PERP",
503
+ # "channel": "ticker",
504
+ # "data": [
505
+ # {
506
+ # "h": "2400.20",
507
+ # "l": "2277.10",
508
+ # "a": "2335.25",
509
+ # "c": "-0.0022",
510
+ # "b": "2335.10",
511
+ # "bs": "5.4000",
512
+ # "k": "2335.16",
513
+ # "ks": "1.9970",
514
+ # "i": "ETHUSD-PERP",
515
+ # "v": "1305697.6462",
516
+ # "vv": "3058704939.17",
517
+ # "oi": "161646.3614",
518
+ # "t": 1726069647560
519
+ # }
520
+ # ]
466
521
  # }
467
- # }
468
522
  #
523
+ self.handle_bid_ask(client, message)
469
524
  messageHash = self.safe_string(message, 'subscription')
470
525
  marketId = self.safe_string(message, 'instrument_name')
471
526
  market = self.safe_market(marketId)
472
527
  data = self.safe_value(message, 'data', [])
473
528
  for i in range(0, len(data)):
474
529
  ticker = data[i]
475
- parsed = self.parse_ticker(ticker, market)
530
+ parsed = self.parse_ws_ticker(ticker, market)
476
531
  symbol = parsed['symbol']
477
532
  self.tickers[symbol] = parsed
478
533
  client.resolve(parsed, messageHash)
479
534
 
535
+ def parse_ws_ticker(self, ticker: dict, market: Market = None) -> Ticker:
536
+ #
537
+ # {
538
+ # "h": "2400.20",
539
+ # "l": "2277.10",
540
+ # "a": "2335.25",
541
+ # "c": "-0.0022",
542
+ # "b": "2335.10",
543
+ # "bs": "5.4000",
544
+ # "k": "2335.16",
545
+ # "ks": "1.9970",
546
+ # "i": "ETHUSD-PERP",
547
+ # "v": "1305697.6462",
548
+ # "vv": "3058704939.17",
549
+ # "oi": "161646.3614",
550
+ # "t": 1726069647560
551
+ # }
552
+ #
553
+ timestamp = self.safe_integer(ticker, 't')
554
+ marketId = self.safe_string(ticker, 'i')
555
+ market = self.safe_market(marketId, market, '_')
556
+ quote = self.safe_string(market, 'quote')
557
+ last = self.safe_string(ticker, 'a')
558
+ return self.safe_ticker({
559
+ 'symbol': market['symbol'],
560
+ 'timestamp': timestamp,
561
+ 'datetime': self.iso8601(timestamp),
562
+ 'high': self.safe_number(ticker, 'h'),
563
+ 'low': self.safe_number(ticker, 'l'),
564
+ 'bid': self.safe_number(ticker, 'b'),
565
+ 'bidVolume': self.safe_number(ticker, 'bs'),
566
+ 'ask': self.safe_number(ticker, 'k'),
567
+ 'askVolume': self.safe_number(ticker, 'ks'),
568
+ 'vwap': None,
569
+ 'open': None,
570
+ 'close': last,
571
+ 'last': last,
572
+ 'previousClose': None,
573
+ 'change': None,
574
+ 'percentage': self.safe_string(ticker, 'c'),
575
+ 'average': None,
576
+ 'baseVolume': self.safe_string(ticker, 'v'),
577
+ 'quoteVolume': self.safe_string(ticker, 'vv') if (quote == 'USD') else None,
578
+ 'info': ticker,
579
+ }, market)
580
+
581
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
582
+ """
583
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#ticker-instrument_name
584
+ watches best bid & ask for symbols
585
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
586
+ :param dict [params]: extra parameters specific to the exchange API endpoint
587
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
588
+ """
589
+ await self.load_markets()
590
+ symbols = self.market_symbols(symbols, None, False)
591
+ messageHashes = []
592
+ topics = []
593
+ marketIds = self.market_ids(symbols)
594
+ for i in range(0, len(marketIds)):
595
+ marketId = marketIds[i]
596
+ messageHashes.append('bidask.' + symbols[i])
597
+ topics.append('ticker.' + marketId)
598
+ url = self.urls['api']['ws']['public']
599
+ id = self.nonce()
600
+ request: dict = {
601
+ 'method': 'subscribe',
602
+ 'params': {
603
+ 'channels': topics,
604
+ },
605
+ 'nonce': id,
606
+ }
607
+ newTickers = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
608
+ if self.newUpdates:
609
+ tickers: dict = {}
610
+ tickers[newTickers['symbol']] = newTickers
611
+ return tickers
612
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
613
+
614
+ def handle_bid_ask(self, client: Client, message):
615
+ data = self.safe_list(message, 'data', [])
616
+ ticker = self.safe_dict(data, 0, {})
617
+ parsedTicker = self.parse_ws_bid_ask(ticker)
618
+ symbol = parsedTicker['symbol']
619
+ self.bidsasks[symbol] = parsedTicker
620
+ messageHash = 'bidask.' + symbol
621
+ client.resolve(parsedTicker, messageHash)
622
+
623
+ def parse_ws_bid_ask(self, ticker, market=None):
624
+ marketId = self.safe_string(ticker, 'i')
625
+ market = self.safe_market(marketId, market)
626
+ symbol = self.safe_string(market, 'symbol')
627
+ timestamp = self.safe_integer(ticker, 't')
628
+ return self.safe_ticker({
629
+ 'symbol': symbol,
630
+ 'timestamp': timestamp,
631
+ 'datetime': self.iso8601(timestamp),
632
+ 'ask': self.safe_string(ticker, 'k'),
633
+ 'askVolume': self.safe_string(ticker, 'ks'),
634
+ 'bid': self.safe_string(ticker, 'b'),
635
+ 'bidVolume': self.safe_string(ticker, 'bs'),
636
+ 'info': ticker,
637
+ }, market)
638
+
480
639
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
481
640
  """
482
641
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
ccxt/pro/mexc.py CHANGED
@@ -6,10 +6,12 @@
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
9
+ from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import AuthenticationError
13
+ from ccxt.base.errors import ArgumentsRequired
14
+ from ccxt.base.errors import NotSupported
13
15
 
14
16
 
15
17
  class mexc(ccxt.async_support.mexc):
@@ -33,7 +35,8 @@ class mexc(ccxt.async_support.mexc):
33
35
  'watchOrderBook': True,
34
36
  'watchOrders': True,
35
37
  'watchTicker': True,
36
- 'watchTickers': False,
38
+ 'watchTickers': True,
39
+ 'watchBidsAsks': True,
37
40
  'watchTrades': True,
38
41
  'watchTradesForSymbols': False,
39
42
  },
@@ -110,6 +113,7 @@ class mexc(ccxt.async_support.mexc):
110
113
  # "t": 1678643605721
111
114
  # }
112
115
  #
116
+ self.handle_bid_ask(client, message)
113
117
  rawTicker = self.safe_value_2(message, 'd', 'data')
114
118
  marketId = self.safe_string_2(message, 's', 'symbol')
115
119
  timestamp = self.safe_integer(message, 't')
@@ -126,6 +130,77 @@ class mexc(ccxt.async_support.mexc):
126
130
  messageHash = 'ticker:' + symbol
127
131
  client.resolve(ticker, messageHash)
128
132
 
133
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
134
+ """
135
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
136
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#individual-symbol-book-ticker-streams
137
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
138
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
139
+ :param dict [params]: extra parameters specific to the exchange API endpoint
140
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
141
+ """
142
+ await self.load_markets()
143
+ symbols = self.market_symbols(symbols, None, False)
144
+ messageHashes = []
145
+ marketIds = self.market_ids(symbols)
146
+ firstMarket = self.market(symbols[0])
147
+ isSpot = firstMarket['spot']
148
+ url = self.urls['api']['ws']['spot'] if (isSpot) else self.urls['api']['ws']['swap']
149
+ request: dict = {}
150
+ if isSpot:
151
+ topics = []
152
+ for i in range(0, len(marketIds)):
153
+ marketId = marketIds[i]
154
+ messageHashes.append('ticker:' + symbols[i])
155
+ topics.append('spot@public.bookTicker.v3.api@' + marketId)
156
+ request['method'] = 'SUBSCRIPTION'
157
+ request['params'] = topics
158
+ else:
159
+ request['method'] = 'sub.tickers'
160
+ request['params'] = {}
161
+ messageHashes.append('ticker')
162
+ ticker = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
163
+ if isSpot and self.newUpdates:
164
+ result: dict = {}
165
+ result[ticker['symbol']] = ticker
166
+ return result
167
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
168
+
169
+ def handle_tickers(self, client: Client, message):
170
+ #
171
+ # {
172
+ # "channel": "push.tickers",
173
+ # "data": [
174
+ # {
175
+ # "symbol": "ETH_USDT",
176
+ # "lastPrice": 2324.5,
177
+ # "riseFallRate": 0.0356,
178
+ # "fairPrice": 2324.32,
179
+ # "indexPrice": 2325.44,
180
+ # "volume24": 25868309,
181
+ # "amount24": 591752573.9792,
182
+ # "maxBidPrice": 2557.98,
183
+ # "minAskPrice": 2092.89,
184
+ # "lower24Price": 2239.39,
185
+ # "high24Price": 2332.59,
186
+ # "timestamp": 1725872514111
187
+ # }
188
+ # ],
189
+ # "ts": 1725872514111
190
+ # }
191
+ #
192
+ data = self.safe_list(message, 'data')
193
+ topic = 'ticker'
194
+ result = []
195
+ for i in range(0, len(data)):
196
+ ticker = self.parse_ticker(data[i])
197
+ symbol = ticker['symbol']
198
+ self.tickers[symbol] = ticker
199
+ result.append(ticker)
200
+ messageHash = topic + ':' + symbol
201
+ client.resolve(ticker, messageHash)
202
+ client.resolve(result, topic)
203
+
129
204
  def parse_ws_ticker(self, ticker, market=None):
130
205
  #
131
206
  # spot
@@ -158,6 +233,80 @@ class mexc(ccxt.async_support.mexc):
158
233
  'info': ticker,
159
234
  }, market)
160
235
 
236
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
237
+ """
238
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#individual-symbol-book-ticker-streams
239
+ watches best bid & ask for symbols
240
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
241
+ :param dict [params]: extra parameters specific to the exchange API endpoint
242
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
243
+ """
244
+ await self.load_markets()
245
+ symbols = self.market_symbols(symbols, None, True, False, True)
246
+ marketType = None
247
+ if symbols is None:
248
+ raise ArgumentsRequired(self.id + 'watchBidsAsks required symbols argument')
249
+ markets = self.markets_for_symbols(symbols)
250
+ marketType, params = self.handle_market_type_and_params('watchBidsAsks', markets[0], params)
251
+ isSpot = marketType == 'spot'
252
+ if not isSpot:
253
+ raise NotSupported(self.id + 'watchBidsAsks only support spot market')
254
+ messageHashes = []
255
+ topics = []
256
+ for i in range(0, len(symbols)):
257
+ if isSpot:
258
+ market = self.market(symbols[i])
259
+ topics.append('spot@public.bookTicker.v3.api@' + market['id'])
260
+ messageHashes.append('bidask:' + symbols[i])
261
+ url = self.urls['api']['ws']['spot']
262
+ request: dict = {
263
+ 'method': 'SUBSCRIPTION',
264
+ 'params': topics,
265
+ }
266
+ ticker = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
267
+ if self.newUpdates:
268
+ tickers: dict = {}
269
+ tickers[ticker['symbol']] = ticker
270
+ return tickers
271
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
272
+
273
+ def handle_bid_ask(self, client: Client, message):
274
+ #
275
+ # {
276
+ # "c": "spot@public.bookTicker.v3.api@BTCUSDT",
277
+ # "d": {
278
+ # "A": "4.70432",
279
+ # "B": "6.714863",
280
+ # "a": "20744.54",
281
+ # "b": "20744.17"
282
+ # },
283
+ # "s": "BTCUSDT",
284
+ # "t": 1678643605721
285
+ # }
286
+ #
287
+ parsedTicker = self.parse_ws_bid_ask(message)
288
+ symbol = parsedTicker['symbol']
289
+ self.bidsasks[symbol] = parsedTicker
290
+ messageHash = 'bidask:' + symbol
291
+ client.resolve(parsedTicker, messageHash)
292
+
293
+ def parse_ws_bid_ask(self, ticker, market=None):
294
+ data = self.safe_dict(ticker, 'd')
295
+ marketId = self.safe_string(ticker, 's')
296
+ market = self.safe_market(marketId, market)
297
+ symbol = self.safe_string(market, 'symbol')
298
+ timestamp = self.safe_integer(ticker, 't')
299
+ return self.safe_ticker({
300
+ 'symbol': symbol,
301
+ 'timestamp': timestamp,
302
+ 'datetime': self.iso8601(timestamp),
303
+ 'ask': self.safe_number(data, 'a'),
304
+ 'askVolume': self.safe_number(data, 'A'),
305
+ 'bid': self.safe_number(data, 'b'),
306
+ 'bidVolume': self.safe_number(data, 'B'),
307
+ 'info': ticker,
308
+ }, market)
309
+
161
310
  async def watch_spot_public(self, channel, messageHash, params={}):
162
311
  url = self.urls['api']['ws']['spot']
163
312
  request: dict = {
@@ -1073,8 +1222,8 @@ class mexc(ccxt.async_support.mexc):
1073
1222
  # "code": 0,
1074
1223
  # "msg": "spot@public.increase.depth.v3.api@BTCUSDT"
1075
1224
  # }
1076
- #
1077
- msg = self.safe_string(message, 'msg')
1225
+ # Set the default to an empty string if the message is empty during the test.
1226
+ msg = self.safe_string(message, 'msg', '')
1078
1227
  if msg == 'PONG':
1079
1228
  self.handle_pong(client, message)
1080
1229
  elif msg.find('@') > -1:
@@ -1110,6 +1259,7 @@ class mexc(ccxt.async_support.mexc):
1110
1259
  'push.kline': self.handle_ohlcv,
1111
1260
  'public.bookTicker.v3.api': self.handle_ticker,
1112
1261
  'push.ticker': self.handle_ticker,
1262
+ 'push.tickers': self.handle_tickers,
1113
1263
  'public.increase.depth.v3.api': self.handle_order_book,
1114
1264
  'push.depth': self.handle_order_book,
1115
1265
  'private.orders.v3.api': self.handle_order,
ccxt/pro/okx.py CHANGED
@@ -1340,8 +1340,10 @@ class okx(ccxt.async_support.okx):
1340
1340
  },
1341
1341
  ],
1342
1342
  }
1343
- message = self.extend(request, params)
1344
- self.watch(url, messageHash, message, messageHash)
1343
+ # Only add params['access'] to prevent sending custom parameters, such.
1344
+ if 'access' in params:
1345
+ request['access'] = params['access']
1346
+ self.watch(url, messageHash, request, messageHash)
1345
1347
  return await future
1346
1348
 
1347
1349
  async def watch_balance(self, params={}) -> Balances:
@@ -1499,7 +1501,7 @@ class okx(ccxt.async_support.okx):
1499
1501
  'channel': 'positions',
1500
1502
  'instType': 'ANY',
1501
1503
  }
1502
- args = [arg]
1504
+ args = [self.extend(arg, params)]
1503
1505
  nonSymbolRequest: dict = {
1504
1506
  'op': 'subscribe',
1505
1507
  'args': args,
ccxt/pro/oxfun.py CHANGED
@@ -30,6 +30,7 @@ class oxfun(ccxt.async_support.oxfun):
30
30
  'watchMyTrades': False,
31
31
  'watchTicker': True,
32
32
  'watchTickers': True,
33
+ 'watchBidsAsks': True,
33
34
  'watchBalance': True,
34
35
  'createOrderWs': True,
35
36
  'editOrderWs': True,
@@ -466,6 +467,73 @@ class oxfun(ccxt.async_support.oxfun):
466
467
  self.tickers[symbol] = ticker
467
468
  client.resolve(ticker, messageHash)
468
469
 
470
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
471
+ """
472
+ :see: https://docs.ox.fun/?json#best-bid-ask
473
+ watches best bid & ask for symbols
474
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
475
+ :param dict [params]: extra parameters specific to the exchange API endpoint
476
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
477
+ """
478
+ await self.load_markets()
479
+ symbols = self.market_symbols(symbols, None, False)
480
+ messageHashes = []
481
+ args = []
482
+ for i in range(0, len(symbols)):
483
+ market = self.market(symbols[i])
484
+ args.append('bestBidAsk:' + market['id'])
485
+ messageHashes.append('bidask:' + market['symbol'])
486
+ newTickers = await self.subscribe_multiple(messageHashes, args, params)
487
+ if self.newUpdates:
488
+ tickers: dict = {}
489
+ tickers[newTickers['symbol']] = newTickers
490
+ return tickers
491
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
492
+
493
+ def handle_bid_ask(self, client: Client, message):
494
+ #
495
+ # {
496
+ # "table": "bestBidAsk",
497
+ # "data": {
498
+ # "ask": [
499
+ # 19045.0,
500
+ # 1.0
501
+ # ],
502
+ # "checksum": 3790706311,
503
+ # "marketCode": "BTC-USD-SWAP-LIN",
504
+ # "bid": [
505
+ # 19015.0,
506
+ # 1.0
507
+ # ],
508
+ # "timestamp": "1665456882928"
509
+ # }
510
+ # }
511
+ #
512
+ data = self.safe_dict(message, 'data', {})
513
+ parsedTicker = self.parse_ws_bid_ask(data)
514
+ symbol = parsedTicker['symbol']
515
+ self.bidsasks[symbol] = parsedTicker
516
+ messageHash = 'bidask:' + symbol
517
+ client.resolve(parsedTicker, messageHash)
518
+
519
+ def parse_ws_bid_ask(self, ticker, market=None):
520
+ marketId = self.safe_string(ticker, 'marketCode')
521
+ market = self.safe_market(marketId, market)
522
+ symbol = self.safe_string(market, 'symbol')
523
+ timestamp = self.safe_integer(ticker, 'timestamp')
524
+ ask = self.safe_list(ticker, 'ask', [])
525
+ bid = self.safe_list(ticker, 'bid', [])
526
+ return self.safe_ticker({
527
+ 'symbol': symbol,
528
+ 'timestamp': timestamp,
529
+ 'datetime': self.iso8601(timestamp),
530
+ 'ask': self.safe_number(ask, 0),
531
+ 'askVolume': self.safe_number(ask, 1),
532
+ 'bid': self.safe_number(bid, 0),
533
+ 'bidVolume': self.safe_number(bid, 1),
534
+ 'info': ticker,
535
+ }, market)
536
+
469
537
  async def watch_balance(self, params={}) -> Balances:
470
538
  """
471
539
  :see: https://docs.ox.fun/?json#balance-channel
@@ -943,6 +1011,8 @@ class oxfun(ccxt.async_support.oxfun):
943
1011
  self.handle_positions(client, message)
944
1012
  if table.find('order') > -1:
945
1013
  self.handle_orders(client, message)
1014
+ if table == 'bestBidAsk':
1015
+ self.handle_bid_ask(client, message)
946
1016
  else:
947
1017
  if event == 'login':
948
1018
  self.handle_authentication_message(client, message)
ccxt/pro/phemex.py CHANGED
@@ -6,7 +6,7 @@
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
9
+ from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import AuthenticationError
@@ -20,7 +20,7 @@ class phemex(ccxt.async_support.phemex):
20
20
  'has': {
21
21
  'ws': True,
22
22
  'watchTicker': True,
23
- 'watchTickers': False, # for now
23
+ 'watchTickers': True,
24
24
  'watchTrades': True,
25
25
  'watchMyTrades': True,
26
26
  'watchOrders': True,
@@ -504,6 +504,45 @@ class phemex(ccxt.async_support.phemex):
504
504
  request = self.deep_extend(subscribe, params)
505
505
  return await self.watch(url, messageHash, request, subscriptionHash)
506
506
 
507
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
508
+ """
509
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-24-hours-ticker
510
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-24-hours-ticker
511
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-24-hours-ticker
512
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
513
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
514
+ :param dict [params]: extra parameters specific to the exchange API endpoint
515
+ :param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
516
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
517
+ """
518
+ await self.load_markets()
519
+ symbols = self.market_symbols(symbols, None, False)
520
+ first = symbols[0]
521
+ market = self.market(first)
522
+ isSwap = market['swap']
523
+ settleIsUSDT = market['settle'] == 'USDT'
524
+ name = 'spot_market24h'
525
+ if isSwap:
526
+ name = 'perp_market24h_pack_p' if settleIsUSDT else 'market24h'
527
+ url = self.urls['api']['ws']
528
+ requestId = self.request_id()
529
+ subscriptionHash = name + '.subscribe'
530
+ messageHashes = []
531
+ for i in range(0, len(symbols)):
532
+ messageHashes.append('ticker:' + symbols[i])
533
+ subscribe: dict = {
534
+ 'method': subscriptionHash,
535
+ 'id': requestId,
536
+ 'params': [],
537
+ }
538
+ request = self.deep_extend(subscribe, params)
539
+ ticker = await self.watch_multiple(url, messageHashes, request, messageHashes)
540
+ if self.newUpdates:
541
+ result: dict = {}
542
+ result[ticker['symbol']] = ticker
543
+ return result
544
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
545
+
507
546
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
508
547
  """
509
548
  :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-trade