ccxt 4.3.39__py2.py3-none-any.whl → 4.3.41__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 (58) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/binance.py +2 -0
  3. ccxt/abstract/binancecoinm.py +2 -0
  4. ccxt/abstract/binanceus.py +2 -0
  5. ccxt/abstract/binanceusdm.py +2 -0
  6. ccxt/abstract/okx.py +7 -0
  7. ccxt/async_support/__init__.py +1 -1
  8. ccxt/async_support/base/exchange.py +1 -1
  9. ccxt/async_support/binance.py +4 -0
  10. ccxt/async_support/bitfinex2.py +1 -1
  11. ccxt/async_support/bithumb.py +9 -1
  12. ccxt/async_support/bitstamp.py +38 -2
  13. ccxt/async_support/coinlist.py +19 -1
  14. ccxt/async_support/coinmate.py +19 -3
  15. ccxt/async_support/coinone.py +1 -1
  16. ccxt/async_support/coinspot.py +11 -2
  17. ccxt/async_support/hitbtc.py +2 -2
  18. ccxt/async_support/independentreserve.py +33 -1
  19. ccxt/async_support/indodax.py +43 -2
  20. ccxt/async_support/okx.py +7 -0
  21. ccxt/async_support/upbit.py +13 -8
  22. ccxt/async_support/woo.py +6 -2
  23. ccxt/async_support/woofipro.py +8 -2
  24. ccxt/base/exchange.py +1 -1
  25. ccxt/binance.py +4 -0
  26. ccxt/bitfinex2.py +1 -1
  27. ccxt/bithumb.py +9 -1
  28. ccxt/bitstamp.py +38 -2
  29. ccxt/coinlist.py +19 -1
  30. ccxt/coinmate.py +19 -3
  31. ccxt/coinone.py +1 -1
  32. ccxt/coinspot.py +11 -2
  33. ccxt/hitbtc.py +2 -2
  34. ccxt/independentreserve.py +33 -1
  35. ccxt/indodax.py +43 -2
  36. ccxt/okx.py +7 -0
  37. ccxt/pro/__init__.py +1 -1
  38. ccxt/pro/alpaca.py +5 -5
  39. ccxt/pro/ascendex.py +3 -3
  40. ccxt/pro/bingx.py +258 -42
  41. ccxt/pro/bitget.py +6 -5
  42. ccxt/pro/bitrue.py +3 -4
  43. ccxt/pro/currencycom.py +6 -5
  44. ccxt/pro/exmo.py +5 -6
  45. ccxt/pro/gemini.py +4 -3
  46. ccxt/pro/independentreserve.py +7 -7
  47. ccxt/pro/lbank.py +4 -4
  48. ccxt/pro/phemex.py +5 -5
  49. ccxt/pro/probit.py +4 -4
  50. ccxt/pro/upbit.py +295 -4
  51. ccxt/pro/wazirx.py +12 -12
  52. ccxt/upbit.py +13 -8
  53. ccxt/woo.py +6 -2
  54. ccxt/woofipro.py +8 -2
  55. {ccxt-4.3.39.dist-info → ccxt-4.3.41.dist-info}/METADATA +4 -4
  56. {ccxt-4.3.39.dist-info → ccxt-4.3.41.dist-info}/RECORD +58 -58
  57. {ccxt-4.3.39.dist-info → ccxt-4.3.41.dist-info}/WHEEL +0 -0
  58. {ccxt-4.3.39.dist-info → ccxt-4.3.41.dist-info}/top_level.txt +0 -0
ccxt/pro/bingx.py CHANGED
@@ -5,10 +5,12 @@
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
+ from ccxt.base.errors import ArgumentsRequired
11
12
  from ccxt.base.errors import BadRequest
13
+ from ccxt.base.errors import NotSupported
12
14
  from ccxt.base.errors import NetworkError
13
15
  from ccxt.base.precise import Precise
14
16
 
@@ -21,11 +23,13 @@ class bingx(ccxt.async_support.bingx):
21
23
  'ws': True,
22
24
  'watchTrades': True,
23
25
  'watchOrderBook': True,
26
+ 'watchOrderBookForSymbols': True,
24
27
  'watchOHLCV': True,
28
+ 'watchOHLCVForSymbols': True,
25
29
  'watchOrders': True,
26
30
  'watchMyTrades': True,
27
31
  'watchTicker': True,
28
- 'watchTickers': False,
32
+ 'watchTickers': True,
29
33
  'watchBalance': True,
30
34
  },
31
35
  'urls': {
@@ -73,6 +77,14 @@ class bingx(ccxt.async_support.bingx):
73
77
  'fetchBalanceSnapshot': True, # needed to be True to keep track of used and free balance
74
78
  'awaitBalanceSnapshot': False, # whether to wait for the balance snapshot before providing updates
75
79
  },
80
+ 'watchOrderBook': {
81
+ 'depth': 100, # 5, 10, 20, 50, 100
82
+ 'interval': 500, # 100, 200, 500, 1000
83
+ },
84
+ 'watchOrderBookForSymbols': {
85
+ 'depth': 100, # 5, 10, 20, 50, 100
86
+ 'interval': 500, # 100, 200, 500, 1000
87
+ },
76
88
  },
77
89
  'streaming': {
78
90
  'keepAlive': 1800000, # 30 minutes
@@ -93,15 +105,16 @@ class bingx(ccxt.async_support.bingx):
93
105
  url = self.safe_value(self.urls['api']['ws'], marketType)
94
106
  if url is None:
95
107
  raise BadRequest(self.id + ' watchTrades is not supported for ' + marketType + ' markets.')
96
- messageHash = market['id'] + '@ticker'
108
+ subscriptionHash = market['id'] + '@ticker'
109
+ messageHash = self.get_message_hash('ticker', market['symbol'])
97
110
  uuid = self.uuid()
98
111
  request: dict = {
99
112
  'id': uuid,
100
- 'dataType': messageHash,
113
+ 'dataType': subscriptionHash,
101
114
  }
102
115
  if marketType == 'swap':
103
116
  request['reqType'] = 'sub'
104
- return await self.watch(url, messageHash, self.extend(request, query), messageHash)
117
+ return await self.watch(url, messageHash, self.extend(request, query), subscriptionHash)
105
118
 
106
119
  def handle_ticker(self, client: Client, message):
107
120
  #
@@ -167,8 +180,9 @@ class bingx(ccxt.async_support.bingx):
167
180
  symbol = market['symbol']
168
181
  ticker = self.parse_ws_ticker(data, market)
169
182
  self.tickers[symbol] = ticker
170
- messageHash = market['id'] + '@ticker'
171
- client.resolve(ticker, messageHash)
183
+ client.resolve(ticker, self.get_message_hash('ticker', symbol))
184
+ if self.safe_string(message, 'dataType') == 'all@ticker':
185
+ client.resolve(ticker, self.get_message_hash('ticker'))
172
186
 
173
187
  def parse_ws_ticker(self, message, market=None):
174
188
  #
@@ -220,6 +234,172 @@ class bingx(ccxt.async_support.bingx):
220
234
  'info': message,
221
235
  }, market)
222
236
 
237
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
238
+ """
239
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
240
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/socket/market.html#Subscribe%20to%2024-hour%20price%20changes%20of%20all%20trading%20pairs
241
+ :param str[] symbols: unified symbol of the market to watch the tickers for
242
+ :param dict [params]: extra parameters specific to the exchange API endpoint
243
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
244
+ """
245
+ await self.load_markets()
246
+ symbols = self.market_symbols(symbols, None, True, True, False)
247
+ firstMarket = None
248
+ marketType = None
249
+ symbolsDefined = (symbols is not None)
250
+ if symbolsDefined:
251
+ firstMarket = self.market(symbols[0])
252
+ marketType, params = self.handle_market_type_and_params('watchTickers', firstMarket, params)
253
+ if marketType == 'spot':
254
+ raise NotSupported(self.id + ' watchTickers is not supported for spot markets yet')
255
+ messageHashes = []
256
+ subscriptionHashes = ['all@ticker']
257
+ if symbolsDefined:
258
+ for i in range(0, len(symbols)):
259
+ symbol = symbols[i]
260
+ market = self.market(symbol)
261
+ messageHashes.append(self.get_message_hash('ticker', market['symbol']))
262
+ else:
263
+ messageHashes.append(self.get_message_hash('ticker'))
264
+ url = self.safe_string(self.urls['api']['ws'], marketType)
265
+ uuid = self.uuid()
266
+ request: dict = {
267
+ 'id': uuid,
268
+ 'dataType': 'all@ticker',
269
+ }
270
+ if marketType == 'swap':
271
+ request['reqType'] = 'sub'
272
+ result = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), subscriptionHashes)
273
+ if self.newUpdates:
274
+ newDict: dict = {}
275
+ newDict[result['symbol']] = result
276
+ return newDict
277
+ return self.tickers
278
+
279
+ async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
280
+ """
281
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
282
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/socket/market.html#Subscribe%20Market%20Depth%20Data%20of%20all%20trading%20pairs
283
+ :param str[] symbols: unified array of symbols
284
+ :param int [limit]: the maximum amount of order book entries to return
285
+ :param dict [params]: extra parameters specific to the exchange API endpoint
286
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
287
+ """
288
+ symbols = self.market_symbols(symbols, None, True, True, False)
289
+ firstMarket = None
290
+ marketType = None
291
+ symbolsDefined = (symbols is not None)
292
+ if symbolsDefined:
293
+ firstMarket = self.market(symbols[0])
294
+ marketType, params = self.handle_market_type_and_params('watchOrderBookForSymbols', firstMarket, params)
295
+ if marketType == 'spot':
296
+ raise NotSupported(self.id + ' watchOrderBookForSymbols is not supported for spot markets yet')
297
+ limit = self.get_order_book_limit_by_market_type(marketType, limit)
298
+ interval = None
299
+ interval, params = self.handle_option_and_params(params, 'watchOrderBookForSymbols', 'interval', 500)
300
+ self.check_required_argument('watchOrderBookForSymbols', interval, 'interval', [100, 200, 500, 1000])
301
+ channelName = 'depth' + str(limit) + '@' + str(interval) + 'ms'
302
+ subscriptionHash = 'all@' + channelName
303
+ messageHashes = []
304
+ if symbolsDefined:
305
+ for i in range(0, len(symbols)):
306
+ symbol = symbols[i]
307
+ market = self.market(symbol)
308
+ messageHashes.append(self.get_message_hash('orderbook', market['symbol']))
309
+ else:
310
+ messageHashes.append(self.get_message_hash('orderbook'))
311
+ url = self.safe_string(self.urls['api']['ws'], marketType)
312
+ uuid = self.uuid()
313
+ request: dict = {
314
+ 'id': uuid,
315
+ 'dataType': subscriptionHash,
316
+ }
317
+ if marketType == 'swap':
318
+ request['reqType'] = 'sub'
319
+ subscriptionArgs: dict = {
320
+ 'symbols': symbols,
321
+ 'limit': limit,
322
+ 'interval': interval,
323
+ 'params': params,
324
+ }
325
+ orderbook = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), [subscriptionHash], subscriptionArgs)
326
+ return orderbook.limit()
327
+
328
+ async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
329
+ """
330
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
331
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
332
+ :param int [since]: timestamp in ms of the earliest candle to fetch
333
+ :param int [limit]: the maximum amount of candles to fetch
334
+ :param dict [params]: extra parameters specific to the exchange API endpoint
335
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
336
+ """
337
+ symbolsLength = len(symbolsAndTimeframes)
338
+ if symbolsLength != 0 and not isinstance(symbolsAndTimeframes[0], list):
339
+ raise ArgumentsRequired(self.id + " watchOHLCVForSymbols() requires a an array like [['BTC/USDT:USDT', '1m'], ['LTC/USDT:USDT', '5m']]")
340
+ await self.load_markets()
341
+ messageHashes = []
342
+ marketType = None
343
+ chosenTimeframe = None
344
+ if symbolsLength != 0:
345
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
346
+ symbols = self.market_symbols(symbols, None, True, True, False)
347
+ firstMarket = self.market(symbols[0])
348
+ marketType, params = self.handle_market_type_and_params('watchOrderBookForSymbols', firstMarket, params)
349
+ if marketType == 'spot':
350
+ raise NotSupported(self.id + ' watchOrderBookForSymbols is not supported for spot markets yet')
351
+ marketOptions = self.safe_dict(self.options, marketType)
352
+ timeframes = self.safe_dict(marketOptions, 'timeframes', {})
353
+ for i in range(0, len(symbolsAndTimeframes)):
354
+ symbolAndTimeframe = symbolsAndTimeframes[i]
355
+ sym = symbolAndTimeframe[0]
356
+ tf = symbolAndTimeframe[1]
357
+ market = self.market(sym)
358
+ rawTimeframe = self.safe_string(timeframes, tf, tf)
359
+ if chosenTimeframe is None:
360
+ chosenTimeframe = rawTimeframe
361
+ elif chosenTimeframe != rawTimeframe:
362
+ raise BadRequest(self.id + ' watchOHLCVForSymbols requires all timeframes to be the same')
363
+ messageHashes.append(self.get_message_hash('ohlcv', market['symbol'], chosenTimeframe))
364
+ subscriptionHash = 'all@kline_' + chosenTimeframe
365
+ url = self.safe_string(self.urls['api']['ws'], marketType)
366
+ uuid = self.uuid()
367
+ request: dict = {
368
+ 'id': uuid,
369
+ 'dataType': subscriptionHash,
370
+ }
371
+ if marketType == 'swap':
372
+ request['reqType'] = 'sub'
373
+ subscriptionArgs: dict = {
374
+ 'limit': limit,
375
+ 'params': params,
376
+ }
377
+ symbol, timeframe, candles = await self.watch_multiple(url, messageHashes, request, [subscriptionHash], subscriptionArgs)
378
+ if self.newUpdates:
379
+ limit = candles.getLimit(symbol, limit)
380
+ filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
381
+ return self.create_ohlcv_object(symbol, timeframe, filtered)
382
+
383
+ def get_order_book_limit_by_market_type(self, marketType: str, limit: Int = None):
384
+ if limit is None:
385
+ limit = 100
386
+ else:
387
+ if marketType == 'swap' or marketType == 'future':
388
+ limit = self.find_nearest_ceiling([5, 10, 20, 50, 100], limit)
389
+ elif marketType == 'spot':
390
+ limit = self.find_nearest_ceiling([20, 100], limit)
391
+ return limit
392
+
393
+ def get_message_hash(self, unifiedChannel: str, symbol: Str = None, extra: Str = None):
394
+ hash = unifiedChannel
395
+ if symbol is not None:
396
+ hash += '::' + symbol
397
+ else:
398
+ hash += 's' # tickers, orderbooks, ohlcvs ...
399
+ if extra is not None:
400
+ hash += '::' + extra
401
+ return hash
402
+
223
403
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
224
404
  """
225
405
  watches information on multiple trades made in a market
@@ -344,27 +524,31 @@ class bingx(ccxt.async_support.bingx):
344
524
  await self.load_markets()
345
525
  market = self.market(symbol)
346
526
  marketType, query = self.handle_market_type_and_params('watchOrderBook', market, params)
347
- if limit is None:
348
- limit = 100
349
- else:
350
- if marketType == 'swap':
351
- if (limit != 5) and (limit != 10) and (limit != 20) and (limit != 50) and (limit != 100):
352
- raise BadRequest(self.id + ' watchOrderBook()(swap) only supports limit 5, 10, 20, 50, and 100')
353
- elif marketType == 'spot':
354
- if (limit != 20) and (limit != 100):
355
- raise BadRequest(self.id + ' watchOrderBook()(spot) only supports limit 20, and 100')
527
+ limit = self.get_order_book_limit_by_market_type(marketType, limit)
528
+ channelName = 'depth' + str(limit)
356
529
  url = self.safe_value(self.urls['api']['ws'], marketType)
357
530
  if url is None:
358
531
  raise BadRequest(self.id + ' watchOrderBook is not supported for ' + marketType + ' markets.')
359
- messageHash = market['id'] + '@depth' + str(limit)
532
+ interval = None
533
+ if marketType != 'spot':
534
+ interval, params = self.handle_option_and_params(params, 'watchOrderBook', 'interval', 500)
535
+ self.check_required_argument('watchOrderBook', interval, 'interval', [100, 200, 500, 1000])
536
+ channelName = channelName + '@' + str(interval) + 'ms'
537
+ subscriptionHash = market['id'] + '@' + channelName
538
+ messageHash = self.get_message_hash('orderbook', market['symbol'])
360
539
  uuid = self.uuid()
361
540
  request: dict = {
362
541
  'id': uuid,
363
- 'dataType': messageHash,
542
+ 'dataType': subscriptionHash,
364
543
  }
365
544
  if marketType == 'swap':
366
545
  request['reqType'] = 'sub'
367
- orderbook = await self.watch(url, messageHash, self.deep_extend(request, query), messageHash)
546
+ subscriptionArgs: dict = {
547
+ 'limit': limit,
548
+ 'interval': interval,
549
+ 'params': params,
550
+ }
551
+ orderbook = await self.watch(url, messageHash, self.deep_extend(request, query), subscriptionHash, subscriptionArgs)
368
552
  return orderbook.limit()
369
553
 
370
554
  def handle_delta(self, bookside, delta):
@@ -399,7 +583,7 @@ class bingx(ccxt.async_support.bingx):
399
583
  #
400
584
  # {
401
585
  # "code": 0,
402
- # "dataType": "BTC-USDT@depth20",
586
+ # "dataType": "BTC-USDT@depth20@100ms", #or "all@depth20@100ms"
403
587
  # "data": {
404
588
  # "bids": [
405
589
  # ['28852.9', "34.2621"],
@@ -408,24 +592,37 @@ class bingx(ccxt.async_support.bingx):
408
592
  # "asks": [
409
593
  # ['28864.9', "23.4079"],
410
594
  # ...
411
- # ]
595
+ # ],
596
+ # "symbol": "BTC-USDT", # self key exists only in "all" subscription
412
597
  # }
413
598
  # }
414
599
  #
415
- data = self.safe_value(message, 'data', [])
416
- messageHash = self.safe_string(message, 'dataType')
417
- marketId = messageHash.split('@')[0]
600
+ data = self.safe_dict(message, 'data', {})
601
+ dataType = self.safe_string(message, 'dataType')
602
+ parts = dataType.split('@')
603
+ firstPart = parts[0]
604
+ isAllEndpoint = (firstPart == 'all')
605
+ marketId = self.safe_string(data, 'symbol', firstPart)
418
606
  isSwap = client.url.find('swap') >= 0
419
607
  marketType = 'swap' if isSwap else 'spot'
420
608
  market = self.safe_market(marketId, None, None, marketType)
421
609
  symbol = market['symbol']
422
- orderbook = self.safe_value(self.orderbooks, symbol)
423
- if orderbook is None:
424
- orderbook = self.order_book()
610
+ if self.safe_value(self.orderbooks, symbol) is None:
611
+ # limit = [5, 10, 20, 50, 100]
612
+ subscriptionHash = dataType
613
+ subscription = client.subscriptions[subscriptionHash]
614
+ limit = self.safe_integer(subscription, 'limit')
615
+ self.orderbooks[symbol] = self.order_book({}, limit)
616
+ orderbook = self.orderbooks[symbol]
425
617
  snapshot = self.parse_order_book(data, symbol, None, 'bids', 'asks', 0, 1)
426
618
  orderbook.reset(snapshot)
427
619
  self.orderbooks[symbol] = orderbook
620
+ messageHash = self.get_message_hash('orderbook', symbol)
428
621
  client.resolve(orderbook, messageHash)
622
+ # resolve for "all"
623
+ if isAllEndpoint:
624
+ messageHashForAll = self.get_message_hash('orderbook')
625
+ client.resolve(orderbook, messageHashForAll)
429
626
 
430
627
  def parse_ws_ohlcv(self, ohlcv, market=None) -> list:
431
628
  #
@@ -496,30 +693,43 @@ class bingx(ccxt.async_support.bingx):
496
693
  # ]
497
694
  # }
498
695
  #
499
- data = self.safe_value(message, 'data', [])
696
+ data = self.safe_list(message, 'data', [])
500
697
  candles = None
501
698
  if isinstance(data, list):
502
699
  candles = data
503
700
  else:
504
- candles = [self.safe_value(data, 'K', [])]
505
- messageHash = self.safe_string(message, 'dataType')
506
- timeframeId = messageHash.split('_')[1]
507
- marketId = messageHash.split('@')[0]
701
+ candles = [self.safe_list(data, 'K', [])]
702
+ dataType = self.safe_string(message, 'dataType')
508
703
  isSwap = client.url.find('swap') >= 0
704
+ parts = dataType.split('@')
705
+ firstPart = parts[0]
706
+ isAllEndpoint = (firstPart == 'all')
707
+ marketId = self.safe_string(message, 's', firstPart)
509
708
  marketType = 'swap' if isSwap else 'spot'
510
709
  market = self.safe_market(marketId, None, None, marketType)
511
710
  symbol = market['symbol']
512
711
  self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
513
- stored = self.safe_value(self.ohlcvs[symbol], timeframeId)
514
- if stored is None:
515
- limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
516
- stored = ArrayCacheByTimestamp(limit)
517
- self.ohlcvs[symbol][timeframeId] = stored
712
+ rawTimeframe = dataType.split('_')[1]
713
+ marketOptions = self.safe_dict(self.options, marketType)
714
+ timeframes = self.safe_dict(marketOptions, 'timeframes', {})
715
+ unifiedTimeframe = self.find_timeframe(rawTimeframe, timeframes)
716
+ if self.safe_value(self.ohlcvs[symbol], rawTimeframe) is None:
717
+ subscriptionHash = dataType
718
+ subscription = client.subscriptions[subscriptionHash]
719
+ limit = self.safe_integer(subscription, 'limit')
720
+ self.ohlcvs[symbol][unifiedTimeframe] = ArrayCacheByTimestamp(limit)
721
+ stored = self.ohlcvs[symbol][unifiedTimeframe]
518
722
  for i in range(0, len(candles)):
519
723
  candle = candles[i]
520
724
  parsed = self.parse_ws_ohlcv(candle, market)
521
725
  stored.append(parsed)
522
- client.resolve(stored, messageHash)
726
+ resolveData = [symbol, unifiedTimeframe, stored]
727
+ messageHash = self.get_message_hash('ohlcv', symbol, unifiedTimeframe)
728
+ client.resolve(resolveData, messageHash)
729
+ # resolve for "all"
730
+ if isAllEndpoint:
731
+ messageHashForAll = self.get_message_hash('ohlcv', None, unifiedTimeframe)
732
+ client.resolve(resolveData, messageHashForAll)
523
733
 
524
734
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
525
735
  """
@@ -541,16 +751,22 @@ class bingx(ccxt.async_support.bingx):
541
751
  raise BadRequest(self.id + ' watchOHLCV is not supported for ' + marketType + ' markets.')
542
752
  options = self.safe_value(self.options, marketType, {})
543
753
  timeframes = self.safe_value(options, 'timeframes', {})
544
- interval = self.safe_string(timeframes, timeframe, timeframe)
545
- messageHash = market['id'] + '@kline_' + interval
754
+ rawTimeframe = self.safe_string(timeframes, timeframe, timeframe)
755
+ messageHash = self.get_message_hash('ohlcv', market['symbol'], timeframe)
756
+ subscriptionHash = market['id'] + '@kline_' + rawTimeframe
546
757
  uuid = self.uuid()
547
758
  request: dict = {
548
759
  'id': uuid,
549
- 'dataType': messageHash,
760
+ 'dataType': subscriptionHash,
550
761
  }
551
762
  if marketType == 'swap':
552
763
  request['reqType'] = 'sub'
553
- ohlcv = await self.watch(url, messageHash, self.extend(request, query), messageHash)
764
+ subscriptionArgs: dict = {
765
+ 'limit': limit,
766
+ 'params': params,
767
+ }
768
+ result = await self.watch(url, messageHash, self.extend(request, query), subscriptionHash, subscriptionArgs)
769
+ ohlcv = result[2]
554
770
  if self.newUpdates:
555
771
  limit = ohlcv.getLimit(symbol, limit)
556
772
  return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
ccxt/pro/bitget.py CHANGED
@@ -939,7 +939,7 @@ class bitget(ccxt.async_support.bitget):
939
939
  type, params = self.handle_market_type_and_params('watchOrders', market, params)
940
940
  subType = None
941
941
  subType, params = self.handle_sub_type_and_params('watchOrders', market, params, 'linear')
942
- if (type == 'spot') and (symbol is None):
942
+ if (type == 'spot' or type == 'margin') and (symbol is None):
943
943
  raise ArgumentsRequired(self.id + ' watchOrders requires a symbol argument for ' + type + ' markets.')
944
944
  if (productType is None) and (type != 'spot') and (symbol is None):
945
945
  messageHash = messageHash + ':' + subType
@@ -955,7 +955,7 @@ class bitget(ccxt.async_support.bitget):
955
955
  subscriptionHash = subscriptionHash + ':' + symbol
956
956
  if isTrigger:
957
957
  subscriptionHash = subscriptionHash + ':stop' # we don't want to re-use the same subscription hash for stop orders
958
- instId = marketId if (type == 'spot') else 'default' # different from other streams here the 'rest' id is required for spot markets, contract markets require default here
958
+ instId = marketId if (type == 'spot' or type == 'margin') else 'default' # different from other streams here the 'rest' id is required for spot markets, contract markets require default here
959
959
  channel = 'orders-algo' if isTrigger else 'orders'
960
960
  marginMode = None
961
961
  marginMode, params = self.handle_margin_mode_and_params('watchOrders', params)
@@ -1011,9 +1011,10 @@ class bitget(ccxt.async_support.bitget):
1011
1011
  # "ts": 1701923982497
1012
1012
  # }
1013
1013
  #
1014
- arg = self.safe_value(message, 'arg', {})
1014
+ arg = self.safe_dict(message, 'arg', {})
1015
1015
  channel = self.safe_string(arg, 'channel')
1016
1016
  instType = self.safe_string(arg, 'instType')
1017
+ argInstId = self.safe_string(arg, 'instId')
1017
1018
  marketType = None
1018
1019
  if instType == 'SPOT':
1019
1020
  marketType = 'spot'
@@ -1035,7 +1036,7 @@ class bitget(ccxt.async_support.bitget):
1035
1036
  marketSymbols: dict = {}
1036
1037
  for i in range(0, len(data)):
1037
1038
  order = data[i]
1038
- marketId = self.safe_string(order, 'instId')
1039
+ marketId = self.safe_string(order, 'instId', argInstId)
1039
1040
  market = self.safe_market(marketId, None, None, marketType)
1040
1041
  parsed = self.parse_ws_order(order, market)
1041
1042
  stored.append(parsed)
@@ -1228,7 +1229,7 @@ class bitget(ccxt.async_support.bitget):
1228
1229
  filledAmount = self.safe_string(order, 'baseVolume')
1229
1230
  totalAmount = self.safe_string(order, 'size')
1230
1231
  cost = self.safe_string(order, 'fillNotionalUsd')
1231
- remaining = self.omit_zero(Precise.string_sub(totalAmount, totalFilled))
1232
+ remaining = Precise.string_sub(totalAmount, totalFilled)
1232
1233
  return self.safe_order({
1233
1234
  'info': order,
1234
1235
  'symbol': symbol,
ccxt/pro/bitrue.py CHANGED
@@ -341,12 +341,11 @@ class bitrue(ccxt.async_support.bitrue):
341
341
  symbol = market['symbol']
342
342
  timestamp = self.safe_integer(message, 'ts')
343
343
  tick = self.safe_value(message, 'tick', {})
344
- orderbook = self.safe_value(self.orderbooks, symbol)
345
- if orderbook is None:
346
- orderbook = self.order_book()
344
+ if not (symbol in self.orderbooks):
345
+ self.orderbooks[symbol] = self.order_book()
346
+ orderbook = self.orderbooks[symbol]
347
347
  snapshot = self.parse_order_book(tick, symbol, timestamp, 'buys', 'asks')
348
348
  orderbook.reset(snapshot)
349
- self.orderbooks[symbol] = orderbook
350
349
  messageHash = 'orderbook:' + symbol
351
350
  client.resolve(orderbook, messageHash)
352
351
 
ccxt/pro/currencycom.py CHANGED
@@ -441,16 +441,17 @@ class currencycom(ccxt.async_support.currencycom):
441
441
  destination = 'depthMarketData.subscribe'
442
442
  messageHash = destination + ':' + symbol
443
443
  timestamp = self.safe_integer(data, 'ts')
444
- orderbook = self.safe_value(self.orderbooks, symbol)
445
- if orderbook is None:
446
- orderbook = self.order_book()
444
+ # orderbook = self.safe_value(self.orderbooks, symbol)
445
+ if not (symbol in self.orderbooks):
446
+ self.orderbooks[symbol] = self.order_book()
447
+ orderbook = self.orderbooks[symbol]
447
448
  orderbook.reset({
448
449
  'symbol': symbol,
449
450
  'timestamp': timestamp,
450
451
  'datetime': self.iso8601(timestamp),
451
452
  })
452
- bids = self.safe_value(data, 'bid', {})
453
- asks = self.safe_value(data, 'ofr', {})
453
+ bids = self.safe_dict(data, 'bid', {})
454
+ asks = self.safe_dict(data, 'ofr', {})
454
455
  self.handle_deltas(orderbook['bids'], bids)
455
456
  self.handle_deltas(orderbook['asks'], asks)
456
457
  self.orderbooks[symbol] = orderbook
ccxt/pro/exmo.py CHANGED
@@ -495,17 +495,16 @@ class exmo(ccxt.async_support.exmo):
495
495
  orderBook = self.safe_value(message, 'data', {})
496
496
  messageHash = 'orderbook:' + symbol
497
497
  timestamp = self.safe_integer(message, 'ts')
498
- orderbook = self.safe_value(self.orderbooks, symbol)
499
- if orderbook is None:
500
- orderbook = self.order_book({})
501
- self.orderbooks[symbol] = orderbook
498
+ if not (symbol in self.orderbooks):
499
+ self.orderbooks[symbol] = self.order_book({})
500
+ orderbook = self.orderbooks[symbol]
502
501
  event = self.safe_string(message, 'event')
503
502
  if event == 'snapshot':
504
503
  snapshot = self.parse_order_book(orderBook, symbol, timestamp, 'bid', 'ask')
505
504
  orderbook.reset(snapshot)
506
505
  else:
507
- asks = self.safe_value(orderBook, 'ask', [])
508
- bids = self.safe_value(orderBook, 'bid', [])
506
+ asks = self.safe_list(orderBook, 'ask', [])
507
+ bids = self.safe_list(orderBook, 'bid', [])
509
508
  self.handle_deltas(orderbook['asks'], asks)
510
509
  self.handle_deltas(orderbook['bids'], bids)
511
510
  orderbook['timestamp'] = timestamp
ccxt/pro/gemini.py CHANGED
@@ -366,9 +366,10 @@ class gemini(ccxt.async_support.gemini):
366
366
  market = self.safe_market(marketId)
367
367
  symbol = market['symbol']
368
368
  messageHash = 'orderbook:' + symbol
369
- orderbook = self.safe_value(self.orderbooks, symbol)
370
- if orderbook is None:
371
- orderbook = self.order_book()
369
+ # orderbook = self.safe_value(self.orderbooks, symbol)
370
+ if not (symbol in self.orderbooks):
371
+ self.orderbooks[symbol] = self.order_book()
372
+ orderbook = self.orderbooks[symbol]
372
373
  for i in range(0, len(changes)):
373
374
  delta = changes[i]
374
375
  price = self.safe_number(delta, 1)
@@ -176,22 +176,22 @@ class independentreserve(ccxt.async_support.independentreserve):
176
176
  base = self.safe_currency_code(baseId)
177
177
  quote = self.safe_currency_code(quoteId)
178
178
  symbol = base + '/' + quote
179
- orderBook = self.safe_value(message, 'Data', {})
179
+ orderBook = self.safe_dict(message, 'Data', {})
180
180
  messageHash = 'orderbook:' + symbol + ':' + depth
181
181
  subscription = self.safe_value(client.subscriptions, messageHash, {})
182
182
  receivedSnapshot = self.safe_bool(subscription, 'receivedSnapshot', False)
183
183
  timestamp = self.safe_integer(message, 'Time')
184
- orderbook = self.safe_value(self.orderbooks, symbol)
185
- if orderbook is None:
186
- orderbook = self.order_book({})
187
- self.orderbooks[symbol] = orderbook
184
+ # orderbook = self.safe_value(self.orderbooks, symbol)
185
+ if not (symbol in self.orderbooks):
186
+ self.orderbooks[symbol] = self.order_book({})
187
+ orderbook = self.orderbooks[symbol]
188
188
  if event == 'OrderBookSnapshot':
189
189
  snapshot = self.parse_order_book(orderBook, symbol, timestamp, 'Bids', 'Offers', 'Price', 'Volume')
190
190
  orderbook.reset(snapshot)
191
191
  subscription['receivedSnapshot'] = True
192
192
  else:
193
- asks = self.safe_value(orderBook, 'Offers', [])
194
- bids = self.safe_value(orderBook, 'Bids', [])
193
+ asks = self.safe_list(orderBook, 'Offers', [])
194
+ bids = self.safe_list(orderBook, 'Bids', [])
195
195
  self.handle_deltas(orderbook['asks'], asks)
196
196
  self.handle_deltas(orderbook['bids'], bids)
197
197
  orderbook['timestamp'] = timestamp
ccxt/pro/lbank.py CHANGED
@@ -751,10 +751,10 @@ class lbank(ccxt.async_support.lbank):
751
751
  orderBook = self.safe_value(message, 'depth', message)
752
752
  datetime = self.safe_string(message, 'TS')
753
753
  timestamp = self.parse8601(datetime)
754
- orderbook = self.safe_value(self.orderbooks, symbol)
755
- if orderbook is None:
756
- orderbook = self.order_book({})
757
- self.orderbooks[symbol] = orderbook
754
+ # orderbook = self.safe_value(self.orderbooks, symbol)
755
+ if not (symbol in self.orderbooks):
756
+ self.orderbooks[symbol] = self.order_book({})
757
+ orderbook = self.orderbooks[symbol]
758
758
  snapshot = self.parse_order_book(orderBook, symbol, timestamp, 'bids', 'asks')
759
759
  orderbook.reset(snapshot)
760
760
  messageHash = 'orderbook:' + symbol
ccxt/pro/phemex.py CHANGED
@@ -677,11 +677,11 @@ class phemex(ccxt.async_support.phemex):
677
677
  self.orderbooks[symbol] = orderbook
678
678
  client.resolve(orderbook, messageHash)
679
679
  else:
680
- orderbook = self.safe_value(self.orderbooks, symbol)
681
- if orderbook is not None:
682
- changes = self.safe_value_2(message, 'book', 'orderbook_p', {})
683
- asks = self.safe_value(changes, 'asks', [])
684
- bids = self.safe_value(changes, 'bids', [])
680
+ if symbol in self.orderbooks:
681
+ orderbook = self.orderbooks[symbol]
682
+ changes = self.safe_dict_2(message, 'book', 'orderbook_p', {})
683
+ asks = self.safe_list(changes, 'asks', [])
684
+ bids = self.safe_list(changes, 'bids', [])
685
685
  self.custom_handle_deltas(orderbook['asks'], asks, market)
686
686
  self.custom_handle_deltas(orderbook['bids'], bids, market)
687
687
  orderbook['nonce'] = nonce
ccxt/pro/probit.py CHANGED
@@ -428,10 +428,10 @@ class probit(ccxt.async_support.probit):
428
428
  symbol = self.safe_symbol(marketId)
429
429
  dataBySide = self.group_by(orderBook, 'side')
430
430
  messageHash = 'orderbook:' + symbol
431
- orderbook = self.safe_value(self.orderbooks, symbol)
432
- if orderbook is None:
433
- orderbook = self.order_book({})
434
- self.orderbooks[symbol] = orderbook
431
+ # orderbook = self.safe_value(self.orderbooks, symbol)
432
+ if not (symbol in self.orderbooks):
433
+ self.orderbooks[symbol] = self.order_book({})
434
+ orderbook = self.orderbooks[symbol]
435
435
  reset = self.safe_bool(message, 'reset', False)
436
436
  if reset:
437
437
  snapshot = self.parse_order_book(dataBySide, symbol, None, 'buy', 'sell', 'price', 'quantity')