ccxt 4.2.83__py2.py3-none-any.whl → 4.2.85__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 (152) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bybit.py +1 -1
  3. ccxt/ace.py +5 -5
  4. ccxt/ascendex.py +8 -8
  5. ccxt/async_support/__init__.py +1 -1
  6. ccxt/async_support/ace.py +5 -5
  7. ccxt/async_support/ascendex.py +8 -8
  8. ccxt/async_support/base/exchange.py +3 -27
  9. ccxt/async_support/bigone.py +12 -12
  10. ccxt/async_support/binance.py +20 -32
  11. ccxt/async_support/bingx.py +12 -9
  12. ccxt/async_support/bit2c.py +1 -1
  13. ccxt/async_support/bitbank.py +8 -8
  14. ccxt/async_support/bitbns.py +5 -5
  15. ccxt/async_support/bitfinex.py +1 -1
  16. ccxt/async_support/bitfinex2.py +1 -1
  17. ccxt/async_support/bitget.py +39 -28
  18. ccxt/async_support/bithumb.py +5 -5
  19. ccxt/async_support/bitmart.py +16 -16
  20. ccxt/async_support/bitopro.py +1 -1
  21. ccxt/async_support/bitrue.py +4 -4
  22. ccxt/async_support/bitso.py +5 -5
  23. ccxt/async_support/bitstamp.py +1 -1
  24. ccxt/async_support/bitteam.py +8 -8
  25. ccxt/async_support/bl3p.py +1 -1
  26. ccxt/async_support/btcturk.py +6 -6
  27. ccxt/async_support/bybit.py +34 -87
  28. ccxt/async_support/coincheck.py +4 -4
  29. ccxt/async_support/coinex.py +12 -13
  30. ccxt/async_support/coinlist.py +7 -7
  31. ccxt/async_support/coinmate.py +4 -4
  32. ccxt/async_support/coinmetro.py +3 -3
  33. ccxt/async_support/coinone.py +5 -5
  34. ccxt/async_support/coinspot.py +2 -2
  35. ccxt/async_support/cryptocom.py +17 -17
  36. ccxt/async_support/currencycom.py +1 -1
  37. ccxt/async_support/delta.py +0 -8
  38. ccxt/async_support/deribit.py +16 -80
  39. ccxt/async_support/digifinex.py +8 -8
  40. ccxt/async_support/exmo.py +8 -8
  41. ccxt/async_support/gate.py +0 -8
  42. ccxt/async_support/hitbtc.py +5 -4
  43. ccxt/async_support/hollaex.py +7 -7
  44. ccxt/async_support/htx.py +12 -34
  45. ccxt/async_support/huobijp.py +3 -3
  46. ccxt/async_support/idex.py +2 -2
  47. ccxt/async_support/independentreserve.py +2 -2
  48. ccxt/async_support/indodax.py +2 -2
  49. ccxt/async_support/kraken.py +8 -8
  50. ccxt/async_support/krakenfutures.py +6 -6
  51. ccxt/async_support/kucoin.py +14 -2
  52. ccxt/async_support/kucoinfutures.py +8 -8
  53. ccxt/async_support/kuna.py +16 -16
  54. ccxt/async_support/latoken.py +2 -2
  55. ccxt/async_support/lbank.py +10 -10
  56. ccxt/async_support/luno.py +4 -4
  57. ccxt/async_support/mercado.py +5 -5
  58. ccxt/async_support/mexc.py +6 -6
  59. ccxt/async_support/ndax.py +1 -1
  60. ccxt/async_support/novadax.py +9 -9
  61. ccxt/async_support/oceanex.py +7 -7
  62. ccxt/async_support/okcoin.py +13 -13
  63. ccxt/async_support/okx.py +23 -31
  64. ccxt/async_support/onetrading.py +4 -4
  65. ccxt/async_support/p2b.py +7 -7
  66. ccxt/async_support/phemex.py +12 -12
  67. ccxt/async_support/poloniexfutures.py +5 -5
  68. ccxt/async_support/probit.py +11 -11
  69. ccxt/async_support/timex.py +7 -7
  70. ccxt/async_support/tokocrypto.py +9 -9
  71. ccxt/async_support/wavesexchange.py +3 -3
  72. ccxt/async_support/whitebit.py +5 -5
  73. ccxt/async_support/woo.py +1 -1
  74. ccxt/async_support/zaif.py +1 -1
  75. ccxt/async_support/zonda.py +7 -7
  76. ccxt/base/exchange.py +66 -23
  77. ccxt/bigone.py +12 -12
  78. ccxt/binance.py +20 -32
  79. ccxt/bingx.py +12 -9
  80. ccxt/bit2c.py +1 -1
  81. ccxt/bitbank.py +8 -8
  82. ccxt/bitbns.py +5 -5
  83. ccxt/bitfinex.py +1 -1
  84. ccxt/bitfinex2.py +1 -1
  85. ccxt/bitget.py +39 -28
  86. ccxt/bithumb.py +5 -5
  87. ccxt/bitmart.py +16 -16
  88. ccxt/bitopro.py +1 -1
  89. ccxt/bitrue.py +4 -4
  90. ccxt/bitso.py +5 -5
  91. ccxt/bitstamp.py +1 -1
  92. ccxt/bitteam.py +8 -8
  93. ccxt/bl3p.py +1 -1
  94. ccxt/btcturk.py +6 -6
  95. ccxt/bybit.py +34 -87
  96. ccxt/coincheck.py +4 -4
  97. ccxt/coinex.py +12 -13
  98. ccxt/coinlist.py +7 -7
  99. ccxt/coinmate.py +4 -4
  100. ccxt/coinmetro.py +3 -3
  101. ccxt/coinone.py +5 -5
  102. ccxt/coinspot.py +2 -2
  103. ccxt/cryptocom.py +17 -17
  104. ccxt/currencycom.py +1 -1
  105. ccxt/delta.py +0 -8
  106. ccxt/deribit.py +16 -80
  107. ccxt/digifinex.py +8 -8
  108. ccxt/exmo.py +8 -8
  109. ccxt/gate.py +0 -8
  110. ccxt/hitbtc.py +5 -4
  111. ccxt/hollaex.py +7 -7
  112. ccxt/htx.py +12 -34
  113. ccxt/huobijp.py +3 -3
  114. ccxt/idex.py +2 -2
  115. ccxt/independentreserve.py +2 -2
  116. ccxt/indodax.py +2 -2
  117. ccxt/kraken.py +8 -8
  118. ccxt/krakenfutures.py +6 -6
  119. ccxt/kucoin.py +14 -2
  120. ccxt/kucoinfutures.py +8 -8
  121. ccxt/kuna.py +16 -16
  122. ccxt/latoken.py +2 -2
  123. ccxt/lbank.py +10 -10
  124. ccxt/luno.py +4 -4
  125. ccxt/mercado.py +5 -5
  126. ccxt/mexc.py +6 -6
  127. ccxt/ndax.py +1 -1
  128. ccxt/novadax.py +9 -9
  129. ccxt/oceanex.py +7 -7
  130. ccxt/okcoin.py +13 -13
  131. ccxt/okx.py +23 -31
  132. ccxt/onetrading.py +4 -4
  133. ccxt/p2b.py +7 -7
  134. ccxt/phemex.py +12 -12
  135. ccxt/poloniexfutures.py +5 -5
  136. ccxt/pro/__init__.py +1 -1
  137. ccxt/pro/binance.py +150 -112
  138. ccxt/pro/kucoin.py +6 -7
  139. ccxt/pro/okx.py +12 -1
  140. ccxt/probit.py +11 -11
  141. ccxt/test/base/test_market.py +3 -0
  142. ccxt/timex.py +7 -7
  143. ccxt/tokocrypto.py +9 -9
  144. ccxt/wavesexchange.py +3 -3
  145. ccxt/whitebit.py +5 -5
  146. ccxt/woo.py +1 -1
  147. ccxt/zaif.py +1 -1
  148. ccxt/zonda.py +7 -7
  149. {ccxt-4.2.83.dist-info → ccxt-4.2.85.dist-info}/METADATA +4 -4
  150. {ccxt-4.2.83.dist-info → ccxt-4.2.85.dist-info}/RECORD +152 -152
  151. {ccxt-4.2.83.dist-info → ccxt-4.2.85.dist-info}/WHEEL +0 -0
  152. {ccxt-4.2.83.dist-info → ccxt-4.2.85.dist-info}/top_level.txt +0 -0
ccxt/pro/binance.py CHANGED
@@ -12,6 +12,7 @@ from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import ArgumentsRequired
14
14
  from ccxt.base.errors import BadRequest
15
+ from ccxt.base.errors import NotSupported
15
16
  from ccxt.base.precise import Precise
16
17
 
17
18
 
@@ -22,6 +23,7 @@ class binance(ccxt.async_support.binance):
22
23
  'has': {
23
24
  'ws': True,
24
25
  'watchBalance': True,
26
+ 'watchBidsAsks': True,
25
27
  'watchMyTrades': True,
26
28
  'watchOHLCV': True,
27
29
  'watchOHLCVForSymbols': False,
@@ -103,10 +105,10 @@ class binance(ccxt.async_support.binance):
103
105
  'name': 'trade', # 'trade' or 'aggTrade'
104
106
  },
105
107
  'watchTicker': {
106
- 'name': 'ticker', # ticker = 1000ms L1+OHLCV, bookTicker = real-time L1
108
+ 'name': 'ticker', # ticker or miniTicker or ticker_<window_size>
107
109
  },
108
110
  'watchTickers': {
109
- 'name': 'ticker', # ticker or miniTicker or bookTicker
111
+ 'name': 'ticker', # ticker or miniTicker or ticker_<window_size>
110
112
  },
111
113
  'watchOHLCV': {
112
114
  'name': 'kline', # or indexPriceKline or markPriceKline(coin-m futures)
@@ -127,6 +129,15 @@ class binance(ccxt.async_support.binance):
127
129
  'ws': {
128
130
  'cost': 5,
129
131
  },
132
+ 'tickerChannelsMap': {
133
+ '24hrTicker': 'ticker',
134
+ '24hrMiniTicker': 'miniTicker',
135
+ # rolling window tickers
136
+ '1hTicker': 'ticker_1h',
137
+ '4hTicker': 'ticker_4h',
138
+ '1dTicker': 'ticker_1d',
139
+ 'bookTicker': 'bookTicker',
140
+ },
130
141
  },
131
142
  })
132
143
 
@@ -867,33 +878,13 @@ class binance(ccxt.async_support.binance):
867
878
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
868
879
  :param str symbol: unified symbol of the market to fetch the ticker for
869
880
  :param dict [params]: extra parameters specific to the exchange API endpoint
870
- :param str [params.name]: stream to use can be ticker or bookTicker
881
+ :param str [params.name]: stream to use can be ticker or miniTicker
871
882
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
872
883
  """
873
884
  await self.load_markets()
874
- market = self.market(symbol)
875
- marketId = market['lowercaseId']
876
- type = market['type']
877
- if market['contract']:
878
- type = 'future' if market['linear'] else 'delivery'
879
- options = self.safe_value(self.options, 'watchTicker', {})
880
- name = self.safe_string(options, 'name', 'ticker')
881
- name = self.safe_string(params, 'name', name)
882
- params = self.omit(params, 'name')
883
- messageHash = marketId + '@' + name
884
- url = self.urls['api']['ws'][type] + '/' + self.stream(type, messageHash)
885
- requestId = self.request_id(url)
886
- request = {
887
- 'method': 'SUBSCRIBE',
888
- 'params': [
889
- messageHash,
890
- ],
891
- 'id': requestId,
892
- }
893
- subscribe = {
894
- 'id': requestId,
895
- }
896
- return await self.watch(url, messageHash, self.extend(request, params), messageHash, subscribe)
885
+ symbol = self.symbol(symbol)
886
+ tickers = await self.watch_tickers([symbol], self.extend(params, {'callerMethodName': 'watchTicker'}))
887
+ return tickers[symbol]
897
888
 
898
889
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
899
890
  """
@@ -902,52 +893,89 @@ class binance(ccxt.async_support.binance):
902
893
  :param dict [params]: extra parameters specific to the exchange API endpoint
903
894
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
904
895
  """
896
+ channelName = None
897
+ channelName, params = self.handle_option_and_params(params, 'watchTickers', 'name', 'ticker')
898
+ if channelName == 'bookTicker':
899
+ raise BadRequest(self.id + ' deprecation notice - to subscribe for bids-asks, use watch_bids_asks() method instead')
900
+ newTickers = await self.watch_multi_ticker_helper('watchTickers', channelName, symbols, params)
901
+ if self.newUpdates:
902
+ return newTickers
903
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
904
+
905
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
906
+ """
907
+ :see: https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-book-ticker-streams
908
+ :see: https://binance-docs.github.io/apidocs/futures/en/#all-book-tickers-stream
909
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#all-book-tickers-stream
910
+ watches best bid & ask for symbols
911
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
912
+ :param dict [params]: extra parameters specific to the exchange API endpoint
913
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
914
+ """
915
+ result = await self.watch_multi_ticker_helper('watchBidsAsks', 'bookTicker', symbols, params)
916
+ if self.newUpdates:
917
+ return result
918
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
919
+
920
+ async def watch_multi_ticker_helper(self, methodName, channelName: str, symbols: Strings = None, params={}):
905
921
  await self.load_markets()
906
- symbols = self.market_symbols(symbols, None, True, True, True)
907
- marketIds = self.market_ids(symbols)
908
- market = None
909
- type = None
910
- if symbols is not None:
911
- market = self.market(symbols[0])
912
- type, params = self.handle_market_type_and_params('watchTickers', market, params)
922
+ symbols = self.market_symbols(symbols, None, True, False, True)
923
+ firstMarket = None
924
+ marketType = None
925
+ symbolsDefined = (symbols is not None)
926
+ if symbolsDefined:
927
+ firstMarket = self.market(symbols[0])
928
+ marketType, params = self.handle_market_type_and_params(methodName, firstMarket, params)
913
929
  subType = None
914
- subType, params = self.handle_sub_type_and_params('watchTickers', market, params)
915
- if self.isLinear(type, subType):
916
- type = 'future'
917
- elif self.isInverse(type, subType):
918
- type = 'delivery'
919
- options = self.safe_value(self.options, 'watchTickers', {})
920
- name = self.safe_string(options, 'name', 'ticker')
921
- name = self.safe_string(params, 'name', name)
922
- params = self.omit(params, 'name')
923
- wsParams = []
924
- messageHash = 'tickers'
925
- if symbols is not None:
926
- messageHash = 'tickers::' + ','.join(symbols)
927
- if name == 'bookTicker':
928
- if marketIds is None:
929
- raise ArgumentsRequired(self.id + ' watchTickers() requires symbols for bookTicker')
930
- # simulate watchTickers with subscribe multiple individual bookTicker topic
931
- for i in range(0, len(marketIds)):
932
- wsParams.append(marketIds[i].lower() + '@bookTicker')
930
+ subType, params = self.handle_sub_type_and_params(methodName, firstMarket, params)
931
+ rawMarketType = None
932
+ if self.isLinear(marketType, subType):
933
+ rawMarketType = 'future'
934
+ elif self.isInverse(marketType, subType):
935
+ rawMarketType = 'delivery'
936
+ elif marketType == 'spot':
937
+ rawMarketType = marketType
933
938
  else:
934
- wsParams = [
935
- '!' + name + '@arr',
936
- ]
937
- url = self.urls['api']['ws'][type] + '/' + self.stream(type, messageHash)
939
+ raise NotSupported(self.id + ' ' + methodName + '() does not support options markets')
940
+ isBidAsk = (channelName == 'bookTicker')
941
+ subscriptionArgs = []
942
+ messageHashes = []
943
+ if symbolsDefined:
944
+ for i in range(0, len(symbols)):
945
+ symbol = symbols[i]
946
+ market = self.market(symbol)
947
+ subscriptionArgs.append(market['lowercaseId'] + '@' + channelName)
948
+ messageHashes.append(self.get_message_hash(channelName, market['symbol'], isBidAsk))
949
+ else:
950
+ if isBidAsk:
951
+ if marketType == 'spot':
952
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() requires symbols for self channel for spot markets')
953
+ subscriptionArgs.append('!' + channelName)
954
+ else:
955
+ subscriptionArgs.append('!' + channelName + '@arr')
956
+ messageHashes.append(self.get_message_hash(channelName, None, isBidAsk))
957
+ streamHash = channelName
958
+ if symbolsDefined:
959
+ streamHash = channelName + '::' + ','.join(symbols)
960
+ url = self.urls['api']['ws'][rawMarketType] + '/' + self.stream(rawMarketType, streamHash)
938
961
  requestId = self.request_id(url)
939
962
  request = {
940
963
  'method': 'SUBSCRIBE',
941
- 'params': wsParams,
964
+ 'params': subscriptionArgs,
942
965
  'id': requestId,
943
966
  }
944
967
  subscribe = {
945
968
  'id': requestId,
946
969
  }
947
- newTickers = await self.watch(url, messageHash, self.extend(request, params), messageHash, subscribe)
948
- if self.newUpdates:
949
- return newTickers
950
- return self.filter_by_array(self.tickers, 'symbol', symbols)
970
+ result = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), subscriptionArgs, subscribe)
971
+ # for efficiency, we have two type of returned structure here - if symbols array was provided, then individual
972
+ # ticker dict comes in, otherwise all-tickers dict comes in
973
+ if not symbolsDefined:
974
+ return result
975
+ else:
976
+ newDict = {}
977
+ newDict[result['symbol']] = result
978
+ return newDict
951
979
 
952
980
  def parse_ws_ticker(self, message, marketType):
953
981
  #
@@ -1028,11 +1056,24 @@ class binance(ccxt.async_support.binance):
1028
1056
  'info': message,
1029
1057
  }, market)
1030
1058
 
1031
- def handle_ticker(self, client: Client, message):
1059
+ def handle_bids_asks(self, client: Client, message):
1060
+ #
1061
+ # arrives one symbol dict or array of symbol dicts
1062
+ #
1063
+ # {
1064
+ # "u": 7488717758,
1065
+ # "s": "BTCUSDT",
1066
+ # "b": "28621.74000000",
1067
+ # "B": "1.43278800",
1068
+ # "a": "28621.75000000",
1069
+ # "A": "2.52500800"
1070
+ # }
1071
+ #
1072
+ self.handle_tickers_and_bids_asks(client, message, 'bidasks')
1073
+
1074
+ def handle_tickers(self, client: Client, message):
1032
1075
  #
1033
- # 24hr rolling window ticker statistics for a single symbol
1034
- # These are NOT the statistics of the UTC day, but a 24hr rolling window for the previous 24hrs
1035
- # Update Speed 1000ms
1076
+ # arrives one symbol dict or array of symbol dicts
1036
1077
  #
1037
1078
  # {
1038
1079
  # "e": "24hrTicker", # event type
@@ -1060,34 +1101,14 @@ class binance(ccxt.async_support.binance):
1060
1101
  # "n": 163222, # total number of trades
1061
1102
  # }
1062
1103
  #
1063
- event = self.safe_string(message, 'e', 'bookTicker')
1064
- if event == '24hrTicker':
1065
- event = 'ticker'
1066
- elif event == '24hrMiniTicker':
1067
- event = 'miniTicker'
1068
- wsMarketId = self.safe_string_lower(message, 's')
1069
- messageHash = wsMarketId + '@' + event
1070
- isSpot = ((client.url.find('/stream') > -1) or (client.url.find('/testnet.binance') > -1))
1071
- marketType = 'spot' if (isSpot) else 'contract'
1072
- result = self.parse_ws_ticker(message, marketType)
1073
- symbol = result['symbol']
1074
- self.tickers[symbol] = result
1075
- client.resolve(result, messageHash)
1076
- if event == 'bookTicker':
1077
- # watch bookTickers
1078
- client.resolve(result, '!' + 'bookTicker@arr')
1079
- messageHashes = self.find_message_hashes(client, 'tickers::')
1080
- for i in range(0, len(messageHashes)):
1081
- currentMessageHash = messageHashes[i]
1082
- parts = currentMessageHash.split('::')
1083
- symbolsString = parts[1]
1084
- symbols = symbolsString.split(',')
1085
- if self.in_array(symbol, symbols):
1086
- client.resolve(result, currentMessageHash)
1104
+ self.handle_tickers_and_bids_asks(client, message, 'tickers')
1087
1105
 
1088
- def handle_tickers(self, client: Client, message):
1106
+ def handle_tickers_and_bids_asks(self, client: Client, message, methodType):
1089
1107
  isSpot = ((client.url.find('/stream') > -1) or (client.url.find('/testnet.binance') > -1))
1090
1108
  marketType = 'spot' if (isSpot) else 'contract'
1109
+ isBidAsk = (methodType == 'bidasks')
1110
+ channelName = None
1111
+ resolvedMessageHashes = []
1091
1112
  rawTickers = []
1092
1113
  newTickers = {}
1093
1114
  if isinstance(message, list):
@@ -1096,22 +1117,34 @@ class binance(ccxt.async_support.binance):
1096
1117
  rawTickers.append(message)
1097
1118
  for i in range(0, len(rawTickers)):
1098
1119
  ticker = rawTickers[i]
1099
- result = self.parse_ws_ticker(ticker, marketType)
1100
- symbol = result['symbol']
1101
- self.tickers[symbol] = result
1102
- newTickers[symbol] = result
1103
- messageHashes = self.find_message_hashes(client, 'tickers::')
1104
- for i in range(0, len(messageHashes)):
1105
- messageHash = messageHashes[i]
1106
- parts = messageHash.split('::')
1107
- symbolsString = parts[1]
1108
- symbols = symbolsString.split(',')
1109
- tickers = self.filter_by_array(newTickers, 'symbol', symbols)
1110
- tickersSymbols = list(tickers.keys())
1111
- numTickers = len(tickersSymbols)
1112
- if numTickers > 0:
1113
- client.resolve(tickers, messageHash)
1114
- client.resolve(newTickers, 'tickers')
1120
+ event = self.safe_string(ticker, 'e')
1121
+ if isBidAsk:
1122
+ event = 'bookTicker' # in `handleMessage`, bookTicker doesn't have identifier, so manually set here
1123
+ channelName = self.safe_string(self.options['tickerChannelsMap'], event, event)
1124
+ if channelName is None:
1125
+ continue
1126
+ parsedTicker = self.parse_ws_ticker(ticker, marketType)
1127
+ symbol = parsedTicker['symbol']
1128
+ newTickers[symbol] = parsedTicker
1129
+ if isBidAsk:
1130
+ self.bidsasks[symbol] = parsedTicker
1131
+ else:
1132
+ self.tickers[symbol] = parsedTicker
1133
+ messageHash = self.get_message_hash(channelName, symbol, isBidAsk)
1134
+ resolvedMessageHashes.append(messageHash)
1135
+ client.resolve(parsedTicker, messageHash)
1136
+ # resolve batch endpoint
1137
+ length = len(resolvedMessageHashes)
1138
+ if length > 0:
1139
+ batchMessageHash = self.get_message_hash(channelName, None, isBidAsk)
1140
+ client.resolve(newTickers, batchMessageHash)
1141
+
1142
+ def get_message_hash(self, channelName: str, symbol: Str, isBidAsk: bool):
1143
+ prefix = 'bidask' if isBidAsk else 'ticker'
1144
+ if symbol is not None:
1145
+ return prefix + ':' + channelName + '@' + symbol
1146
+ else:
1147
+ return prefix + 's' + ':' + channelName
1115
1148
 
1116
1149
  def sign_params(self, params={}):
1117
1150
  self.check_required_credentials()
@@ -2741,11 +2774,17 @@ class binance(ccxt.async_support.binance):
2741
2774
  'kline': self.handle_ohlcv,
2742
2775
  'markPrice_kline': self.handle_ohlcv,
2743
2776
  'indexPrice_kline': self.handle_ohlcv,
2777
+ '1hTicker@arr': self.handle_tickers,
2778
+ '4hTicker@arr': self.handle_tickers,
2779
+ '1dTicker@arr': self.handle_tickers,
2744
2780
  '24hrTicker@arr': self.handle_tickers,
2745
2781
  '24hrMiniTicker@arr': self.handle_tickers,
2746
- '24hrTicker': self.handle_ticker,
2747
- '24hrMiniTicker': self.handle_ticker,
2748
- 'bookTicker': self.handle_ticker,
2782
+ '1hTicker': self.handle_tickers,
2783
+ '4hTicker': self.handle_tickers,
2784
+ '1dTicker': self.handle_tickers,
2785
+ '24hrTicker': self.handle_tickers,
2786
+ '24hrMiniTicker': self.handle_tickers,
2787
+ 'bookTicker': self.handle_bids_asks, # there is no "bookTicker@arr" endpoint
2749
2788
  'outboundAccountPosition': self.handle_balance,
2750
2789
  'balanceUpdate': self.handle_balance,
2751
2790
  'ACCOUNT_UPDATE': self.handle_acount_update,
@@ -2773,8 +2812,7 @@ class binance(ccxt.async_support.binance):
2773
2812
  # "A": "2.52500800"
2774
2813
  # }
2775
2814
  #
2776
- if event is None:
2777
- self.handle_ticker(client, message)
2778
- self.handle_tickers(client, message)
2815
+ if event is None and ('a' in message) and ('b' in message):
2816
+ self.handle_bids_asks(client, message)
2779
2817
  else:
2780
2818
  method(client, message)
ccxt/pro/kucoin.py CHANGED
@@ -824,17 +824,16 @@ class kucoin(ccxt.async_support.kucoin):
824
824
  return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
825
825
 
826
826
  def handle_my_trade(self, client: Client, message):
827
- trades = self.myTrades
828
- if trades is None:
827
+ if self.myTrades is None:
829
828
  limit = self.safe_integer(self.options, 'tradesLimit', 1000)
830
- trades = ArrayCacheBySymbolById(limit)
831
- data = self.safe_value(message, 'data')
829
+ self.myTrades = ArrayCacheBySymbolById(limit)
830
+ data = self.safe_dict(message, 'data')
832
831
  parsed = self.parse_ws_trade(data)
833
- trades.append(parsed)
832
+ self.myTrades.append(parsed)
834
833
  messageHash = 'myTrades'
835
- client.resolve(trades, messageHash)
834
+ client.resolve(self.myTrades, messageHash)
836
835
  symbolSpecificMessageHash = messageHash + ':' + parsed['symbol']
837
- client.resolve(trades, symbolSpecificMessageHash)
836
+ client.resolve(self.myTrades, symbolSpecificMessageHash)
838
837
 
839
838
  def parse_ws_trade(self, trade, market=None):
840
839
  #
ccxt/pro/okx.py CHANGED
@@ -459,7 +459,7 @@ class okx(ccxt.async_support.okx):
459
459
  """
460
460
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
461
461
  :param str[] symbols: unified array of symbols
462
- :param int [limit]: the maximum amount of order book entries to return
462
+ :param int [limit]: 1,5, 400, 50(l2-tbt, vip4+) or 40000(vip5+) the maximum amount of order book entries to return
463
463
  :param dict [params]: extra parameters specific to the exchange API endpoint
464
464
  :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
465
465
  """
@@ -467,6 +467,17 @@ class okx(ccxt.async_support.okx):
467
467
  symbols = self.market_symbols(symbols)
468
468
  options = self.safe_value(self.options, 'watchOrderBook', {})
469
469
  depth = self.safe_string(options, 'depth', 'books')
470
+ if limit is not None:
471
+ if limit == 1:
472
+ depth = 'bbo-tbt'
473
+ elif limit > 1 and limit <= 5:
474
+ depth = 'books5'
475
+ elif limit == 400:
476
+ depth = 'books'
477
+ elif limit == 50:
478
+ depth = 'books50-l2-tbt' # Make sure you have VIP4 and above
479
+ elif limit == 4000:
480
+ depth = 'books-l2-tbt' # Make sure you have VIP5 and above
470
481
  if (depth == 'books-l2-tbt') or (depth == 'books50-l2-tbt'):
471
482
  await self.authenticate({'access': 'public'})
472
483
  topics = []
ccxt/probit.py CHANGED
@@ -616,7 +616,7 @@ class probit(Exchange, ImplicitAPI):
616
616
  # ]
617
617
  # }
618
618
  #
619
- data = self.safe_value(response, 'data', [])
619
+ data = self.safe_list(response, 'data', [])
620
620
  return self.parse_tickers(data, symbols)
621
621
 
622
622
  def fetch_ticker(self, symbol: str, params={}) -> Ticker:
@@ -744,7 +744,7 @@ class probit(Exchange, ImplicitAPI):
744
744
  # ]
745
745
  # }
746
746
  #
747
- data = self.safe_value(response, 'data', [])
747
+ data = self.safe_list(response, 'data', [])
748
748
  return self.parse_trades(data, market, since, limit)
749
749
 
750
750
  def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
@@ -793,7 +793,7 @@ class probit(Exchange, ImplicitAPI):
793
793
  # ]
794
794
  # }
795
795
  #
796
- data = self.safe_value(response, 'data', [])
796
+ data = self.safe_list(response, 'data', [])
797
797
  return self.parse_trades(data, market, since, limit)
798
798
 
799
799
  def parse_trade(self, trade, market: Market = None) -> Trade:
@@ -963,7 +963,7 @@ class probit(Exchange, ImplicitAPI):
963
963
  # ]
964
964
  # }
965
965
  #
966
- data = self.safe_value(response, 'data', [])
966
+ data = self.safe_list(response, 'data', [])
967
967
  return self.parse_ohlcvs(data, market, timeframe, since, limit)
968
968
 
969
969
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
@@ -1007,7 +1007,7 @@ class probit(Exchange, ImplicitAPI):
1007
1007
  market = self.market(symbol)
1008
1008
  request['market_id'] = market['id']
1009
1009
  response = self.privateGetOpenOrder(self.extend(request, params))
1010
- data = self.safe_value(response, 'data')
1010
+ data = self.safe_list(response, 'data')
1011
1011
  return self.parse_orders(data, market, since, limit)
1012
1012
 
1013
1013
  def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
@@ -1035,7 +1035,7 @@ class probit(Exchange, ImplicitAPI):
1035
1035
  if limit:
1036
1036
  request['limit'] = limit
1037
1037
  response = self.privateGetOrderHistory(self.extend(request, params))
1038
- data = self.safe_value(response, 'data')
1038
+ data = self.safe_list(response, 'data')
1039
1039
  return self.parse_orders(data, market, since, limit)
1040
1040
 
1041
1041
  def fetch_order(self, id: str, symbol: Str = None, params={}):
@@ -1061,7 +1061,7 @@ class probit(Exchange, ImplicitAPI):
1061
1061
  query = self.omit(params, ['clientOrderId', 'client_order_id'])
1062
1062
  response = self.privateGetOrder(self.extend(request, query))
1063
1063
  data = self.safe_value(response, 'data', [])
1064
- order = self.safe_value(data, 0)
1064
+ order = self.safe_dict(data, 0)
1065
1065
  return self.parse_order(order, market)
1066
1066
 
1067
1067
  def parse_order_status(self, status):
@@ -1242,7 +1242,7 @@ class probit(Exchange, ImplicitAPI):
1242
1242
  'order_id': id,
1243
1243
  }
1244
1244
  response = self.privatePostCancelOrder(self.extend(request, params))
1245
- data = self.safe_value(response, 'data')
1245
+ data = self.safe_dict(response, 'data')
1246
1246
  return self.parse_order(data)
1247
1247
 
1248
1248
  def parse_deposit_address(self, depositAddress, currency: Currency = None):
@@ -1328,7 +1328,7 @@ class probit(Exchange, ImplicitAPI):
1328
1328
  currencyIds.append(currency['id'])
1329
1329
  request['currency_id'] = ','.join(codes)
1330
1330
  response = self.privateGetDepositAddress(self.extend(request, params))
1331
- data = self.safe_value(response, 'data', [])
1331
+ data = self.safe_list(response, 'data', [])
1332
1332
  return self.parse_deposit_addresses(data, codes)
1333
1333
 
1334
1334
  def withdraw(self, code: str, amount: float, address, tag=None, params={}):
@@ -1371,7 +1371,7 @@ class probit(Exchange, ImplicitAPI):
1371
1371
  request['platform_id'] = network
1372
1372
  params = self.omit(params, 'network')
1373
1373
  response = self.privatePostWithdrawal(self.extend(request, params))
1374
- data = self.safe_value(response, 'data')
1374
+ data = self.safe_dict(response, 'data')
1375
1375
  return self.parse_transaction(data, currency)
1376
1376
 
1377
1377
  def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
@@ -1605,7 +1605,7 @@ class probit(Exchange, ImplicitAPI):
1605
1605
  # ]
1606
1606
  # }
1607
1607
  #
1608
- data = self.safe_value(response, 'data')
1608
+ data = self.safe_list(response, 'data')
1609
1609
  return self.parse_deposit_withdraw_fees(data, codes, 'id')
1610
1610
 
1611
1611
  def parse_deposit_withdraw_fee(self, fee, currency: Currency = None):
@@ -91,6 +91,9 @@ def test_market(exchange, skipped_properties, method, market):
91
91
  # otherwise, it must be false or undefined
92
92
  test_shared_methods.assert_in_array(exchange, skipped_properties, method, market, 'margin', [False, None])
93
93
  if not ('contractSize' in skipped_properties):
94
+ if not market['spot']:
95
+ # if not spot, then contractSize should be defined
96
+ assert market['contractSize'] is not None, '\"contractSize\" must be defined when \"spot\" is false' + log_text
94
97
  test_shared_methods.assert_greater(exchange, skipped_properties, method, market, 'contractSize', '0')
95
98
  # typical values
96
99
  test_shared_methods.assert_greater(exchange, skipped_properties, method, market, 'expiry', '0')
ccxt/timex.py CHANGED
@@ -541,7 +541,7 @@ class timex(Exchange, ImplicitAPI):
541
541
  # }
542
542
  # ]
543
543
  #
544
- ticker = self.safe_value(response, 0)
544
+ ticker = self.safe_dict(response, 0)
545
545
  return self.parse_ticker(ticker, market)
546
546
 
547
547
  def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
@@ -779,7 +779,7 @@ class timex(Exchange, ImplicitAPI):
779
779
  # }
780
780
  #
781
781
  orders = self.safe_value(response, 'orders', [])
782
- order = self.safe_value(orders, 0, {})
782
+ order = self.safe_dict(orders, 0, {})
783
783
  return self.parse_order(order, market)
784
784
 
785
785
  def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
@@ -827,7 +827,7 @@ class timex(Exchange, ImplicitAPI):
827
827
  })
828
828
  orders = self.safe_value(response, 'changedOrders', [])
829
829
  firstOrder = self.safe_value(orders, 0, {})
830
- order = self.safe_value(firstOrder, 'newOrder', {})
830
+ order = self.safe_dict(firstOrder, 'newOrder', {})
831
831
  return self.parse_order(order, market)
832
832
 
833
833
  def cancel_order(self, id: str, symbol: Str = None, params={}):
@@ -929,7 +929,7 @@ class timex(Exchange, ImplicitAPI):
929
929
  # }
930
930
  #
931
931
  order = self.safe_value(response, 'order', {})
932
- trades = self.safe_value(response, 'trades', [])
932
+ trades = self.safe_list(response, 'trades', [])
933
933
  return self.parse_order(self.extend(order, {'trades': trades}))
934
934
 
935
935
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
@@ -980,7 +980,7 @@ class timex(Exchange, ImplicitAPI):
980
980
  # ]
981
981
  # }
982
982
  #
983
- orders = self.safe_value(response, 'orders', [])
983
+ orders = self.safe_list(response, 'orders', [])
984
984
  return self.parse_orders(orders, market, since, limit)
985
985
 
986
986
  def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
@@ -1035,7 +1035,7 @@ class timex(Exchange, ImplicitAPI):
1035
1035
  # ]
1036
1036
  # }
1037
1037
  #
1038
- orders = self.safe_value(response, 'orders', [])
1038
+ orders = self.safe_list(response, 'orders', [])
1039
1039
  return self.parse_orders(orders, market, since, limit)
1040
1040
 
1041
1041
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
@@ -1093,7 +1093,7 @@ class timex(Exchange, ImplicitAPI):
1093
1093
  # ]
1094
1094
  # }
1095
1095
  #
1096
- trades = self.safe_value(response, 'trades', [])
1096
+ trades = self.safe_list(response, 'trades', [])
1097
1097
  return self.parse_trades(trades, market, since, limit)
1098
1098
 
1099
1099
  def parse_trading_fee(self, fee, market: Market = None):
ccxt/tokocrypto.py CHANGED
@@ -1203,7 +1203,7 @@ class tokocrypto(Exchange, ImplicitAPI):
1203
1203
  }
1204
1204
  response = self.binanceGetTicker24hr(self.extend(request, params))
1205
1205
  if isinstance(response, list):
1206
- firstTicker = self.safe_value(response, 0, {})
1206
+ firstTicker = self.safe_dict(response, 0, {})
1207
1207
  return self.parse_ticker(firstTicker, market)
1208
1208
  return self.parse_ticker(response, market)
1209
1209
 
@@ -1311,7 +1311,7 @@ class tokocrypto(Exchange, ImplicitAPI):
1311
1311
  # [1591478640000,"0.02500800","0.02501100","0.02500300","0.02500800","154.14200000",1591478699999,"3.85405839",97,"5.32300000","0.13312641","0"],
1312
1312
  # ]
1313
1313
  #
1314
- data = self.safe_value(response, 'data', response)
1314
+ data = self.safe_list(response, 'data', response)
1315
1315
  return self.parse_ohlcvs(data, market, timeframe, since, limit)
1316
1316
 
1317
1317
  def fetch_balance(self, params={}) -> Balances:
@@ -1712,7 +1712,7 @@ class tokocrypto(Exchange, ImplicitAPI):
1712
1712
  # "timestamp": 1662710994975
1713
1713
  # }
1714
1714
  #
1715
- rawOrder = self.safe_value(response, 'data', {})
1715
+ rawOrder = self.safe_dict(response, 'data', {})
1716
1716
  return self.parse_order(rawOrder, market)
1717
1717
 
1718
1718
  def fetch_order(self, id: str, symbol: Str = None, params={}):
@@ -1759,7 +1759,7 @@ class tokocrypto(Exchange, ImplicitAPI):
1759
1759
  #
1760
1760
  data = self.safe_value(response, 'data', {})
1761
1761
  list = self.safe_value(data, 'list', [])
1762
- rawOrder = self.safe_value(list, 0, {})
1762
+ rawOrder = self.safe_dict(list, 0, {})
1763
1763
  return self.parse_order(rawOrder)
1764
1764
 
1765
1765
  def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
@@ -1825,7 +1825,7 @@ class tokocrypto(Exchange, ImplicitAPI):
1825
1825
  # }
1826
1826
  #
1827
1827
  data = self.safe_value(response, 'data', {})
1828
- orders = self.safe_value(data, 'list', [])
1828
+ orders = self.safe_list(data, 'list', [])
1829
1829
  return self.parse_orders(orders, market, since, limit)
1830
1830
 
1831
1831
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
@@ -1894,7 +1894,7 @@ class tokocrypto(Exchange, ImplicitAPI):
1894
1894
  # "timestamp": 1662710683634
1895
1895
  # }
1896
1896
  #
1897
- rawOrder = self.safe_value(response, 'data', {})
1897
+ rawOrder = self.safe_dict(response, 'data', {})
1898
1898
  return self.parse_order(rawOrder)
1899
1899
 
1900
1900
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
@@ -1949,7 +1949,7 @@ class tokocrypto(Exchange, ImplicitAPI):
1949
1949
  # }
1950
1950
  #
1951
1951
  data = self.safe_value(response, 'data', {})
1952
- trades = self.safe_value(data, 'list', [])
1952
+ trades = self.safe_list(data, 'list', [])
1953
1953
  return self.parse_trades(trades, market, since, limit)
1954
1954
 
1955
1955
  def fetch_deposit_address(self, code: str, params={}):
@@ -2056,7 +2056,7 @@ class tokocrypto(Exchange, ImplicitAPI):
2056
2056
  # }
2057
2057
  #
2058
2058
  data = self.safe_value(response, 'data', {})
2059
- deposits = self.safe_value(data, 'list', [])
2059
+ deposits = self.safe_list(data, 'list', [])
2060
2060
  return self.parse_transactions(deposits, currency, since, limit)
2061
2061
 
2062
2062
  def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
@@ -2108,7 +2108,7 @@ class tokocrypto(Exchange, ImplicitAPI):
2108
2108
  # }
2109
2109
  #
2110
2110
  data = self.safe_value(response, 'data', {})
2111
- withdrawals = self.safe_value(data, 'list', [])
2111
+ withdrawals = self.safe_list(data, 'list', [])
2112
2112
  return self.parse_transactions(withdrawals, currency, since, limit)
2113
2113
 
2114
2114
  def parse_transaction_status_by_type(self, status, type=None):