ccxt 4.4.2__py2.py3-none-any.whl → 4.4.3__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ccxt/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,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
@@ -33,7 +33,7 @@ class mexc(ccxt.async_support.mexc):
33
33
  'watchOrderBook': True,
34
34
  'watchOrders': True,
35
35
  'watchTicker': True,
36
- 'watchTickers': False,
36
+ 'watchTickers': True,
37
37
  'watchTrades': True,
38
38
  'watchTradesForSymbols': False,
39
39
  },
@@ -126,6 +126,77 @@ class mexc(ccxt.async_support.mexc):
126
126
  messageHash = 'ticker:' + symbol
127
127
  client.resolve(ticker, messageHash)
128
128
 
129
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
130
+ """
131
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
132
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#individual-symbol-book-ticker-streams
133
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
134
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
135
+ :param dict [params]: extra parameters specific to the exchange API endpoint
136
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
137
+ """
138
+ await self.load_markets()
139
+ symbols = self.market_symbols(symbols, None, False)
140
+ messageHashes = []
141
+ marketIds = self.market_ids(symbols)
142
+ firstMarket = self.market(symbols[0])
143
+ isSpot = firstMarket['spot']
144
+ url = self.urls['api']['ws']['spot'] if (isSpot) else self.urls['api']['ws']['swap']
145
+ request: dict = {}
146
+ if isSpot:
147
+ topics = []
148
+ for i in range(0, len(marketIds)):
149
+ marketId = marketIds[i]
150
+ messageHashes.append('ticker:' + symbols[i])
151
+ topics.append('spot@public.bookTicker.v3.api@' + marketId)
152
+ request['method'] = 'SUBSCRIPTION'
153
+ request['params'] = topics
154
+ else:
155
+ request['method'] = 'sub.tickers'
156
+ request['params'] = {}
157
+ messageHashes.append('ticker')
158
+ ticker = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
159
+ if isSpot and self.newUpdates:
160
+ result: dict = {}
161
+ result[ticker['symbol']] = ticker
162
+ return result
163
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
164
+
165
+ def handle_tickers(self, client: Client, message):
166
+ #
167
+ # {
168
+ # "channel": "push.tickers",
169
+ # "data": [
170
+ # {
171
+ # "symbol": "ETH_USDT",
172
+ # "lastPrice": 2324.5,
173
+ # "riseFallRate": 0.0356,
174
+ # "fairPrice": 2324.32,
175
+ # "indexPrice": 2325.44,
176
+ # "volume24": 25868309,
177
+ # "amount24": 591752573.9792,
178
+ # "maxBidPrice": 2557.98,
179
+ # "minAskPrice": 2092.89,
180
+ # "lower24Price": 2239.39,
181
+ # "high24Price": 2332.59,
182
+ # "timestamp": 1725872514111
183
+ # }
184
+ # ],
185
+ # "ts": 1725872514111
186
+ # }
187
+ #
188
+ data = self.safe_list(message, 'data')
189
+ topic = 'ticker'
190
+ result = []
191
+ for i in range(0, len(data)):
192
+ ticker = self.parse_ticker(data[i])
193
+ symbol = ticker['symbol']
194
+ self.tickers[symbol] = ticker
195
+ result.append(ticker)
196
+ messageHash = topic + ':' + symbol
197
+ client.resolve(ticker, messageHash)
198
+ client.resolve(result, topic)
199
+
129
200
  def parse_ws_ticker(self, ticker, market=None):
130
201
  #
131
202
  # spot
@@ -1073,8 +1144,8 @@ class mexc(ccxt.async_support.mexc):
1073
1144
  # "code": 0,
1074
1145
  # "msg": "spot@public.increase.depth.v3.api@BTCUSDT"
1075
1146
  # }
1076
- #
1077
- msg = self.safe_string(message, 'msg')
1147
+ # Set the default to an empty string if the message is empty during the test.
1148
+ msg = self.safe_string(message, 'msg', '')
1078
1149
  if msg == 'PONG':
1079
1150
  self.handle_pong(client, message)
1080
1151
  elif msg.find('@') > -1:
@@ -1110,6 +1181,7 @@ class mexc(ccxt.async_support.mexc):
1110
1181
  'push.kline': self.handle_ohlcv,
1111
1182
  'public.bookTicker.v3.api': self.handle_ticker,
1112
1183
  'push.ticker': self.handle_ticker,
1184
+ 'push.tickers': self.handle_tickers,
1113
1185
  'public.increase.depth.v3.api': self.handle_order_book,
1114
1186
  'push.depth': self.handle_order_book,
1115
1187
  '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
ccxt/pro/woofipro.py CHANGED
@@ -26,6 +26,7 @@ class woofipro(ccxt.async_support.woofipro):
26
26
  'watchOrders': True,
27
27
  'watchTicker': True,
28
28
  'watchTickers': True,
29
+ 'watchBidsAsks': True,
29
30
  'watchTrades': True,
30
31
  'watchTradesForSymbols': False,
31
32
  'watchPositions': True,
@@ -284,6 +285,68 @@ class woofipro(ccxt.async_support.woofipro):
284
285
  result.append(ticker)
285
286
  client.resolve(result, topic)
286
287
 
288
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
289
+ """
290
+ :see: https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/bbos
291
+ watches best bid & ask for symbols
292
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
293
+ :param dict [params]: extra parameters specific to the exchange API endpoint
294
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
295
+ """
296
+ await self.load_markets()
297
+ symbols = self.market_symbols(symbols)
298
+ name = 'bbos'
299
+ topic = name
300
+ request: dict = {
301
+ 'event': 'subscribe',
302
+ 'topic': topic,
303
+ }
304
+ message = self.extend(request, params)
305
+ tickers = await self.watch_public(topic, message)
306
+ return self.filter_by_array(tickers, 'symbol', symbols)
307
+
308
+ def handle_bid_ask(self, client: Client, message):
309
+ #
310
+ # {
311
+ # "topic": "bbos",
312
+ # "ts": 1726212495000,
313
+ # "data": [
314
+ # {
315
+ # "symbol": "PERP_WOO_USDC",
316
+ # "ask": 0.16570,
317
+ # "askSize": 4224,
318
+ # "bid": 0.16553,
319
+ # "bidSize": 6645
320
+ # }
321
+ # ]
322
+ # }
323
+ #
324
+ topic = self.safe_string(message, 'topic')
325
+ data = self.safe_list(message, 'data', [])
326
+ timestamp = self.safe_integer(message, 'ts')
327
+ result = []
328
+ for i in range(0, len(data)):
329
+ ticker = self.parse_ws_bid_ask(self.extend(data[i], {'ts': timestamp}))
330
+ self.tickers[ticker['symbol']] = ticker
331
+ result.append(ticker)
332
+ client.resolve(result, topic)
333
+
334
+ def parse_ws_bid_ask(self, ticker, market=None):
335
+ marketId = self.safe_string(ticker, 'symbol')
336
+ market = self.safe_market(marketId, market)
337
+ symbol = self.safe_string(market, 'symbol')
338
+ timestamp = self.safe_integer(ticker, 'ts')
339
+ return self.safe_ticker({
340
+ 'symbol': symbol,
341
+ 'timestamp': timestamp,
342
+ 'datetime': self.iso8601(timestamp),
343
+ 'ask': self.safe_string(ticker, 'ask'),
344
+ 'askVolume': self.safe_string(ticker, 'askSize'),
345
+ 'bid': self.safe_string(ticker, 'bid'),
346
+ 'bidVolume': self.safe_string(ticker, 'bidSize'),
347
+ 'info': ticker,
348
+ }, market)
349
+
287
350
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
288
351
  """
289
352
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
@@ -1133,6 +1196,7 @@ class woofipro(ccxt.async_support.woofipro):
1133
1196
  'algoexecutionreport': self.handle_order_update,
1134
1197
  'position': self.handle_positions,
1135
1198
  'balance': self.handle_balance,
1199
+ 'bbos': self.handle_bid_ask,
1136
1200
  }
1137
1201
  event = self.safe_string(message, 'event')
1138
1202
  method = self.safe_value(methods, event)
ccxt/xt.py CHANGED
@@ -1137,17 +1137,21 @@ class xt(Exchange, ImplicitAPI):
1137
1137
  maxCost = None
1138
1138
  minPrice = None
1139
1139
  maxPrice = None
1140
+ amountPrecision = None
1140
1141
  for i in range(0, len(filters)):
1141
1142
  entry = filters[i]
1142
1143
  filter = self.safe_string(entry, 'filter')
1143
1144
  if filter == 'QUANTITY':
1144
1145
  minAmount = self.safe_number(entry, 'min')
1145
1146
  maxAmount = self.safe_number(entry, 'max')
1147
+ amountPrecision = self.safe_number(entry, 'tickSize')
1146
1148
  if filter == 'QUOTE_QTY':
1147
1149
  minCost = self.safe_number(entry, 'min')
1148
1150
  if filter == 'PRICE':
1149
1151
  minPrice = self.safe_number(entry, 'min')
1150
1152
  maxPrice = self.safe_number(entry, 'max')
1153
+ if amountPrecision is None:
1154
+ amountPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision')))
1151
1155
  underlyingType = self.safe_string(market, 'underlyingType')
1152
1156
  linear = None
1153
1157
  inverse = None
@@ -1222,7 +1226,7 @@ class xt(Exchange, ImplicitAPI):
1222
1226
  'optionType': None,
1223
1227
  'precision': {
1224
1228
  'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision'))),
1225
- 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision'))),
1229
+ 'amount': amountPrecision,
1226
1230
  'base': self.parse_number(self.parse_precision(self.safe_string(market, 'baseCoinPrecision'))),
1227
1231
  'quote': self.parse_number(self.parse_precision(self.safe_string(market, 'quoteCoinPrecision'))),
1228
1232
  },