ccxt 4.4.8__py2.py3-none-any.whl → 4.4.10__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 (89) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bigone.py +1 -1
  3. ccxt/abstract/kucoinfutures.py +5 -0
  4. ccxt/abstract/oceanex.py +5 -0
  5. ccxt/ascendex.py +5 -4
  6. ccxt/async_support/__init__.py +1 -1
  7. ccxt/async_support/ascendex.py +5 -4
  8. ccxt/async_support/base/exchange.py +1 -1
  9. ccxt/async_support/bigone.py +35 -86
  10. ccxt/async_support/binance.py +8 -11
  11. ccxt/async_support/bingx.py +27 -23
  12. ccxt/async_support/bitfinex2.py +7 -16
  13. ccxt/async_support/bitget.py +10 -6
  14. ccxt/async_support/bitmart.py +4 -3
  15. ccxt/async_support/bitmex.py +7 -6
  16. ccxt/async_support/blofin.py +7 -16
  17. ccxt/async_support/bybit.py +22 -17
  18. ccxt/async_support/coinex.py +19 -5
  19. ccxt/async_support/delta.py +6 -5
  20. ccxt/async_support/deribit.py +4 -3
  21. ccxt/async_support/digifinex.py +18 -4
  22. ccxt/async_support/gate.py +61 -13
  23. ccxt/async_support/hashkey.py +6 -6
  24. ccxt/async_support/hitbtc.py +6 -5
  25. ccxt/async_support/htx.py +25 -6
  26. ccxt/async_support/hyperliquid.py +6 -1
  27. ccxt/async_support/krakenfutures.py +6 -5
  28. ccxt/async_support/kucoin.py +1 -0
  29. ccxt/async_support/kucoinfutures.py +164 -4
  30. ccxt/async_support/mexc.py +4 -3
  31. ccxt/async_support/oceanex.py +80 -4
  32. ccxt/async_support/okx.py +17 -3
  33. ccxt/async_support/oxfun.py +7 -7
  34. ccxt/async_support/phemex.py +4 -3
  35. ccxt/async_support/poloniexfutures.py +13 -2
  36. ccxt/async_support/vertex.py +6 -5
  37. ccxt/async_support/whitebit.py +14 -13
  38. ccxt/async_support/woo.py +42 -21
  39. ccxt/async_support/woofipro.py +19 -6
  40. ccxt/async_support/xt.py +5 -3
  41. ccxt/base/exchange.py +1 -1
  42. ccxt/base/types.py +1 -0
  43. ccxt/bigone.py +35 -86
  44. ccxt/binance.py +8 -11
  45. ccxt/bingx.py +27 -23
  46. ccxt/bitfinex2.py +7 -16
  47. ccxt/bitget.py +10 -6
  48. ccxt/bitmart.py +4 -3
  49. ccxt/bitmex.py +7 -6
  50. ccxt/blofin.py +7 -16
  51. ccxt/bybit.py +22 -17
  52. ccxt/coinex.py +19 -5
  53. ccxt/delta.py +6 -5
  54. ccxt/deribit.py +4 -3
  55. ccxt/digifinex.py +18 -4
  56. ccxt/gate.py +61 -13
  57. ccxt/hashkey.py +6 -6
  58. ccxt/hitbtc.py +6 -5
  59. ccxt/htx.py +25 -6
  60. ccxt/hyperliquid.py +6 -1
  61. ccxt/krakenfutures.py +6 -5
  62. ccxt/kucoin.py +1 -0
  63. ccxt/kucoinfutures.py +164 -4
  64. ccxt/mexc.py +4 -3
  65. ccxt/oceanex.py +80 -4
  66. ccxt/okx.py +17 -3
  67. ccxt/oxfun.py +7 -7
  68. ccxt/phemex.py +4 -3
  69. ccxt/poloniexfutures.py +13 -2
  70. ccxt/pro/__init__.py +1 -1
  71. ccxt/pro/binance.py +3 -3
  72. ccxt/pro/deribit.py +39 -2
  73. ccxt/pro/gate.py +1 -1
  74. ccxt/pro/hitbtc.py +112 -44
  75. ccxt/pro/hollaex.py +5 -0
  76. ccxt/pro/okx.py +12 -1
  77. ccxt/pro/p2b.py +33 -2
  78. ccxt/pro/whitebit.py +29 -1
  79. ccxt/vertex.py +6 -5
  80. ccxt/whitebit.py +14 -13
  81. ccxt/woo.py +42 -21
  82. ccxt/woofipro.py +19 -6
  83. ccxt/xt.py +5 -3
  84. ccxt-4.4.10.dist-info/METADATA +636 -0
  85. {ccxt-4.4.8.dist-info → ccxt-4.4.10.dist-info}/RECORD +88 -88
  86. ccxt-4.4.8.dist-info/METADATA +0 -636
  87. {ccxt-4.4.8.dist-info → ccxt-4.4.10.dist-info}/LICENSE.txt +0 -0
  88. {ccxt-4.4.8.dist-info → ccxt-4.4.10.dist-info}/WHEEL +0 -0
  89. {ccxt-4.4.8.dist-info → ccxt-4.4.10.dist-info}/top_level.txt +0 -0
ccxt/phemex.py CHANGED
@@ -7,7 +7,7 @@ from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.phemex import ImplicitAPI
8
8
  import hashlib
9
9
  import numbers
10
- from ccxt.base.types import Balances, Currencies, Currency, Int, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
10
+ from ccxt.base.types import Balances, Currencies, Currency, Int, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, Trade, Transaction, TransferEntry
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
@@ -3741,7 +3741,7 @@ class phemex(Exchange, ImplicitAPI):
3741
3741
  value = Precise.string_mul(value, tickPrecision)
3742
3742
  return value
3743
3743
 
3744
- def fetch_funding_rate(self, symbol: str, params={}):
3744
+ def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
3745
3745
  """
3746
3746
  fetch the current funding rate
3747
3747
  :param str symbol: unified market symbol
@@ -3786,7 +3786,7 @@ class phemex(Exchange, ImplicitAPI):
3786
3786
  result = self.safe_value(response, 'result', {})
3787
3787
  return self.parse_funding_rate(result, market)
3788
3788
 
3789
- def parse_funding_rate(self, contract, market: Market = None):
3789
+ def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
3790
3790
  #
3791
3791
  # {
3792
3792
  # "askEp": 2332500,
@@ -3845,6 +3845,7 @@ class phemex(Exchange, ImplicitAPI):
3845
3845
  'previousFundingRate': None,
3846
3846
  'previousFundingTimestamp': None,
3847
3847
  'previousFundingDatetime': None,
3848
+ 'interval': None,
3848
3849
  }
3849
3850
 
3850
3851
  def set_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
ccxt/poloniexfutures.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.poloniexfutures import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
9
+ from ccxt.base.types import Balances, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, Trade
10
10
  from typing import List
11
11
  from ccxt.base.errors import AuthenticationError
12
12
  from ccxt.base.errors import AccountSuspended
@@ -1527,7 +1527,7 @@ class poloniexfutures(Exchange, ImplicitAPI):
1527
1527
  'trades': None,
1528
1528
  }, market)
1529
1529
 
1530
- def fetch_funding_rate(self, symbol: str, params={}):
1530
+ def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
1531
1531
  """
1532
1532
  fetch the current funding rate
1533
1533
  :see: https://api-docs.poloniex.com/futures/api/futures-index#get-premium-index
@@ -1571,8 +1571,19 @@ class poloniexfutures(Exchange, ImplicitAPI):
1571
1571
  'previousFundingRate': self.safe_number(data, 'value'),
1572
1572
  'previousFundingTimestamp': fundingTimestamp,
1573
1573
  'previousFundingDatetime': self.iso8601(fundingTimestamp),
1574
+ 'interval': self.parse_funding_interval(self.safe_string(data, 'interval')),
1574
1575
  }
1575
1576
 
1577
+ def parse_funding_interval(self, interval):
1578
+ intervals: dict = {
1579
+ '3600000': '1h',
1580
+ '14400000': '4h',
1581
+ '28800000': '8h',
1582
+ '57600000': '16h',
1583
+ '86400000': '24h',
1584
+ }
1585
+ return self.safe_string(intervals, interval, interval)
1586
+
1576
1587
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1577
1588
  """
1578
1589
  fetch all trades made by the user
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.8'
7
+ __version__ = '4.4.10'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/binance.py CHANGED
@@ -2417,13 +2417,13 @@ class binance(ccxt.async_support.binance):
2417
2417
  subType, params = self.handle_sub_type_and_params('watchBalance', None, params)
2418
2418
  isPortfolioMargin = None
2419
2419
  isPortfolioMargin, params = self.handle_option_and_params_2(params, 'watchBalance', 'papi', 'portfolioMargin', False)
2420
- urlType = type
2421
- if isPortfolioMargin:
2422
- urlType = 'papi'
2423
2420
  if self.isLinear(type, subType):
2424
2421
  type = 'future'
2425
2422
  elif self.isInverse(type, subType):
2426
2423
  type = 'delivery'
2424
+ urlType = type
2425
+ if isPortfolioMargin:
2426
+ urlType = 'papi'
2427
2427
  url = self.urls['api']['ws'][urlType] + '/' + self.options[type]['listenKey']
2428
2428
  client = self.client(url)
2429
2429
  self.set_balance_cache(client, type, isPortfolioMargin)
ccxt/pro/deribit.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 ExchangeError
@@ -22,7 +22,7 @@ class deribit(ccxt.async_support.deribit):
22
22
  'ws': True,
23
23
  'watchBalance': True,
24
24
  'watchTicker': True,
25
- 'watchTickers': False,
25
+ 'watchTickers': True,
26
26
  'watchTrades': True,
27
27
  'watchTradesForSymbols': True,
28
28
  'watchMyTrades': True,
@@ -189,6 +189,43 @@ class deribit(ccxt.async_support.deribit):
189
189
  request = self.deep_extend(message, params)
190
190
  return await self.watch(url, channel, request, channel, request)
191
191
 
192
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
193
+ """
194
+ :see: https://docs.deribit.com/#ticker-instrument_name-interval
195
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
196
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
197
+ :param dict [params]: extra parameters specific to the exchange API endpoint
198
+ :param str [params.interval]: specify aggregation and frequency of notifications. Possible values: 100ms, raw
199
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
200
+ """
201
+ await self.load_markets()
202
+ symbols = self.market_symbols(symbols, None, False)
203
+ url = self.urls['api']['ws']
204
+ interval = self.safe_string(params, 'interval', '100ms')
205
+ params = self.omit(params, 'interval')
206
+ await self.load_markets()
207
+ if interval == 'raw':
208
+ await self.authenticate()
209
+ channels = []
210
+ for i in range(0, len(symbols)):
211
+ market = self.market(symbols[i])
212
+ channels.append('ticker.' + market['id'] + '.' + interval)
213
+ message: dict = {
214
+ 'jsonrpc': '2.0',
215
+ 'method': 'public/subscribe',
216
+ 'params': {
217
+ 'channels': channels,
218
+ },
219
+ 'id': self.request_id(),
220
+ }
221
+ request = self.deep_extend(message, params)
222
+ newTickers = await self.watch_multiple(url, channels, request, channels, request)
223
+ if self.newUpdates:
224
+ tickers: dict = {}
225
+ tickers[newTickers['symbol']] = newTickers
226
+ return tickers
227
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
228
+
192
229
  def handle_ticker(self, client: Client, message):
193
230
  #
194
231
  # {
ccxt/pro/gate.py CHANGED
@@ -332,7 +332,7 @@ class gate(ccxt.async_support.gate):
332
332
  symbol = market['symbol']
333
333
  if market['swap'] is not True:
334
334
  raise NotSupported(self.id + ' fetchOrdersByStatusWs is only supported by swap markets. Use rest API for other markets')
335
- request, requestParams = self.fetchOrdersByStatusRequest(status, symbol, since, limit, params)
335
+ request, requestParams = self.prepareOrdersByStatusRequest(status, symbol, since, limit, params)
336
336
  newRequest = self.omit(request, ['settle'])
337
337
  messageType = self.get_type_by_market(market)
338
338
  channel = messageType + '.order_list'
ccxt/pro/hitbtc.py CHANGED
@@ -22,6 +22,7 @@ class hitbtc(ccxt.async_support.hitbtc):
22
22
  'ws': True,
23
23
  'watchTicker': True,
24
24
  'watchTickers': True,
25
+ 'watchBidsAsks': True,
25
26
  'watchTrades': True,
26
27
  'watchTradesForSymbols': False,
27
28
  'watchOrderBook': True,
@@ -56,8 +57,11 @@ class hitbtc(ccxt.async_support.hitbtc):
56
57
  'watchTickers': {
57
58
  'method': 'ticker/{speed}', # 'ticker/{speed}','ticker/price/{speed}', 'ticker/{speed}/batch', or 'ticker/{speed}/price/batch''
58
59
  },
60
+ 'watchBidsAsks': {
61
+ 'method': 'orderbook/top/{speed}', # 'orderbook/top/{speed}', 'orderbook/top/{speed}/batch'
62
+ },
59
63
  'watchOrderBook': {
60
- 'method': 'orderbook/full', # 'orderbook/full', 'orderbook/{depth}/{speed}', 'orderbook/{depth}/{speed}/batch', 'orderbook/top/{speed}', or 'orderbook/top/{speed}/batch'
64
+ 'method': 'orderbook/full', # 'orderbook/full', 'orderbook/{depth}/{speed}', 'orderbook/{depth}/{speed}/batch'
61
65
  },
62
66
  },
63
67
  'timeframes': {
@@ -130,17 +134,22 @@ class hitbtc(ccxt.async_support.hitbtc):
130
134
  :param dict [params]: extra parameters specific to the hitbtc api
131
135
  """
132
136
  await self.load_markets()
137
+ symbols = self.market_symbols(symbols)
138
+ isBatch = name.find('batch') >= 0
133
139
  url = self.urls['api']['ws']['public']
134
- messageHash = messageHashPrefix
135
- if symbols is not None:
136
- messageHash = messageHash + '::' + ','.join(symbols)
140
+ messageHashes = []
141
+ if symbols is not None and not isBatch:
142
+ for i in range(0, len(symbols)):
143
+ messageHashes.append(messageHashPrefix + '::' + symbols[i])
144
+ else:
145
+ messageHashes.append(messageHashPrefix)
137
146
  subscribe: dict = {
138
147
  'method': 'subscribe',
139
148
  'id': self.nonce(),
140
149
  'ch': name,
141
150
  }
142
151
  request = self.extend(subscribe, params)
143
- return await self.watch(url, messageHash, request, messageHash)
152
+ return await self.watch_multiple(url, messageHashes, request, messageHashes)
144
153
 
145
154
  async def subscribe_private(self, name: str, symbol: Str = None, params={}):
146
155
  """
@@ -192,7 +201,7 @@ class hitbtc(ccxt.async_support.hitbtc):
192
201
  :param str symbol: unified symbol of the market to fetch the order book for
193
202
  :param int [limit]: the maximum amount of order book entries to return
194
203
  :param dict [params]: extra parameters specific to the exchange API endpoint
195
- :param str [params.method]: 'orderbook/full', 'orderbook/{depth}/{speed}', 'orderbook/{depth}/{speed}/batch', 'orderbook/top/{speed}', or 'orderbook/top/{speed}/batch'
204
+ :param str [params.method]: 'orderbook/full', 'orderbook/{depth}/{speed}', 'orderbook/{depth}/{speed}/batch'
196
205
  :param int [params.depth]: 5 , 10, or 20(default)
197
206
  :param int [params.speed]: 100(default), 500, or 1000
198
207
  :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
@@ -206,10 +215,6 @@ class hitbtc(ccxt.async_support.hitbtc):
206
215
  name = 'orderbook/D' + depth + '/' + speed + 'ms'
207
216
  elif name == 'orderbook/{depth}/{speed}/batch':
208
217
  name = 'orderbook/D' + depth + '/' + speed + 'ms/batch'
209
- elif name == 'orderbook/top/{speed}':
210
- name = 'orderbook/top/' + speed + 'ms'
211
- elif name == 'orderbook/top/{speed}/batch':
212
- name = 'orderbook/top/' + speed + 'ms/batch'
213
218
  market = self.market(symbol)
214
219
  request: dict = {
215
220
  'params': {
@@ -298,33 +303,22 @@ class hitbtc(ccxt.async_support.hitbtc):
298
303
  :param str [params.speed]: '1s'(default), or '3s'
299
304
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
300
305
  """
301
- options = self.safe_value(self.options, 'watchTicker')
302
- defaultMethod = self.safe_string(options, 'method', 'ticker/{speed}')
303
- method = self.safe_string_2(params, 'method', 'defaultMethod', defaultMethod)
304
- speed = self.safe_string(params, 'speed', '1s')
305
- name = self.implode_params(method, {'speed': speed})
306
- params = self.omit(params, ['method', 'speed'])
307
- market = self.market(symbol)
308
- request: dict = {
309
- 'params': {
310
- 'symbols': [market['id']],
311
- },
312
- }
313
- result = await self.subscribe_public(name, 'tickers', [symbol], self.deep_extend(request, params))
314
- return self.safe_value(result, symbol)
306
+ ticker = await self.watch_tickers([symbol], params)
307
+ return self.safe_value(ticker, symbol)
315
308
 
316
309
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
317
310
  """
318
311
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
319
312
  :param str symbol: unified symbol of the market to fetch the ticker for
320
313
  :param dict params: extra parameters specific to the exchange API endpoint
321
- :param str params['method']: 'ticker/{speed}'(default),'ticker/price/{speed}', 'ticker/{speed}/batch', or 'ticker/{speed}/price/batch''
314
+ :param str params['method']: 'ticker/{speed}' ,'ticker/price/{speed}', 'ticker/{speed}/batch'(default), or 'ticker/{speed}/price/batch''
322
315
  :param str params['speed']: '1s'(default), or '3s'
323
316
  :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
324
317
  """
325
318
  await self.load_markets()
319
+ symbols = self.market_symbols(symbols)
326
320
  options = self.safe_value(self.options, 'watchTicker')
327
- defaultMethod = self.safe_string(options, 'method', 'ticker/{speed}')
321
+ defaultMethod = self.safe_string(options, 'method', 'ticker/{speed}/batch')
328
322
  method = self.safe_string_2(params, 'method', 'defaultMethod', defaultMethod)
329
323
  speed = self.safe_string(params, 'speed', '1s')
330
324
  name = self.implode_params(method, {'speed': speed})
@@ -341,10 +335,13 @@ class hitbtc(ccxt.async_support.hitbtc):
341
335
  'symbols': marketIds,
342
336
  },
343
337
  }
344
- tickers = await self.subscribe_public(name, 'tickers', symbols, self.deep_extend(request, params))
338
+ newTickers = await self.subscribe_public(name, 'tickers', symbols, self.deep_extend(request, params))
345
339
  if self.newUpdates:
346
- return tickers
347
- return self.filter_by_array(self.tickers, 'symbol', symbols)
340
+ if not isinstance(newTickers, list):
341
+ tickers: dict = {}
342
+ tickers[newTickers['symbol']] = newTickers
343
+ return tickers
344
+ return self.filter_by_array(newTickers, 'symbol', symbols)
348
345
 
349
346
  def handle_ticker(self, client: Client, message):
350
347
  #
@@ -387,27 +384,18 @@ class hitbtc(ccxt.async_support.hitbtc):
387
384
  #
388
385
  data = self.safe_value(message, 'data', {})
389
386
  marketIds = list(data.keys())
390
- newTickers: dict = {}
387
+ result = []
388
+ topic = 'tickers'
391
389
  for i in range(0, len(marketIds)):
392
390
  marketId = marketIds[i]
393
391
  market = self.safe_market(marketId)
394
392
  symbol = market['symbol']
395
393
  ticker = self.parse_ws_ticker(data[marketId], market)
396
394
  self.tickers[symbol] = ticker
397
- newTickers[symbol] = ticker
398
- client.resolve(newTickers, 'tickers')
399
- messageHashes = self.find_message_hashes(client, 'tickers::')
400
- for i in range(0, len(messageHashes)):
401
- messageHash = messageHashes[i]
402
- parts = messageHash.split('::')
403
- symbolsString = parts[1]
404
- symbols = symbolsString.split(',')
405
- tickers = self.filter_by_array(newTickers, 'symbol', symbols)
406
- tickersSymbols = list(tickers.keys())
407
- numTickers = len(tickersSymbols)
408
- if numTickers > 0:
409
- client.resolve(tickers, messageHash)
410
- return message
395
+ result.append(ticker)
396
+ messageHash = topic + '::' + symbol
397
+ client.resolve(ticker, messageHash)
398
+ client.resolve(result, topic)
411
399
 
412
400
  def parse_ws_ticker(self, ticker, market=None):
413
401
  #
@@ -464,6 +452,81 @@ class hitbtc(ccxt.async_support.hitbtc):
464
452
  'info': ticker,
465
453
  }, market)
466
454
 
455
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
456
+ """
457
+ watches best bid & ask for symbols
458
+ :see: https://api.hitbtc.com/#subscribe-to-top-of-book
459
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
460
+ :param dict [params]: extra parameters specific to the exchange API endpoint
461
+ :param str [params.method]: 'orderbook/top/{speed}' or 'orderbook/top/{speed}/batch(default)'
462
+ :param str [params.speed]: '100ms'(default) or '500ms' or '1000ms'
463
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
464
+ """
465
+ await self.load_markets()
466
+ symbols = self.market_symbols(symbols, None, False)
467
+ options = self.safe_value(self.options, 'watchBidsAsks')
468
+ defaultMethod = self.safe_string(options, 'method', 'orderbook/top/{speed}/batch')
469
+ method = self.safe_string_2(params, 'method', 'defaultMethod', defaultMethod)
470
+ speed = self.safe_string(params, 'speed', '100ms')
471
+ name = self.implode_params(method, {'speed': speed})
472
+ params = self.omit(params, ['method', 'speed'])
473
+ marketIds = self.market_ids(symbols)
474
+ request: dict = {
475
+ 'params': {
476
+ 'symbols': marketIds,
477
+ },
478
+ }
479
+ newTickers = await self.subscribe_public(name, 'bidask', symbols, self.deep_extend(request, params))
480
+ if self.newUpdates:
481
+ if not isinstance(newTickers, list):
482
+ tickers: dict = {}
483
+ tickers[newTickers['symbol']] = newTickers
484
+ return tickers
485
+ return self.filter_by_array(newTickers, 'symbol', symbols)
486
+
487
+ def handle_bid_ask(self, client: Client, message):
488
+ #
489
+ # {
490
+ # "ch": "orderbook/top/100ms", # or 'orderbook/top/100ms/batch'
491
+ # "data": {
492
+ # "BTCUSDT": {
493
+ # "t": 1727276919771,
494
+ # "a": "63931.45",
495
+ # "A": "0.02879",
496
+ # "b": "63926.97",
497
+ # "B": "0.00100"
498
+ # }
499
+ # }
500
+ # }
501
+ #
502
+ data = self.safe_dict(message, 'data', {})
503
+ marketIds = list(data.keys())
504
+ result = []
505
+ topic = 'bidask'
506
+ for i in range(0, len(marketIds)):
507
+ marketId = marketIds[i]
508
+ market = self.safe_market(marketId)
509
+ symbol = market['symbol']
510
+ ticker = self.parse_ws_bid_ask(data[marketId], market)
511
+ self.bidsasks[symbol] = ticker
512
+ result.append(ticker)
513
+ messageHash = topic + '::' + symbol
514
+ client.resolve(ticker, messageHash)
515
+ client.resolve(result, topic)
516
+
517
+ def parse_ws_bid_ask(self, ticker, market=None):
518
+ timestamp = self.safe_integer(ticker, 't')
519
+ return self.safe_ticker({
520
+ 'symbol': market['symbol'],
521
+ 'timestamp': timestamp,
522
+ 'datetime': self.iso8601(timestamp),
523
+ 'ask': self.safe_string(ticker, 'a'),
524
+ 'askVolume': self.safe_string(ticker, 'A'),
525
+ 'bid': self.safe_string(ticker, 'b'),
526
+ 'bidVolume': self.safe_string(ticker, 'B'),
527
+ 'info': ticker,
528
+ }, market)
529
+
467
530
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
468
531
  """
469
532
  get the list of most recent trades for a particular symbol
@@ -1144,11 +1207,16 @@ class hitbtc(ccxt.async_support.hitbtc):
1144
1207
  if channel is not None:
1145
1208
  splitChannel = channel.split('/')
1146
1209
  channel = self.safe_string(splitChannel, 0)
1210
+ if channel == 'orderbook':
1211
+ channel2 = self.safe_string(splitChannel, 1)
1212
+ if channel2 is not None and channel2 == 'top':
1213
+ channel = 'orderbook/top'
1147
1214
  methods: dict = {
1148
1215
  'candles': self.handle_ohlcv,
1149
1216
  'ticker': self.handle_ticker,
1150
1217
  'trades': self.handle_trades,
1151
1218
  'orderbook': self.handle_order_book,
1219
+ 'orderbook/top': self.handle_bid_ask,
1152
1220
  'spot_order': self.handle_order,
1153
1221
  'spot_orders': self.handle_order,
1154
1222
  'margin_order': self.handle_order,
ccxt/pro/hollaex.py CHANGED
@@ -62,6 +62,7 @@ class hollaex(ccxt.async_support.hollaex):
62
62
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
63
63
  """
64
64
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
65
+ :see: https://apidocs.hollaex.com/#sending-receiving-messages
65
66
  :param str symbol: unified symbol of the market to fetch the order book for
66
67
  :param int [limit]: the maximum amount of order book entries to return
67
68
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -116,6 +117,7 @@ class hollaex(ccxt.async_support.hollaex):
116
117
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
117
118
  """
118
119
  get the list of most recent trades for a particular symbol
120
+ :see: https://apidocs.hollaex.com/#sending-receiving-messages
119
121
  :param str symbol: unified symbol of the market to fetch trades for
120
122
  :param int [since]: timestamp in ms of the earliest trade to fetch
121
123
  :param int [limit]: the maximum amount of trades to fetch
@@ -167,6 +169,7 @@ class hollaex(ccxt.async_support.hollaex):
167
169
  async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
168
170
  """
169
171
  watches information on multiple trades made by the user
172
+ :see: https://apidocs.hollaex.com/#sending-receiving-messages
170
173
  :param str symbol: unified market symbol of the market trades were made in
171
174
  :param int [since]: the earliest time in ms to fetch trades for
172
175
  :param int [limit]: the maximum number of trade structures to retrieve
@@ -239,6 +242,7 @@ class hollaex(ccxt.async_support.hollaex):
239
242
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
240
243
  """
241
244
  watches information on multiple orders made by the user
245
+ :see: https://apidocs.hollaex.com/#sending-receiving-messages
242
246
  :param str symbol: unified market symbol of the market orders were made in
243
247
  :param int [since]: the earliest time in ms to fetch orders for
244
248
  :param int [limit]: the maximum number of order structures to retrieve
@@ -350,6 +354,7 @@ class hollaex(ccxt.async_support.hollaex):
350
354
  async def watch_balance(self, params={}) -> Balances:
351
355
  """
352
356
  watch balance and get the amount of funds available for trading or funds locked in orders
357
+ :see: https://apidocs.hollaex.com/#sending-receiving-messages
353
358
  :param dict [params]: extra parameters specific to the exchange API endpoint
354
359
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
355
360
  """
ccxt/pro/okx.py CHANGED
@@ -2055,10 +2055,21 @@ class okx(ccxt.async_support.okx):
2055
2055
  try:
2056
2056
  if errorCode and errorCode != '0':
2057
2057
  feedback = self.id + ' ' + self.json(message)
2058
- self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
2058
+ if errorCode != '1':
2059
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
2059
2060
  messageString = self.safe_value(message, 'msg')
2060
2061
  if messageString is not None:
2061
2062
  self.throw_broadly_matched_exception(self.exceptions['broad'], messageString, feedback)
2063
+ else:
2064
+ data = self.safe_list(message, 'data', [])
2065
+ for i in range(0, len(data)):
2066
+ d = data[i]
2067
+ errorCode = self.safe_string(d, 'sCode')
2068
+ if errorCode is not None:
2069
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
2070
+ messageString = self.safe_value(message, 'sMsg')
2071
+ if messageString is not None:
2072
+ self.throw_broadly_matched_exception(self.exceptions['broad'], messageString, feedback)
2062
2073
  raise ExchangeError(feedback)
2063
2074
  except Exception as e:
2064
2075
  # if the message contains an id, it means it is a response to a request
ccxt/pro/p2b.py CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheByTimestamp
8
- from ccxt.base.types import Int, OrderBook, Ticker, Trade
8
+ from ccxt.base.types import Int, OrderBook, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
@@ -34,7 +34,7 @@ class p2b(ccxt.async_support.p2b):
34
34
  'watchOrders': False,
35
35
  # 'watchStatus': True,
36
36
  'watchTicker': True,
37
- 'watchTickers': False, # in the docs but does not return anything when subscribed to
37
+ 'watchTickers': True,
38
38
  'watchTrades': True,
39
39
  'watchTradesForSymbols': True,
40
40
  },
@@ -133,6 +133,36 @@ class p2b(ccxt.async_support.p2b):
133
133
  messageHash = name + '::' + market['symbol']
134
134
  return await self.subscribe(name + '.subscribe', messageHash, request, params)
135
135
 
136
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
137
+ """
138
+ :see: https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#last-price
139
+ :see: https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#market-status
140
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
141
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
142
+ :param dict [params]: extra parameters specific to the exchange API endpoint
143
+ :param dict [params.method]: 'state'(default) or 'price'
144
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
145
+ """
146
+ await self.load_markets()
147
+ symbols = self.market_symbols(symbols, None, False)
148
+ watchTickerOptions = self.safe_dict(self.options, 'watchTicker')
149
+ name = self.safe_string(watchTickerOptions, 'name', 'state') # or price
150
+ name, params = self.handle_option_and_params(params, 'method', 'name', name)
151
+ messageHashes = []
152
+ args = []
153
+ for i in range(0, len(symbols)):
154
+ market = self.market(symbols[i])
155
+ messageHashes.append(name + '::' + market['symbol'])
156
+ args.append(market['id'])
157
+ url = self.urls['api']['ws']
158
+ request: dict = {
159
+ 'method': name + '.subscribe',
160
+ 'params': args,
161
+ 'id': self.milliseconds(),
162
+ }
163
+ await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
164
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
165
+
136
166
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
137
167
  """
138
168
  get the list of most recent trades for a particular symbol
@@ -332,6 +362,7 @@ class p2b(ccxt.async_support.p2b):
332
362
  else:
333
363
  ticker = self.parse_ticker(tickerData, market)
334
364
  symbol = ticker['symbol']
365
+ self.tickers[symbol] = ticker
335
366
  messageHash = messageHashStart + '::' + symbol
336
367
  client.resolve(ticker, messageHash)
337
368
  return message
ccxt/pro/whitebit.py CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
- from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
8
+ from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import AuthenticationError
@@ -26,6 +26,7 @@ class whitebit(ccxt.async_support.whitebit):
26
26
  'watchOrderBook': True,
27
27
  'watchOrders': True,
28
28
  'watchTicker': True,
29
+ 'watchTickers': True,
29
30
  'watchTrades': True,
30
31
  'watchTradesForSymbols': False,
31
32
  },
@@ -249,6 +250,33 @@ class whitebit(ccxt.async_support.whitebit):
249
250
  # every time we want to subscribe to another market we have to "re-subscribe" sending it all again
250
251
  return await self.watch_multiple_subscription(messageHash, method, symbol, False, params)
251
252
 
253
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
254
+ """
255
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
256
+ :see: https://docs.whitebit.com/public/websocket/#market-statistics
257
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
258
+ :param dict [params]: extra parameters specific to the exchange API endpoint
259
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
260
+ """
261
+ await self.load_markets()
262
+ symbols = self.market_symbols(symbols, None, False)
263
+ method = 'market_subscribe'
264
+ url = self.urls['api']['ws']
265
+ id = self.nonce()
266
+ messageHashes = []
267
+ args = []
268
+ for i in range(0, len(symbols)):
269
+ market = self.market(symbols[i])
270
+ messageHashes.append('ticker:' + market['symbol'])
271
+ args.append(market['id'])
272
+ request: dict = {
273
+ 'id': id,
274
+ 'method': method,
275
+ 'params': args,
276
+ }
277
+ await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
278
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
279
+
252
280
  def handle_ticker(self, client: Client, message):
253
281
  #
254
282
  # {
ccxt/vertex.py CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.vertex import ImplicitAPI
8
- from ccxt.base.types import Balances, Currencies, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees
8
+ from ccxt.base.types import Balances, Currencies, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFees
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import AuthenticationError
@@ -1154,7 +1154,7 @@ class vertex(Exchange, ImplicitAPI):
1154
1154
  rows = self.safe_list(response, 'candlesticks', [])
1155
1155
  return self.parse_ohlcvs(rows, market, timeframe, since, limit)
1156
1156
 
1157
- def parse_funding_rate(self, ticker, market: Market = None):
1157
+ def parse_funding_rate(self, ticker, market: Market = None) -> FundingRate:
1158
1158
  #
1159
1159
  # {
1160
1160
  # "product_id": 4,
@@ -1208,9 +1208,10 @@ class vertex(Exchange, ImplicitAPI):
1208
1208
  'previousFundingRate': None,
1209
1209
  'previousFundingTimestamp': None,
1210
1210
  'previousFundingDatetime': None,
1211
+ 'interval': None,
1211
1212
  }
1212
1213
 
1213
- def fetch_funding_rate(self, symbol: str, params={}):
1214
+ def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
1214
1215
  """
1215
1216
  fetch the current funding rate
1216
1217
  :see: https://docs.vertexprotocol.com/developer-resources/api/archive-indexer/funding-rate
@@ -1235,13 +1236,13 @@ class vertex(Exchange, ImplicitAPI):
1235
1236
  #
1236
1237
  return self.parse_funding_rate(response, market)
1237
1238
 
1238
- def fetch_funding_rates(self, symbols: Strings = None, params={}):
1239
+ def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
1239
1240
  """
1240
1241
  fetches funding rates for multiple markets
1241
1242
  :see: https://docs.vertexprotocol.com/developer-resources/api/v2/contracts
1242
1243
  :param str[] symbols: unified symbols of the markets to fetch the funding rates for, all market funding rates are returned if not assigned
1243
1244
  :param dict [params]: extra parameters specific to the exchange API endpoint
1244
- :returns dict: an array of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1245
+ :returns dict[]: an array of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1245
1246
  """
1246
1247
  self.load_markets()
1247
1248
  request = {}