ccxt 4.3.62__py2.py3-none-any.whl → 4.3.63__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 (46) hide show
  1. ccxt/__init__.py +2 -1
  2. ccxt/abstract/binance.py +5 -5
  3. ccxt/abstract/binancecoinm.py +5 -5
  4. ccxt/abstract/binanceus.py +5 -5
  5. ccxt/abstract/binanceusdm.py +5 -5
  6. ccxt/abstract/cryptocom.py +11 -0
  7. ccxt/abstract/woo.py +3 -0
  8. ccxt/ace.py +33 -15
  9. ccxt/async_support/__init__.py +2 -1
  10. ccxt/async_support/ace.py +33 -15
  11. ccxt/async_support/base/exchange.py +1 -1
  12. ccxt/async_support/binance.py +6 -9
  13. ccxt/async_support/bingx.py +451 -151
  14. ccxt/async_support/coinbaseinternational.py +1 -1
  15. ccxt/async_support/cryptocom.py +17 -2
  16. ccxt/async_support/mercado.py +5 -1
  17. ccxt/async_support/woo.py +296 -81
  18. ccxt/async_support/xt.py +3 -3
  19. ccxt/base/errors.py +8 -1
  20. ccxt/base/exchange.py +8 -2
  21. ccxt/binance.py +6 -9
  22. ccxt/bingx.py +451 -151
  23. ccxt/coinbaseinternational.py +1 -1
  24. ccxt/cryptocom.py +17 -2
  25. ccxt/mercado.py +5 -1
  26. ccxt/pro/__init__.py +1 -1
  27. ccxt/pro/binance.py +56 -35
  28. ccxt/pro/bitfinex2.py +6 -4
  29. ccxt/pro/bitget.py +5 -2
  30. ccxt/pro/bitvavo.py +1 -1
  31. ccxt/pro/bybit.py +41 -18
  32. ccxt/pro/cryptocom.py +7 -2
  33. ccxt/pro/gate.py +6 -3
  34. ccxt/pro/htx.py +5 -1
  35. ccxt/pro/independentreserve.py +6 -4
  36. ccxt/pro/kraken.py +79 -6
  37. ccxt/pro/okx.py +4 -4
  38. ccxt/pro/poloniexfutures.py +5 -2
  39. ccxt/pro/woofipro.py +1 -1
  40. ccxt/woo.py +296 -81
  41. ccxt/xt.py +3 -3
  42. {ccxt-4.3.62.dist-info → ccxt-4.3.63.dist-info}/METADATA +4 -4
  43. {ccxt-4.3.62.dist-info → ccxt-4.3.63.dist-info}/RECORD +46 -46
  44. {ccxt-4.3.62.dist-info → ccxt-4.3.63.dist-info}/LICENSE.txt +0 -0
  45. {ccxt-4.3.62.dist-info → ccxt-4.3.63.dist-info}/WHEEL +0 -0
  46. {ccxt-4.3.62.dist-info → ccxt-4.3.63.dist-info}/top_level.txt +0 -0
@@ -571,7 +571,7 @@ class coinbaseinternational(Exchange, ImplicitAPI):
571
571
  }
572
572
  return self.v1PrivatePostPortfoliosMargin(self.extend(request, params))
573
573
 
574
- def fetch_deposits_withdrawals(self, code: str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
574
+ def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
575
575
  """
576
576
  fetch history of deposits and withdrawals
577
577
  :see: https://docs.cloud.coinbase.com/intx/reference/gettransfers
ccxt/cryptocom.py CHANGED
@@ -176,6 +176,9 @@ class cryptocom(Exchange, ImplicitAPI):
176
176
  'public/get-expired-settlement-price': 10 / 3,
177
177
  'public/get-insurance': 1,
178
178
  },
179
+ 'post': {
180
+ 'public/staking/get-conversion-rate': 2,
181
+ },
179
182
  },
180
183
  'private': {
181
184
  'post': {
@@ -205,6 +208,16 @@ class cryptocom(Exchange, ImplicitAPI):
205
208
  'private/get-accounts': 10 / 3,
206
209
  'private/get-withdrawal-history': 10 / 3,
207
210
  'private/get-deposit-history': 10 / 3,
211
+ 'private/staking/stake': 2,
212
+ 'private/staking/unstake': 2,
213
+ 'private/staking/get-staking-position': 2,
214
+ 'private/staking/get-staking-instruments': 2,
215
+ 'private/staking/get-open-stake': 2,
216
+ 'private/staking/get-stake-history': 2,
217
+ 'private/staking/get-reward-history': 2,
218
+ 'private/staking/convert': 2,
219
+ 'private/staking/get-open-convert': 2,
220
+ 'private/staking/get-convert-history': 2,
208
221
  },
209
222
  },
210
223
  },
@@ -799,15 +812,17 @@ class cryptocom(Exchange, ImplicitAPI):
799
812
  'timeframe': self.safe_string(self.timeframes, timeframe, timeframe),
800
813
  }
801
814
  if limit is not None:
815
+ if limit > 300:
816
+ limit = 300
802
817
  request['count'] = limit
803
818
  now = self.microseconds()
804
819
  duration = self.parse_timeframe(timeframe)
805
820
  until = self.safe_integer(params, 'until', now)
806
821
  params = self.omit(params, ['until'])
807
822
  if since is not None:
808
- request['start_ts'] = since
823
+ request['start_ts'] = since - duration * 1000
809
824
  if limit is not None:
810
- request['end_ts'] = self.sum(since, duration * (limit + 1) * 1000) - 1
825
+ request['end_ts'] = self.sum(since, duration * limit * 1000)
811
826
  else:
812
827
  request['end_ts'] = until
813
828
  else:
ccxt/mercado.py CHANGED
@@ -12,6 +12,7 @@ from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import ArgumentsRequired
13
13
  from ccxt.base.errors import InvalidOrder
14
14
  from ccxt.base.decimal_to_precision import TICK_SIZE
15
+ from ccxt.base.precise import Precise
15
16
 
16
17
 
17
18
  class mercado(Exchange, ImplicitAPI):
@@ -444,7 +445,10 @@ class mercado(Exchange, ImplicitAPI):
444
445
  if side == 'buy':
445
446
  if price is None:
446
447
  raise InvalidOrder(self.id + ' createOrder() requires the price argument with market buy orders to calculate total order cost(amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount')
447
- request['cost'] = self.price_to_precision(market['symbol'], amount * price)
448
+ amountString = self.number_to_string(amount)
449
+ priceString = self.number_to_string(price)
450
+ cost = self.parse_to_numeric(Precise.string_mul(amountString, priceString))
451
+ request['cost'] = self.price_to_precision(market['symbol'], cost)
448
452
  else:
449
453
  request['quantity'] = self.amount_to_precision(market['symbol'], amount)
450
454
  response = getattr(self, method)(self.extend(request, params))
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.62'
7
+ __version__ = '4.3.63'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/binance.py CHANGED
@@ -12,7 +12,7 @@ from typing import List
12
12
  from ccxt.base.errors import ArgumentsRequired
13
13
  from ccxt.base.errors import BadRequest
14
14
  from ccxt.base.errors import NotSupported
15
- from ccxt.base.errors import InvalidNonce
15
+ from ccxt.base.errors import ChecksumError
16
16
  from ccxt.base.precise import Precise
17
17
 
18
18
 
@@ -30,7 +30,7 @@ class binance(ccxt.async_support.binance):
30
30
  'watchBidsAsks': True,
31
31
  'watchMyTrades': True,
32
32
  'watchOHLCV': True,
33
- 'watchOHLCVForSymbols': False,
33
+ 'watchOHLCVForSymbols': True,
34
34
  'watchOrderBook': True,
35
35
  'watchOrderBookForSymbols': True,
36
36
  'watchOrders': True,
@@ -133,6 +133,7 @@ class binance(ccxt.async_support.binance):
133
133
  },
134
134
  'watchOrderBook': {
135
135
  'maxRetries': 3,
136
+ 'checksum': True,
136
137
  },
137
138
  'watchBalance': {
138
139
  'fetchBalanceSnapshot': False, # or True
@@ -805,10 +806,10 @@ class binance(ccxt.async_support.binance):
805
806
  if nonce < orderbook['nonce']:
806
807
  client.resolve(orderbook, messageHash)
807
808
  else:
808
- checksum = self.safe_bool(self.options, 'checksum', True)
809
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
809
810
  if checksum:
810
811
  # todo: client.reject from handleOrderBookMessage properly
811
- raise InvalidNonce(self.id + ' handleOrderBook received an out-of-order nonce')
812
+ raise ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
812
813
  else:
813
814
  # future
814
815
  # 4. Drop any event where u is < lastUpdateId in the snapshot
@@ -820,10 +821,10 @@ class binance(ccxt.async_support.binance):
820
821
  if nonce <= orderbook['nonce']:
821
822
  client.resolve(orderbook, messageHash)
822
823
  else:
823
- checksum = self.safe_bool(self.options, 'checksum', True)
824
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
824
825
  if checksum:
825
826
  # todo: client.reject from handleOrderBookMessage properly
826
- raise InvalidNonce(self.id + ' handleOrderBook received an out-of-order nonce')
827
+ raise ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
827
828
  except Exception as e:
828
829
  del self.orderbooks[symbol]
829
830
  del client.subscriptions[messageHash]
@@ -1104,37 +1105,57 @@ class binance(ccxt.async_support.binance):
1104
1105
  :param dict [params]: extra parameters specific to the exchange API endpoint
1105
1106
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
1106
1107
  """
1108
+ params['callerMethodName'] = 'watchOHLCV'
1109
+ result = await self.watch_ohlcv_for_symbols([[symbol, timeframe]], since, limit, params)
1110
+ return result[symbol][timeframe]
1111
+
1112
+ async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
1113
+ """
1114
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1115
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
1116
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1117
+ :param int [limit]: the maximum amount of candles to fetch
1118
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1119
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1120
+ """
1107
1121
  await self.load_markets()
1108
- market = self.market(symbol)
1109
- marketId = market['lowercaseId']
1110
- interval = self.safe_string(self.timeframes, timeframe, timeframe)
1111
- options = self.safe_value(self.options, 'watchOHLCV', {})
1112
- nameOption = self.safe_string(options, 'name', 'kline')
1113
- name = self.safe_string(params, 'name', nameOption)
1114
- if name == 'indexPriceKline':
1115
- marketId = marketId.replace('_perp', '')
1116
- # weird behavior for index price kline we can't use the perp suffix
1117
- params = self.omit(params, 'name')
1118
- messageHash = marketId + '@' + name + '_' + interval
1119
- type = market['type']
1120
- if market['contract']:
1121
- type = 'future' if market['linear'] else 'delivery'
1122
- url = self.urls['api']['ws'][type] + '/' + self.stream(type, messageHash)
1122
+ klineType = None
1123
+ klineType, params = self.handle_param_string_2(params, 'channel', 'name', 'kline')
1124
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
1125
+ marketSymbols = self.market_symbols(symbols, None, False, False, True)
1126
+ firstMarket = self.market(marketSymbols[0])
1127
+ type = firstMarket['type']
1128
+ if firstMarket['contract']:
1129
+ type = 'future' if firstMarket['linear'] else 'delivery'
1130
+ rawHashes = []
1131
+ messageHashes = []
1132
+ for i in range(0, len(symbolsAndTimeframes)):
1133
+ symAndTf = symbolsAndTimeframes[i]
1134
+ symbolString = symAndTf[0]
1135
+ timeframeString = symAndTf[1]
1136
+ interval = self.safe_string(self.timeframes, timeframeString, timeframeString)
1137
+ market = self.market(symbolString)
1138
+ marketId = market['lowercaseId']
1139
+ if klineType == 'indexPriceKline':
1140
+ # weird behavior for index price kline we can't use the perp suffix
1141
+ marketId = marketId.replace('_perp', '')
1142
+ rawHashes.append(marketId + '@' + klineType + '_' + interval)
1143
+ messageHashes.append('ohlcv::' + symbolString + '::' + timeframeString)
1144
+ url = self.urls['api']['ws'][type] + '/' + self.stream(type, 'multipleOHLCV')
1123
1145
  requestId = self.request_id(url)
1124
- request: dict = {
1146
+ request = {
1125
1147
  'method': 'SUBSCRIBE',
1126
- 'params': [
1127
- messageHash,
1128
- ],
1148
+ 'params': rawHashes,
1129
1149
  'id': requestId,
1130
1150
  }
1131
- subscribe: dict = {
1151
+ subscribe = {
1132
1152
  'id': requestId,
1133
1153
  }
1134
- ohlcv = await self.watch(url, messageHash, self.extend(request, params), messageHash, subscribe)
1154
+ symbol, timeframe, candles = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes, subscribe)
1135
1155
  if self.newUpdates:
1136
- limit = ohlcv.getLimit(symbol, limit)
1137
- return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
1156
+ limit = candles.getLimit(symbol, limit)
1157
+ filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
1158
+ return self.create_ohlcv_object(symbol, timeframe, filtered)
1138
1159
 
1139
1160
  def handle_ohlcv(self, client: Client, message):
1140
1161
  #
@@ -1174,11 +1195,9 @@ class binance(ccxt.async_support.binance):
1174
1195
  if event == 'indexPriceKline':
1175
1196
  # indexPriceKline doesn't have the _PERP suffix
1176
1197
  marketId = self.safe_string(message, 'ps')
1177
- lowercaseMarketId = marketId.lower()
1178
1198
  interval = self.safe_string(kline, 'i')
1179
1199
  # use a reverse lookup in a static map instead
1180
- timeframe = self.find_timeframe(interval)
1181
- messageHash = lowercaseMarketId + '@' + event + '_' + interval
1200
+ unifiedTimeframe = self.find_timeframe(interval)
1182
1201
  parsed = [
1183
1202
  self.safe_integer(kline, 't'),
1184
1203
  self.safe_float(kline, 'o'),
@@ -1190,14 +1209,16 @@ class binance(ccxt.async_support.binance):
1190
1209
  isSpot = ((client.url.find('/stream') > -1) or (client.url.find('/testnet.binance') > -1))
1191
1210
  marketType = 'spot' if (isSpot) else 'contract'
1192
1211
  symbol = self.safe_symbol(marketId, None, None, marketType)
1212
+ messageHash = 'ohlcv::' + symbol + '::' + unifiedTimeframe
1193
1213
  self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
1194
- stored = self.safe_value(self.ohlcvs[symbol], timeframe)
1214
+ stored = self.safe_value(self.ohlcvs[symbol], unifiedTimeframe)
1195
1215
  if stored is None:
1196
1216
  limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
1197
1217
  stored = ArrayCacheByTimestamp(limit)
1198
- self.ohlcvs[symbol][timeframe] = stored
1218
+ self.ohlcvs[symbol][unifiedTimeframe] = stored
1199
1219
  stored.append(parsed)
1200
- client.resolve(stored, messageHash)
1220
+ resolveData = [symbol, unifiedTimeframe, stored]
1221
+ client.resolve(resolveData, messageHash)
1201
1222
 
1202
1223
  async def fetch_ticker_ws(self, symbol: str, params={}) -> Ticker:
1203
1224
  """
ccxt/pro/bitfinex2.py CHANGED
@@ -11,7 +11,7 @@ from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
14
- from ccxt.base.errors import InvalidNonce
14
+ from ccxt.base.errors import ChecksumError
15
15
  from ccxt.base.precise import Precise
16
16
 
17
17
 
@@ -42,9 +42,9 @@ class bitfinex2(ccxt.async_support.bitfinex2):
42
42
  'watchOrderBook': {
43
43
  'prec': 'P0',
44
44
  'freq': 'F0',
45
+ 'checksum': True,
45
46
  },
46
47
  'ordersLimit': 1000,
47
- 'checksum': True,
48
48
  },
49
49
  })
50
50
 
@@ -641,10 +641,12 @@ class bitfinex2(ccxt.async_support.bitfinex2):
641
641
  localChecksum = self.crc32(payload, True)
642
642
  responseChecksum = self.safe_integer(message, 2)
643
643
  if responseChecksum != localChecksum:
644
- error = InvalidNonce(self.id + ' invalid checksum')
645
644
  del client.subscriptions[messageHash]
646
645
  del self.orderbooks[symbol]
647
- client.reject(error, messageHash)
646
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
647
+ if checksum:
648
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
649
+ client.reject(error, messageHash)
648
650
 
649
651
  async def watch_balance(self, params={}) -> Balances:
650
652
  """
ccxt/pro/bitget.py CHANGED
@@ -14,7 +14,7 @@ from ccxt.base.errors import AuthenticationError
14
14
  from ccxt.base.errors import ArgumentsRequired
15
15
  from ccxt.base.errors import BadRequest
16
16
  from ccxt.base.errors import RateLimitExceeded
17
- from ccxt.base.errors import InvalidNonce
17
+ from ccxt.base.errors import ChecksumError
18
18
  from ccxt.base.precise import Precise
19
19
 
20
20
 
@@ -68,6 +68,9 @@ class bitget(ccxt.async_support.bitget):
68
68
  '1d': '1D',
69
69
  '1w': '1W',
70
70
  },
71
+ 'watchOrderBook': {
72
+ 'checksum': True,
73
+ },
71
74
  },
72
75
  'streaming': {
73
76
  'ping': self.ping,
@@ -539,9 +542,9 @@ class bitget(ccxt.async_support.bitget):
539
542
  calculatedChecksum = self.crc32(payload, True)
540
543
  responseChecksum = self.safe_integer(rawOrderBook, 'checksum')
541
544
  if calculatedChecksum != responseChecksum:
542
- error = InvalidNonce(self.id + ' invalid checksum')
543
545
  del client.subscriptions[messageHash]
544
546
  del self.orderbooks[symbol]
547
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
545
548
  client.reject(error, messageHash)
546
549
  return
547
550
  else:
ccxt/pro/bitvavo.py CHANGED
@@ -476,7 +476,7 @@ class bitvavo(ccxt.async_support.bitvavo):
476
476
  :param int [since]: the earliest time in ms to fetch trades for
477
477
  :param int [limit]: the maximum number of trade structures to retrieve
478
478
  :param dict [params]: extra parameters specific to the exchange API endpoint
479
- :returns dict[]: a list of [trade structures]{@link https://docs.ccxt.com/#/?id=ortradeder-structure
479
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
480
480
  """
481
481
  if symbol is None:
482
482
  raise ArgumentsRequired(self.id + ' watchMyTrades() requires a symbol argument')
ccxt/pro/bybit.py CHANGED
@@ -38,7 +38,7 @@ class bybit(ccxt.async_support.bybit):
38
38
  'watchMyLiquidationsForSymbols': False,
39
39
  'watchMyTrades': True,
40
40
  'watchOHLCV': True,
41
- 'watchOHLCVForSymbols': False,
41
+ 'watchOHLCVForSymbols': True,
42
42
  'watchOrderBook': True,
43
43
  'watchOrderBookForSymbols': True,
44
44
  'watchOrders': True,
@@ -513,19 +513,42 @@ class bybit(ccxt.async_support.bybit):
513
513
  :param dict [params]: extra parameters specific to the exchange API endpoint
514
514
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
515
515
  """
516
+ params['callerMethodName'] = 'watchOHLCV'
517
+ result = await self.watch_ohlcv_for_symbols([[symbol, timeframe]], since, limit, params)
518
+ return result[symbol][timeframe]
519
+
520
+ async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
521
+ """
522
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
523
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/kline
524
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
525
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
526
+ :param int [since]: timestamp in ms of the earliest candle to fetch
527
+ :param int [limit]: the maximum amount of candles to fetch
528
+ :param dict [params]: extra parameters specific to the exchange API endpoint
529
+ :returns dict: A list of candles ordered, open, high, low, close, volume
530
+ """
516
531
  await self.load_markets()
517
- market = self.market(symbol)
518
- symbol = market['symbol']
519
- url = await self.get_url_by_market_type(symbol, False, 'watchOHLCV', params)
520
- params = self.clean_params(params)
521
- ohlcv = None
522
- timeframeId = self.safe_string(self.timeframes, timeframe, timeframe)
523
- topics = ['kline.' + timeframeId + '.' + market['id']]
524
- messageHash = 'kline' + ':' + timeframeId + ':' + symbol
525
- ohlcv = await self.watch_topics(url, [messageHash], topics, params)
532
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
533
+ marketSymbols = self.market_symbols(symbols, None, False, True, True)
534
+ firstSymbol = marketSymbols[0]
535
+ url = await self.get_url_by_market_type(firstSymbol, False, 'watchOHLCVForSymbols', params)
536
+ rawHashes = []
537
+ messageHashes = []
538
+ for i in range(0, len(symbolsAndTimeframes)):
539
+ data = symbolsAndTimeframes[i]
540
+ symbolString = self.safe_string(data, 0)
541
+ market = self.market(symbolString)
542
+ symbolString = market['symbol']
543
+ unfiedTimeframe = self.safe_string(data, 1)
544
+ timeframeId = self.safe_string(self.timeframes, unfiedTimeframe, unfiedTimeframe)
545
+ rawHashes.append('kline.' + timeframeId + '.' + market['id'])
546
+ messageHashes.append('ohlcv::' + symbolString + '::' + unfiedTimeframe)
547
+ symbol, timeframe, stored = await self.watch_topics(url, messageHashes, rawHashes, params)
526
548
  if self.newUpdates:
527
- limit = ohlcv.getLimit(symbol, limit)
528
- return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
549
+ limit = stored.getLimit(symbol, limit)
550
+ filtered = self.filter_by_since_limit(stored, since, limit, 0, True)
551
+ return self.create_ohlcv_object(symbol, timeframe, filtered)
529
552
 
530
553
  def handle_ohlcv(self, client: Client, message):
531
554
  #
@@ -564,16 +587,16 @@ class bybit(ccxt.async_support.bybit):
564
587
  ohlcvsByTimeframe = self.safe_value(self.ohlcvs, symbol)
565
588
  if ohlcvsByTimeframe is None:
566
589
  self.ohlcvs[symbol] = {}
567
- stored = self.safe_value(ohlcvsByTimeframe, timeframe)
568
- if stored is None:
590
+ if self.safe_value(ohlcvsByTimeframe, timeframe) is None:
569
591
  limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
570
- stored = ArrayCacheByTimestamp(limit)
571
- self.ohlcvs[symbol][timeframe] = stored
592
+ self.ohlcvs[symbol][timeframe] = ArrayCacheByTimestamp(limit)
593
+ stored = self.ohlcvs[symbol][timeframe]
572
594
  for i in range(0, len(data)):
573
595
  parsed = self.parse_ws_ohlcv(data[i])
574
596
  stored.append(parsed)
575
- messageHash = 'kline' + ':' + timeframeId + ':' + symbol
576
- client.resolve(stored, messageHash)
597
+ messageHash = 'ohlcv::' + symbol + '::' + timeframe
598
+ resolveData = [symbol, timeframe, stored]
599
+ client.resolve(resolveData, messageHash)
577
600
 
578
601
  def parse_ws_ohlcv(self, ohlcv, market=None) -> list:
579
602
  #
ccxt/pro/cryptocom.py CHANGED
@@ -11,7 +11,7 @@ from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import AuthenticationError
13
13
  from ccxt.base.errors import NetworkError
14
- from ccxt.base.errors import InvalidNonce
14
+ from ccxt.base.errors import ChecksumError
15
15
 
16
16
 
17
17
  class cryptocom(ccxt.async_support.cryptocom):
@@ -52,6 +52,9 @@ class cryptocom(ccxt.async_support.cryptocom):
52
52
  'fetchPositionsSnapshot': True, # or False
53
53
  'awaitPositionsSnapshot': True, # whether to wait for the positions snapshot before providing updates
54
54
  },
55
+ 'watchOrderBook': {
56
+ 'checksum': True,
57
+ },
55
58
  },
56
59
  'streaming': {
57
60
  },
@@ -213,7 +216,9 @@ class cryptocom(ccxt.async_support.cryptocom):
213
216
  previousNonce = self.safe_integer(data, 'pu')
214
217
  currentNonce = orderbook['nonce']
215
218
  if currentNonce != previousNonce:
216
- raise InvalidNonce(self.id + ' watchOrderBook() ' + symbol + ' ' + previousNonce + ' != ' + nonce)
219
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
220
+ if checksum:
221
+ raise ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
217
222
  self.handle_deltas(orderbook['asks'], self.safe_value(books, 'asks', []))
218
223
  self.handle_deltas(orderbook['bids'], self.safe_value(books, 'bids', []))
219
224
  orderbook['nonce'] = nonce
ccxt/pro/gate.py CHANGED
@@ -14,7 +14,7 @@ from ccxt.base.errors import AuthenticationError
14
14
  from ccxt.base.errors import ArgumentsRequired
15
15
  from ccxt.base.errors import BadRequest
16
16
  from ccxt.base.errors import NotSupported
17
- from ccxt.base.errors import InvalidNonce
17
+ from ccxt.base.errors import ChecksumError
18
18
  from ccxt.base.precise import Precise
19
19
 
20
20
 
@@ -105,6 +105,7 @@ class gate(ccxt.async_support.gate):
105
105
  'interval': '100ms',
106
106
  'snapshotDelay': 10, # how many deltas to cache before fetching a snapshot
107
107
  'snapshotMaxRetries': 3,
108
+ 'checksum': True,
108
109
  },
109
110
  'watchBalance': {
110
111
  'settle': 'usdt', # or btc
@@ -460,10 +461,12 @@ class gate(ccxt.async_support.gate):
460
461
  elif nonce >= deltaStart - 1:
461
462
  self.handle_delta(storedOrderBook, delta)
462
463
  else:
463
- error = InvalidNonce(self.id + ' orderbook update has a nonce bigger than u')
464
464
  del client.subscriptions[messageHash]
465
465
  del self.orderbooks[symbol]
466
- client.reject(error, messageHash)
466
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
467
+ if checksum:
468
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
469
+ client.reject(error, messageHash)
467
470
  client.resolve(storedOrderBook, messageHash)
468
471
 
469
472
  def get_cache_index(self, orderBook, cache):
ccxt/pro/htx.py CHANGED
@@ -16,6 +16,7 @@ from ccxt.base.errors import BadRequest
16
16
  from ccxt.base.errors import BadSymbol
17
17
  from ccxt.base.errors import NetworkError
18
18
  from ccxt.base.errors import InvalidNonce
19
+ from ccxt.base.errors import ChecksumError
19
20
 
20
21
 
21
22
  class htx(ccxt.async_support.htx):
@@ -109,6 +110,7 @@ class htx(ccxt.async_support.htx):
109
110
  'api': 'api', # or api-aws for clients hosted on AWS
110
111
  'watchOrderBook': {
111
112
  'maxRetries': 3,
113
+ 'checksum': True,
112
114
  },
113
115
  'ws': {
114
116
  'gunzip': True,
@@ -549,7 +551,9 @@ class htx(ccxt.async_support.htx):
549
551
  orderbook.reset(snapshot)
550
552
  orderbook['nonce'] = version
551
553
  if (prevSeqNum is not None) and prevSeqNum > orderbook['nonce']:
552
- raise InvalidNonce(self.id + ' watchOrderBook() received a mesage out of order')
554
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
555
+ if checksum:
556
+ raise ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
553
557
  spotConditon = market['spot'] and (prevSeqNum == orderbook['nonce'])
554
558
  nonSpotCondition = market['contract'] and (version - 1 == orderbook['nonce'])
555
559
  if spotConditon or nonSpotCondition:
@@ -9,7 +9,7 @@ from ccxt.base.types import Int, OrderBook, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import NotSupported
12
- from ccxt.base.errors import InvalidNonce
12
+ from ccxt.base.errors import ChecksumError
13
13
 
14
14
 
15
15
  class independentreserve(ccxt.async_support.independentreserve):
@@ -33,7 +33,9 @@ class independentreserve(ccxt.async_support.independentreserve):
33
33
  },
34
34
  },
35
35
  'options': {
36
- 'checksum': False, # TODO: currently only working for snapshot
36
+ 'watchOrderBook': {
37
+ 'checksum': True, # TODO: currently only working for snapshot
38
+ },
37
39
  },
38
40
  'streaming': {
39
41
  },
@@ -196,7 +198,7 @@ class independentreserve(ccxt.async_support.independentreserve):
196
198
  self.handle_deltas(orderbook['bids'], bids)
197
199
  orderbook['timestamp'] = timestamp
198
200
  orderbook['datetime'] = self.iso8601(timestamp)
199
- checksum = self.safe_bool(self.options, 'checksum', True)
201
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
200
202
  if checksum and receivedSnapshot:
201
203
  storedAsks = orderbook['asks']
202
204
  storedBids = orderbook['bids']
@@ -212,7 +214,7 @@ class independentreserve(ccxt.async_support.independentreserve):
212
214
  calculatedChecksum = self.crc32(payload, True)
213
215
  responseChecksum = self.safe_integer(orderBook, 'Crc32')
214
216
  if calculatedChecksum != responseChecksum:
215
- error = InvalidNonce(self.id + ' invalid checksum')
217
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
216
218
  del client.subscriptions[messageHash]
217
219
  del self.orderbooks[symbol]
218
220
  client.reject(error, messageHash)