ccxt 4.2.84__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 (150) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/ace.py +5 -5
  3. ccxt/ascendex.py +8 -8
  4. ccxt/async_support/__init__.py +1 -1
  5. ccxt/async_support/ace.py +5 -5
  6. ccxt/async_support/ascendex.py +8 -8
  7. ccxt/async_support/base/exchange.py +3 -27
  8. ccxt/async_support/bigone.py +12 -12
  9. ccxt/async_support/binance.py +20 -32
  10. ccxt/async_support/bingx.py +12 -9
  11. ccxt/async_support/bit2c.py +1 -1
  12. ccxt/async_support/bitbank.py +8 -8
  13. ccxt/async_support/bitbns.py +5 -5
  14. ccxt/async_support/bitfinex.py +1 -1
  15. ccxt/async_support/bitfinex2.py +1 -1
  16. ccxt/async_support/bitget.py +29 -24
  17. ccxt/async_support/bithumb.py +5 -5
  18. ccxt/async_support/bitmart.py +16 -16
  19. ccxt/async_support/bitopro.py +1 -1
  20. ccxt/async_support/bitrue.py +4 -4
  21. ccxt/async_support/bitso.py +5 -5
  22. ccxt/async_support/bitstamp.py +1 -1
  23. ccxt/async_support/bitteam.py +8 -8
  24. ccxt/async_support/bl3p.py +1 -1
  25. ccxt/async_support/btcturk.py +6 -6
  26. ccxt/async_support/bybit.py +30 -83
  27. ccxt/async_support/coincheck.py +4 -4
  28. ccxt/async_support/coinex.py +11 -11
  29. ccxt/async_support/coinlist.py +7 -7
  30. ccxt/async_support/coinmate.py +4 -4
  31. ccxt/async_support/coinmetro.py +3 -3
  32. ccxt/async_support/coinone.py +5 -5
  33. ccxt/async_support/coinspot.py +2 -2
  34. ccxt/async_support/cryptocom.py +17 -17
  35. ccxt/async_support/currencycom.py +1 -1
  36. ccxt/async_support/delta.py +0 -8
  37. ccxt/async_support/deribit.py +16 -80
  38. ccxt/async_support/digifinex.py +8 -8
  39. ccxt/async_support/exmo.py +8 -8
  40. ccxt/async_support/gate.py +0 -8
  41. ccxt/async_support/hitbtc.py +5 -4
  42. ccxt/async_support/hollaex.py +7 -7
  43. ccxt/async_support/htx.py +7 -7
  44. ccxt/async_support/huobijp.py +3 -3
  45. ccxt/async_support/idex.py +2 -2
  46. ccxt/async_support/independentreserve.py +2 -2
  47. ccxt/async_support/indodax.py +2 -2
  48. ccxt/async_support/kraken.py +8 -8
  49. ccxt/async_support/krakenfutures.py +6 -6
  50. ccxt/async_support/kucoin.py +4 -1
  51. ccxt/async_support/kucoinfutures.py +8 -8
  52. ccxt/async_support/kuna.py +16 -16
  53. ccxt/async_support/latoken.py +2 -2
  54. ccxt/async_support/lbank.py +10 -10
  55. ccxt/async_support/luno.py +4 -4
  56. ccxt/async_support/mercado.py +5 -5
  57. ccxt/async_support/mexc.py +6 -6
  58. ccxt/async_support/ndax.py +1 -1
  59. ccxt/async_support/novadax.py +9 -9
  60. ccxt/async_support/oceanex.py +7 -7
  61. ccxt/async_support/okcoin.py +13 -13
  62. ccxt/async_support/okx.py +23 -31
  63. ccxt/async_support/onetrading.py +4 -4
  64. ccxt/async_support/p2b.py +7 -7
  65. ccxt/async_support/phemex.py +12 -12
  66. ccxt/async_support/poloniexfutures.py +5 -5
  67. ccxt/async_support/probit.py +11 -11
  68. ccxt/async_support/timex.py +7 -7
  69. ccxt/async_support/tokocrypto.py +9 -9
  70. ccxt/async_support/wavesexchange.py +3 -3
  71. ccxt/async_support/whitebit.py +5 -5
  72. ccxt/async_support/woo.py +1 -1
  73. ccxt/async_support/zaif.py +1 -1
  74. ccxt/async_support/zonda.py +7 -7
  75. ccxt/base/exchange.py +66 -23
  76. ccxt/bigone.py +12 -12
  77. ccxt/binance.py +20 -32
  78. ccxt/bingx.py +12 -9
  79. ccxt/bit2c.py +1 -1
  80. ccxt/bitbank.py +8 -8
  81. ccxt/bitbns.py +5 -5
  82. ccxt/bitfinex.py +1 -1
  83. ccxt/bitfinex2.py +1 -1
  84. ccxt/bitget.py +29 -24
  85. ccxt/bithumb.py +5 -5
  86. ccxt/bitmart.py +16 -16
  87. ccxt/bitopro.py +1 -1
  88. ccxt/bitrue.py +4 -4
  89. ccxt/bitso.py +5 -5
  90. ccxt/bitstamp.py +1 -1
  91. ccxt/bitteam.py +8 -8
  92. ccxt/bl3p.py +1 -1
  93. ccxt/btcturk.py +6 -6
  94. ccxt/bybit.py +30 -83
  95. ccxt/coincheck.py +4 -4
  96. ccxt/coinex.py +11 -11
  97. ccxt/coinlist.py +7 -7
  98. ccxt/coinmate.py +4 -4
  99. ccxt/coinmetro.py +3 -3
  100. ccxt/coinone.py +5 -5
  101. ccxt/coinspot.py +2 -2
  102. ccxt/cryptocom.py +17 -17
  103. ccxt/currencycom.py +1 -1
  104. ccxt/delta.py +0 -8
  105. ccxt/deribit.py +16 -80
  106. ccxt/digifinex.py +8 -8
  107. ccxt/exmo.py +8 -8
  108. ccxt/gate.py +0 -8
  109. ccxt/hitbtc.py +5 -4
  110. ccxt/hollaex.py +7 -7
  111. ccxt/htx.py +7 -7
  112. ccxt/huobijp.py +3 -3
  113. ccxt/idex.py +2 -2
  114. ccxt/independentreserve.py +2 -2
  115. ccxt/indodax.py +2 -2
  116. ccxt/kraken.py +8 -8
  117. ccxt/krakenfutures.py +6 -6
  118. ccxt/kucoin.py +4 -1
  119. ccxt/kucoinfutures.py +8 -8
  120. ccxt/kuna.py +16 -16
  121. ccxt/latoken.py +2 -2
  122. ccxt/lbank.py +10 -10
  123. ccxt/luno.py +4 -4
  124. ccxt/mercado.py +5 -5
  125. ccxt/mexc.py +6 -6
  126. ccxt/ndax.py +1 -1
  127. ccxt/novadax.py +9 -9
  128. ccxt/oceanex.py +7 -7
  129. ccxt/okcoin.py +13 -13
  130. ccxt/okx.py +23 -31
  131. ccxt/onetrading.py +4 -4
  132. ccxt/p2b.py +7 -7
  133. ccxt/phemex.py +12 -12
  134. ccxt/poloniexfutures.py +5 -5
  135. ccxt/pro/__init__.py +1 -1
  136. ccxt/pro/binance.py +150 -112
  137. ccxt/pro/kucoin.py +6 -7
  138. ccxt/pro/okx.py +12 -1
  139. ccxt/probit.py +11 -11
  140. ccxt/timex.py +7 -7
  141. ccxt/tokocrypto.py +9 -9
  142. ccxt/wavesexchange.py +3 -3
  143. ccxt/whitebit.py +5 -5
  144. ccxt/woo.py +1 -1
  145. ccxt/zaif.py +1 -1
  146. ccxt/zonda.py +7 -7
  147. {ccxt-4.2.84.dist-info → ccxt-4.2.85.dist-info}/METADATA +4 -4
  148. {ccxt-4.2.84.dist-info → ccxt-4.2.85.dist-info}/RECORD +150 -150
  149. {ccxt-4.2.84.dist-info → ccxt-4.2.85.dist-info}/WHEEL +0 -0
  150. {ccxt-4.2.84.dist-info → ccxt-4.2.85.dist-info}/top_level.txt +0 -0
ccxt/phemex.py CHANGED
@@ -1266,7 +1266,7 @@ class phemex(Exchange, ImplicitAPI):
1266
1266
  # }
1267
1267
  #
1268
1268
  data = self.safe_value(response, 'data', {})
1269
- rows = self.safe_value(data, 'rows', [])
1269
+ rows = self.safe_list(data, 'rows', [])
1270
1270
  return self.parse_ohlcvs(rows, market, timeframe, since, userLimit)
1271
1271
 
1272
1272
  def parse_ticker(self, ticker, market: Market = None) -> Ticker:
@@ -1422,7 +1422,7 @@ class phemex(Exchange, ImplicitAPI):
1422
1422
  # }
1423
1423
  # }
1424
1424
  #
1425
- result = self.safe_value(response, 'result', {})
1425
+ result = self.safe_dict(response, 'result', {})
1426
1426
  return self.parse_ticker(result, market)
1427
1427
 
1428
1428
  def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
@@ -1452,7 +1452,7 @@ class phemex(Exchange, ImplicitAPI):
1452
1452
  response = self.v1GetMdTicker24hrAll(query)
1453
1453
  else:
1454
1454
  response = self.v2GetMdV2Ticker24hrAll(query)
1455
- result = self.safe_value(response, 'result', [])
1455
+ result = self.safe_list(response, 'result', [])
1456
1456
  return self.parse_tickers(result, symbols)
1457
1457
 
1458
1458
  def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
@@ -2587,7 +2587,7 @@ class phemex(Exchange, ImplicitAPI):
2587
2587
  # }
2588
2588
  # }
2589
2589
  #
2590
- data = self.safe_value(response, 'data', {})
2590
+ data = self.safe_dict(response, 'data', {})
2591
2591
  return self.parse_order(data, market)
2592
2592
 
2593
2593
  def edit_order(self, id: str, symbol: str, type: OrderType = None, side: OrderSide = None, amount: Num = None, price: Num = None, params={}):
@@ -2648,7 +2648,7 @@ class phemex(Exchange, ImplicitAPI):
2648
2648
  response = self.privatePutOrdersReplace(self.extend(request, params))
2649
2649
  else:
2650
2650
  response = self.privatePutSpotOrders(self.extend(request, params))
2651
- data = self.safe_value(response, 'data', {})
2651
+ data = self.safe_dict(response, 'data', {})
2652
2652
  return self.parse_order(data, market)
2653
2653
 
2654
2654
  def cancel_order(self, id: str, symbol: Str = None, params={}):
@@ -2684,7 +2684,7 @@ class phemex(Exchange, ImplicitAPI):
2684
2684
  response = self.privateDeleteOrdersCancel(self.extend(request, params))
2685
2685
  else:
2686
2686
  response = self.privateDeleteSpotOrders(self.extend(request, params))
2687
- data = self.safe_value(response, 'data', {})
2687
+ data = self.safe_dict(response, 'data', {})
2688
2688
  return self.parse_order(data, market)
2689
2689
 
2690
2690
  def cancel_all_orders(self, symbol: Str = None, params={}):
@@ -2782,7 +2782,7 @@ class phemex(Exchange, ImplicitAPI):
2782
2782
  else:
2783
2783
  response = self.privateGetSpotOrders(self.extend(request, params))
2784
2784
  data = self.safe_value(response, 'data', {})
2785
- rows = self.safe_value(data, 'rows', data)
2785
+ rows = self.safe_list(data, 'rows', data)
2786
2786
  return self.parse_orders(rows, market, since, limit)
2787
2787
 
2788
2788
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
@@ -2821,7 +2821,7 @@ class phemex(Exchange, ImplicitAPI):
2821
2821
  if isinstance(data, list):
2822
2822
  return self.parse_orders(data, market, since, limit)
2823
2823
  else:
2824
- rows = self.safe_value(data, 'rows', [])
2824
+ rows = self.safe_list(data, 'rows', [])
2825
2825
  return self.parse_orders(rows, market, since, limit)
2826
2826
 
2827
2827
  def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
@@ -2898,7 +2898,7 @@ class phemex(Exchange, ImplicitAPI):
2898
2898
  if isinstance(data, list):
2899
2899
  return self.parse_orders(data, market, since, limit)
2900
2900
  else:
2901
- rows = self.safe_value(data, 'rows', [])
2901
+ rows = self.safe_list(data, 'rows', [])
2902
2902
  return self.parse_orders(rows, market, since, limit)
2903
2903
 
2904
2904
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
@@ -3942,7 +3942,7 @@ class phemex(Exchange, ImplicitAPI):
3942
3942
  #
3943
3943
  #
3944
3944
  data = self.safe_value(response, 'data', {})
3945
- riskLimits = self.safe_value(data, 'riskLimits')
3945
+ riskLimits = self.safe_list(data, 'riskLimits')
3946
3946
  return self.parse_leverage_tiers(riskLimits, symbols, 'symbol')
3947
3947
 
3948
3948
  def parse_market_leverage_tiers(self, info, market: Market = None):
@@ -4173,7 +4173,7 @@ class phemex(Exchange, ImplicitAPI):
4173
4173
  # }
4174
4174
  #
4175
4175
  data = self.safe_value(response, 'data', {})
4176
- transfers = self.safe_value(data, 'rows', [])
4176
+ transfers = self.safe_list(data, 'rows', [])
4177
4177
  return self.parse_transfers(transfers, currency, since, limit)
4178
4178
 
4179
4179
  def parse_transfer(self, transfer, currency: Currency = None):
@@ -4375,7 +4375,7 @@ class phemex(Exchange, ImplicitAPI):
4375
4375
  # }
4376
4376
  # }
4377
4377
  #
4378
- data = self.safe_value(response, 'data', {})
4378
+ data = self.safe_dict(response, 'data', {})
4379
4379
  return self.parse_transaction(data, currency)
4380
4380
 
4381
4381
  def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
ccxt/poloniexfutures.py CHANGED
@@ -665,7 +665,7 @@ class poloniexfutures(Exchange, ImplicitAPI):
665
665
  # },
666
666
  # }
667
667
  #
668
- trades = self.safe_value(response, 'data', [])
668
+ trades = self.safe_list(response, 'data', [])
669
669
  return self.parse_trades(trades, market, since, limit)
670
670
 
671
671
  def fetch_time(self, params={}):
@@ -729,7 +729,7 @@ class poloniexfutures(Exchange, ImplicitAPI):
729
729
  # ]
730
730
  # }
731
731
  #
732
- data = self.safe_value(response, 'data', [])
732
+ data = self.safe_list(response, 'data', [])
733
733
  return self.parse_ohlcvs(data, market, timeframe, since, limit)
734
734
 
735
735
  def parse_balance(self, response) -> Balances:
@@ -970,7 +970,7 @@ class poloniexfutures(Exchange, ImplicitAPI):
970
970
  # ]
971
971
  # }
972
972
  #
973
- data = self.safe_value(response, 'data')
973
+ data = self.safe_list(response, 'data')
974
974
  return self.parse_positions(data, symbols)
975
975
 
976
976
  def parse_position(self, position, market: Market = None):
@@ -1389,7 +1389,7 @@ class poloniexfutures(Exchange, ImplicitAPI):
1389
1389
  # }
1390
1390
  #
1391
1391
  market = self.market(symbol) if (symbol is not None) else None
1392
- responseData = self.safe_value(response, 'data')
1392
+ responseData = self.safe_dict(response, 'data')
1393
1393
  return self.parse_order(responseData, market)
1394
1394
 
1395
1395
  def parse_order(self, order, market: Market = None) -> Order:
@@ -1616,7 +1616,7 @@ class poloniexfutures(Exchange, ImplicitAPI):
1616
1616
  # }
1617
1617
  #
1618
1618
  data = self.safe_value(response, 'data', {})
1619
- trades = self.safe_value(data, 'items', {})
1619
+ trades = self.safe_list(data, 'items', [])
1620
1620
  return self.parse_trades(trades, market, since, limit)
1621
1621
 
1622
1622
  def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.84'
7
+ __version__ = '4.2.85'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
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 = []