ccxt 4.2.96__py2.py3-none-any.whl → 4.2.98__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.
ccxt/__init__.py CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.2.96'
25
+ __version__ = '4.2.98'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.96'
7
+ __version__ = '4.2.98'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.2.96'
5
+ __version__ = '4.2.98'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -5549,7 +5549,7 @@ class binance(Exchange, ImplicitAPI):
5549
5549
  response = await self.papiPostCmOrder(request)
5550
5550
  else:
5551
5551
  response = await self.dapiPrivatePostOrder(request)
5552
- elif marketType == 'margin' or marginMode is not None:
5552
+ elif marketType == 'margin' or marginMode is not None or isPortfolioMargin:
5553
5553
  if isPortfolioMargin:
5554
5554
  response = await self.papiPostMarginOrder(request)
5555
5555
  else:
@@ -5631,12 +5631,6 @@ class binance(Exchange, ImplicitAPI):
5631
5631
  uppercaseType = 'TAKE_PROFIT_MARKET' if market['contract'] else 'TAKE_PROFIT'
5632
5632
  elif isLimitOrder:
5633
5633
  uppercaseType = 'TAKE_PROFIT' if market['contract'] else 'TAKE_PROFIT_LIMIT'
5634
- if (marketType == 'spot') or (marketType == 'margin'):
5635
- request['newOrderRespType'] = self.safe_string(self.options['newOrderRespType'], type, 'RESULT') # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5636
- else:
5637
- # swap, futures and options
5638
- if not isPortfolioMargin:
5639
- request['newOrderRespType'] = 'RESULT' # "ACK", "RESULT", default "ACK"
5640
5634
  if market['option']:
5641
5635
  if type == 'market':
5642
5636
  raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market')
@@ -5664,6 +5658,12 @@ class binance(Exchange, ImplicitAPI):
5664
5658
  uppercaseType = 'LIMIT_MAKER'
5665
5659
  if marginMode == 'isolated':
5666
5660
  request['isIsolated'] = True
5661
+ # handle newOrderRespType response type
5662
+ if ((marketType == 'spot') or (marketType == 'margin')) and not isPortfolioMargin:
5663
+ request['newOrderRespType'] = self.safe_string(self.options['newOrderRespType'], type, 'FULL') # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5664
+ else:
5665
+ # swap, futures and options
5666
+ request['newOrderRespType'] = 'RESULT' # "ACK", "RESULT", default "ACK"
5667
5667
  typeRequest = 'strategyType' if isPortfolioMarginConditional else 'type'
5668
5668
  request[typeRequest] = uppercaseType
5669
5669
  # additional required fields depending on the order type
@@ -6217,7 +6217,7 @@ class binance(Exchange, ImplicitAPI):
6217
6217
  response = await self.papiGetCmOpenOrders(self.extend(request, params))
6218
6218
  else:
6219
6219
  response = await self.dapiPrivateGetOpenOrders(self.extend(request, params))
6220
- elif type == 'margin' or marginMode is not None:
6220
+ elif type == 'margin' or marginMode is not None or isPortfolioMargin:
6221
6221
  if isPortfolioMargin:
6222
6222
  response = await self.papiGetMarginOpenOrders(self.extend(request, params))
6223
6223
  else:
@@ -6646,7 +6646,7 @@ class binance(Exchange, ImplicitAPI):
6646
6646
  response = await self.papiDeleteCmAllOpenOrders(self.extend(request, params))
6647
6647
  else:
6648
6648
  response = await self.dapiPrivateDeleteAllOpenOrders(self.extend(request, params))
6649
- elif (type == 'margin') or (marginMode is not None):
6649
+ elif (type == 'margin') or (marginMode is not None) or isPortfolioMargin:
6650
6650
  if isPortfolioMargin:
6651
6651
  response = await self.papiDeleteMarginAllOpenOrders(self.extend(request, params))
6652
6652
  else:
@@ -1145,12 +1145,16 @@ class coinbase(Exchange, ImplicitAPI):
1145
1145
  self.v3PrivateGetBrokerageProducts(params),
1146
1146
  self.v3PrivateGetBrokerageTransactionSummary(params),
1147
1147
  ]
1148
- unresolvedContractPromises = [
1149
- self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE'})),
1150
- self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1151
- self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE'})),
1152
- self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1153
- ]
1148
+ unresolvedContractPromises = []
1149
+ try:
1150
+ unresolvedContractPromises = [
1151
+ self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE'})),
1152
+ self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1153
+ self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE'})),
1154
+ self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1155
+ ]
1156
+ except Exception as e:
1157
+ unresolvedContractPromises = [] # the sync version of ccxt won't have the promise.all line so the request is made here
1154
1158
  promises = await asyncio.gather(*spotUnresolvedPromises)
1155
1159
  contractPromises = None
1156
1160
  try:
@@ -1184,13 +1184,17 @@ class deribit(Exchange, ImplicitAPI):
1184
1184
  """
1185
1185
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1186
1186
  :see: https://docs.deribit.com/#public-get_book_summary_by_currency
1187
- :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1187
+ :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1188
1188
  :param dict [params]: extra parameters specific to the exchange API endpoint
1189
+ :param str [params.code]: *required* the currency code to fetch the tickers for, eg. 'BTC', 'ETH'
1189
1190
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1190
1191
  """
1191
1192
  await self.load_markets()
1192
1193
  symbols = self.market_symbols(symbols)
1193
- code = self.code_from_options('fetchTickers', params)
1194
+ code = self.safe_string_2(params, 'code', 'currency')
1195
+ params = self.omit(params, ['code'])
1196
+ if code is None:
1197
+ raise ArgumentsRequired(self.id + ' fetchTickers requires a currency/code(eg: BTC/ETH/USDT) parameter to fetch tickers for')
1194
1198
  currency = self.currency(code)
1195
1199
  request = {
1196
1200
  'currency': currency['id'],
@@ -1226,7 +1230,7 @@ class deribit(Exchange, ImplicitAPI):
1226
1230
  # "testnet": False
1227
1231
  # }
1228
1232
  #
1229
- result = self.safe_value(response, 'result', [])
1233
+ result = self.safe_list(response, 'result', [])
1230
1234
  tickers = {}
1231
1235
  for i in range(0, len(result)):
1232
1236
  ticker = self.parse_ticker(result[i])
ccxt/async_support/okx.py CHANGED
@@ -9,6 +9,7 @@ import asyncio
9
9
  import hashlib
10
10
  from ccxt.base.types import Account, Balances, Conversion, Currencies, Currency, Greeks, Int, Leverage, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
11
11
  from typing import List
12
+ from typing import Any
12
13
  from ccxt.base.errors import ExchangeError
13
14
  from ccxt.base.errors import AuthenticationError
14
15
  from ccxt.base.errors import PermissionDenied
@@ -1130,13 +1131,13 @@ class okx(Exchange, ImplicitAPI):
1130
1131
  },
1131
1132
  })
1132
1133
 
1133
- def handle_market_type_and_params(self, methodName, market=None, params={}):
1134
+ def handle_market_type_and_params(self, methodName: str, market: Market = None, params={}, defaultValue=None) -> Any:
1134
1135
  instType = self.safe_string(params, 'instType')
1135
1136
  params = self.omit(params, 'instType')
1136
1137
  type = self.safe_string(params, 'type')
1137
1138
  if (type is None) and (instType is not None):
1138
1139
  params['type'] = instType
1139
- return super(okx, self).handle_market_type_and_params(methodName, market, params)
1140
+ return super(okx, self).handle_market_type_and_params(methodName, market, params, defaultValue)
1140
1141
 
1141
1142
  def convert_to_instrument_type(self, type):
1142
1143
  exchangeTypes = self.safe_dict(self.options, 'exchangeType', {})
@@ -382,7 +382,10 @@ class poloniexfutures(Exchange, ImplicitAPI):
382
382
  #
383
383
  marketId = self.safe_string(ticker, 'symbol')
384
384
  symbol = self.safe_symbol(marketId, market)
385
- timestamp = self.safe_integer_product(ticker, 'ts', 0.000001)
385
+ timestampString = self.safe_string(ticker, 'ts')
386
+ # check timestamp bcz bug: https://app.travis-ci.com/github/ccxt/ccxt/builds/269959181#L4011
387
+ multiplier = 0.00001 if (len(timestampString) == 18) else 0.000001
388
+ timestamp = self.safe_integer_product(ticker, 'ts', multiplier)
386
389
  last = self.safe_string_2(ticker, 'price', 'lastPrice')
387
390
  percentage = Precise.string_mul(self.safe_string(ticker, 'priceChgPct'), '100')
388
391
  return self.safe_ticker({
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.96'
7
+ __version__ = '4.2.98'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -3971,11 +3971,23 @@ class Exchange(object):
3971
3971
  result, empty = self.handle_option_and_params({}, methodName, optionName, defaultValue)
3972
3972
  return result
3973
3973
 
3974
- def handle_market_type_and_params(self, methodName: str, market: Market = None, params={}):
3974
+ def handle_market_type_and_params(self, methodName: str, market: Market = None, params={}, defaultValue=None):
3975
+ """
3976
+ * @ignore
3977
+ * @param methodName the method calling handleMarketTypeAndParams
3978
+ :param Market market:
3979
+ :param dict params:
3980
+ :param str [params.type]: type assigned by user
3981
+ :param str [params.defaultType]: same.type
3982
+ :param str [defaultValue]: assigned programatically in the method calling handleMarketTypeAndParams
3983
+ :returns [str, dict]: the market type and params with type and defaultType omitted
3984
+ """
3975
3985
  defaultType = self.safe_string_2(self.options, 'defaultType', 'type', 'spot')
3986
+ if defaultValue is None: # defaultValue takes precendence over exchange wide defaultType
3987
+ defaultValue = defaultType
3976
3988
  methodOptions = self.safe_dict(self.options, methodName)
3977
- methodType = defaultType
3978
- if methodOptions is not None:
3989
+ methodType = defaultValue
3990
+ if methodOptions is not None: # user defined methodType takes precedence over defaultValue
3979
3991
  if isinstance(methodOptions, str):
3980
3992
  methodType = methodOptions
3981
3993
  else:
ccxt/binance.py CHANGED
@@ -5548,7 +5548,7 @@ class binance(Exchange, ImplicitAPI):
5548
5548
  response = self.papiPostCmOrder(request)
5549
5549
  else:
5550
5550
  response = self.dapiPrivatePostOrder(request)
5551
- elif marketType == 'margin' or marginMode is not None:
5551
+ elif marketType == 'margin' or marginMode is not None or isPortfolioMargin:
5552
5552
  if isPortfolioMargin:
5553
5553
  response = self.papiPostMarginOrder(request)
5554
5554
  else:
@@ -5630,12 +5630,6 @@ class binance(Exchange, ImplicitAPI):
5630
5630
  uppercaseType = 'TAKE_PROFIT_MARKET' if market['contract'] else 'TAKE_PROFIT'
5631
5631
  elif isLimitOrder:
5632
5632
  uppercaseType = 'TAKE_PROFIT' if market['contract'] else 'TAKE_PROFIT_LIMIT'
5633
- if (marketType == 'spot') or (marketType == 'margin'):
5634
- request['newOrderRespType'] = self.safe_string(self.options['newOrderRespType'], type, 'RESULT') # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5635
- else:
5636
- # swap, futures and options
5637
- if not isPortfolioMargin:
5638
- request['newOrderRespType'] = 'RESULT' # "ACK", "RESULT", default "ACK"
5639
5633
  if market['option']:
5640
5634
  if type == 'market':
5641
5635
  raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market')
@@ -5663,6 +5657,12 @@ class binance(Exchange, ImplicitAPI):
5663
5657
  uppercaseType = 'LIMIT_MAKER'
5664
5658
  if marginMode == 'isolated':
5665
5659
  request['isIsolated'] = True
5660
+ # handle newOrderRespType response type
5661
+ if ((marketType == 'spot') or (marketType == 'margin')) and not isPortfolioMargin:
5662
+ request['newOrderRespType'] = self.safe_string(self.options['newOrderRespType'], type, 'FULL') # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5663
+ else:
5664
+ # swap, futures and options
5665
+ request['newOrderRespType'] = 'RESULT' # "ACK", "RESULT", default "ACK"
5666
5666
  typeRequest = 'strategyType' if isPortfolioMarginConditional else 'type'
5667
5667
  request[typeRequest] = uppercaseType
5668
5668
  # additional required fields depending on the order type
@@ -6216,7 +6216,7 @@ class binance(Exchange, ImplicitAPI):
6216
6216
  response = self.papiGetCmOpenOrders(self.extend(request, params))
6217
6217
  else:
6218
6218
  response = self.dapiPrivateGetOpenOrders(self.extend(request, params))
6219
- elif type == 'margin' or marginMode is not None:
6219
+ elif type == 'margin' or marginMode is not None or isPortfolioMargin:
6220
6220
  if isPortfolioMargin:
6221
6221
  response = self.papiGetMarginOpenOrders(self.extend(request, params))
6222
6222
  else:
@@ -6645,7 +6645,7 @@ class binance(Exchange, ImplicitAPI):
6645
6645
  response = self.papiDeleteCmAllOpenOrders(self.extend(request, params))
6646
6646
  else:
6647
6647
  response = self.dapiPrivateDeleteAllOpenOrders(self.extend(request, params))
6648
- elif (type == 'margin') or (marginMode is not None):
6648
+ elif (type == 'margin') or (marginMode is not None) or isPortfolioMargin:
6649
6649
  if isPortfolioMargin:
6650
6650
  response = self.papiDeleteMarginAllOpenOrders(self.extend(request, params))
6651
6651
  else:
ccxt/coinbase.py CHANGED
@@ -1144,12 +1144,16 @@ class coinbase(Exchange, ImplicitAPI):
1144
1144
  self.v3PrivateGetBrokerageProducts(params),
1145
1145
  self.v3PrivateGetBrokerageTransactionSummary(params),
1146
1146
  ]
1147
- unresolvedContractPromises = [
1148
- self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE'})),
1149
- self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1150
- self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE'})),
1151
- self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1152
- ]
1147
+ unresolvedContractPromises = []
1148
+ try:
1149
+ unresolvedContractPromises = [
1150
+ self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE'})),
1151
+ self.v3PrivateGetBrokerageProducts(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1152
+ self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE'})),
1153
+ self.v3PrivateGetBrokerageTransactionSummary(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1154
+ ]
1155
+ except Exception as e:
1156
+ unresolvedContractPromises = [] # the sync version of ccxt won't have the promise.all line so the request is made here
1153
1157
  promises = spotUnresolvedPromises
1154
1158
  contractPromises = None
1155
1159
  try:
ccxt/deribit.py CHANGED
@@ -1184,13 +1184,17 @@ class deribit(Exchange, ImplicitAPI):
1184
1184
  """
1185
1185
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1186
1186
  :see: https://docs.deribit.com/#public-get_book_summary_by_currency
1187
- :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1187
+ :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1188
1188
  :param dict [params]: extra parameters specific to the exchange API endpoint
1189
+ :param str [params.code]: *required* the currency code to fetch the tickers for, eg. 'BTC', 'ETH'
1189
1190
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1190
1191
  """
1191
1192
  self.load_markets()
1192
1193
  symbols = self.market_symbols(symbols)
1193
- code = self.code_from_options('fetchTickers', params)
1194
+ code = self.safe_string_2(params, 'code', 'currency')
1195
+ params = self.omit(params, ['code'])
1196
+ if code is None:
1197
+ raise ArgumentsRequired(self.id + ' fetchTickers requires a currency/code(eg: BTC/ETH/USDT) parameter to fetch tickers for')
1194
1198
  currency = self.currency(code)
1195
1199
  request = {
1196
1200
  'currency': currency['id'],
@@ -1226,7 +1230,7 @@ class deribit(Exchange, ImplicitAPI):
1226
1230
  # "testnet": False
1227
1231
  # }
1228
1232
  #
1229
- result = self.safe_value(response, 'result', [])
1233
+ result = self.safe_list(response, 'result', [])
1230
1234
  tickers = {}
1231
1235
  for i in range(0, len(result)):
1232
1236
  ticker = self.parse_ticker(result[i])
ccxt/okx.py CHANGED
@@ -8,6 +8,7 @@ from ccxt.abstract.okx import ImplicitAPI
8
8
  import hashlib
9
9
  from ccxt.base.types import Account, Balances, Conversion, Currencies, Currency, Greeks, Int, Leverage, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
10
10
  from typing import List
11
+ from typing import Any
11
12
  from ccxt.base.errors import ExchangeError
12
13
  from ccxt.base.errors import AuthenticationError
13
14
  from ccxt.base.errors import PermissionDenied
@@ -1129,13 +1130,13 @@ class okx(Exchange, ImplicitAPI):
1129
1130
  },
1130
1131
  })
1131
1132
 
1132
- def handle_market_type_and_params(self, methodName, market=None, params={}):
1133
+ def handle_market_type_and_params(self, methodName: str, market: Market = None, params={}, defaultValue=None) -> Any:
1133
1134
  instType = self.safe_string(params, 'instType')
1134
1135
  params = self.omit(params, 'instType')
1135
1136
  type = self.safe_string(params, 'type')
1136
1137
  if (type is None) and (instType is not None):
1137
1138
  params['type'] = instType
1138
- return super(okx, self).handle_market_type_and_params(methodName, market, params)
1139
+ return super(okx, self).handle_market_type_and_params(methodName, market, params, defaultValue)
1139
1140
 
1140
1141
  def convert_to_instrument_type(self, type):
1141
1142
  exchangeTypes = self.safe_dict(self.options, 'exchangeType', {})
ccxt/poloniexfutures.py CHANGED
@@ -382,7 +382,10 @@ class poloniexfutures(Exchange, ImplicitAPI):
382
382
  #
383
383
  marketId = self.safe_string(ticker, 'symbol')
384
384
  symbol = self.safe_symbol(marketId, market)
385
- timestamp = self.safe_integer_product(ticker, 'ts', 0.000001)
385
+ timestampString = self.safe_string(ticker, 'ts')
386
+ # check timestamp bcz bug: https://app.travis-ci.com/github/ccxt/ccxt/builds/269959181#L4011
387
+ multiplier = 0.00001 if (len(timestampString) == 18) else 0.000001
388
+ timestamp = self.safe_integer_product(ticker, 'ts', multiplier)
386
389
  last = self.safe_string_2(ticker, 'price', 'lastPrice')
387
390
  percentage = Precise.string_mul(self.safe_string(ticker, 'priceChgPct'), '100')
388
391
  return self.safe_ticker({
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.2.96'
7
+ __version__ = '4.2.98'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/binance.py CHANGED
@@ -9,10 +9,10 @@ import hashlib
9
9
  from ccxt.base.types import Balances, Int, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
- from ccxt.base.errors import ExchangeError
13
12
  from ccxt.base.errors import ArgumentsRequired
14
13
  from ccxt.base.errors import BadRequest
15
14
  from ccxt.base.errors import NotSupported
15
+ from ccxt.base.errors import InvalidNonce
16
16
  from ccxt.base.precise import Precise
17
17
 
18
18
 
@@ -400,8 +400,10 @@ class binance(ccxt.async_support.binance):
400
400
  if nonce < orderbook['nonce']:
401
401
  client.resolve(orderbook, messageHash)
402
402
  else:
403
- # todo: client.reject from handleOrderBookMessage properly
404
- raise ExchangeError(self.id + ' handleOrderBook received an out-of-order nonce')
403
+ checksum = self.safe_bool(self.options, 'checksum', True)
404
+ if checksum:
405
+ # todo: client.reject from handleOrderBookMessage properly
406
+ raise InvalidNonce(self.id + ' handleOrderBook received an out-of-order nonce')
405
407
  else:
406
408
  # future
407
409
  # 4. Drop any event where u is < lastUpdateId in the snapshot
@@ -413,8 +415,10 @@ class binance(ccxt.async_support.binance):
413
415
  if nonce <= orderbook['nonce']:
414
416
  client.resolve(orderbook, messageHash)
415
417
  else:
416
- # todo: client.reject from handleOrderBookMessage properly
417
- raise ExchangeError(self.id + ' handleOrderBook received an out-of-order nonce')
418
+ checksum = self.safe_bool(self.options, 'checksum', True)
419
+ if checksum:
420
+ # todo: client.reject from handleOrderBookMessage properly
421
+ raise InvalidNonce(self.id + ' handleOrderBook received an out-of-order nonce')
418
422
  except Exception as e:
419
423
  del self.orderbooks[symbol]
420
424
  del client.subscriptions[messageHash]
@@ -8,9 +8,9 @@ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById
8
8
  from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
- from ccxt.base.errors import ExchangeError
12
11
  from ccxt.base.errors import AuthenticationError
13
12
  from ccxt.base.errors import BadRequest
13
+ from ccxt.base.errors import InvalidNonce
14
14
 
15
15
 
16
16
  class poloniexfutures(ccxt.async_support.poloniexfutures):
@@ -817,7 +817,10 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
817
817
  sequence = self.safe_integer(delta, 'sequence')
818
818
  nonce = self.safe_integer(orderbook, 'nonce')
819
819
  if nonce != sequence - 1:
820
- raise ExchangeError(self.id + ' watchOrderBook received an out-of-order nonce')
820
+ checksum = self.safe_bool(self.options, 'checksum', True)
821
+ if checksum:
822
+ # todo: client.reject from handleOrderBookMessage properly
823
+ raise InvalidNonce(self.id + ' watchOrderBook received an out-of-order nonce')
821
824
  change = self.safe_string(delta, 'change')
822
825
  splitChange = change.split(',')
823
826
  price = self.safe_number(splitChange, 0)
@@ -24,7 +24,9 @@ def test_order_book(exchange, skipped_properties, method, orderbook, symbol):
24
24
  'datetime': '2017-09-01T00:00:00',
25
25
  'nonce': 134234234,
26
26
  }
27
- empty_allowed_for = ['symbol', 'nonce', 'datetime', 'timestamp'] # todo: make timestamp required
27
+ empty_allowed_for = ['nonce']
28
+ # turn into copy: https://discord.com/channels/690203284119617602/921046068555313202/1220626834887282728
29
+ orderbook = exchange.deep_extend({}, orderbook)
28
30
  test_shared_methods.assert_structure(exchange, skipped_properties, method, orderbook, format, empty_allowed_for)
29
31
  test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, orderbook)
30
32
  test_shared_methods.assert_symbol(exchange, skipped_properties, method, orderbook, 'symbol', symbol)
@@ -37,24 +39,28 @@ def test_order_book(exchange, skipped_properties, method, orderbook, symbol):
37
39
  bids_length = len(bids)
38
40
  for i in range(0, bids_length):
39
41
  current_bid_string = exchange.safe_string(bids[i], 0)
40
- next_i = i + 1
41
- if bids_length > next_i:
42
- next_bid_string = exchange.safe_string(bids[next_i], 0)
43
- has_correct_order = Precise.string_gt(current_bid_string, next_bid_string)
44
- assert has_correct_order, 'current bid should be > than the next one: ' + current_bid_string + '>' + next_bid_string + log_text
45
- test_shared_methods.assert_greater(exchange, skipped_properties, method, bids[i], 0, '0')
46
- test_shared_methods.assert_greater(exchange, skipped_properties, method, bids[i], 1, '0')
42
+ if not ('compareToNextItem' in skipped_properties):
43
+ next_i = i + 1
44
+ if bids_length > next_i:
45
+ next_bid_string = exchange.safe_string(bids[next_i], 0)
46
+ assert Precise.string_gt(current_bid_string, next_bid_string), 'current bid should be > than the next one: ' + current_bid_string + '>' + next_bid_string + log_text
47
+ if not ('compareToZero' in skipped_properties):
48
+ # compare price & volume to zero
49
+ test_shared_methods.assert_greater(exchange, skipped_properties, method, bids[i], 0, '0')
50
+ test_shared_methods.assert_greater(exchange, skipped_properties, method, bids[i], 1, '0')
47
51
  asks = orderbook['asks']
48
52
  asks_length = len(asks)
49
53
  for i in range(0, asks_length):
50
54
  current_ask_string = exchange.safe_string(asks[i], 0)
51
- next_i = i + 1
52
- if asks_length > next_i:
53
- next_ask_string = exchange.safe_string(asks[next_i], 0)
54
- has_correct_order = Precise.string_lt(current_ask_string, next_ask_string)
55
- assert has_correct_order, 'current ask should be < than the next one: ' + current_ask_string + '<' + next_ask_string + log_text
56
- test_shared_methods.assert_greater(exchange, skipped_properties, method, asks[i], 0, '0')
57
- test_shared_methods.assert_greater(exchange, skipped_properties, method, asks[i], 1, '0')
55
+ if not ('compareToNextItem' in skipped_properties):
56
+ next_i = i + 1
57
+ if asks_length > next_i:
58
+ next_ask_string = exchange.safe_string(asks[next_i], 0)
59
+ assert Precise.string_lt(current_ask_string, next_ask_string), 'current ask should be < than the next one: ' + current_ask_string + '<' + next_ask_string + log_text
60
+ if not ('compareToZero' in skipped_properties):
61
+ # compare price & volume to zero
62
+ test_shared_methods.assert_greater(exchange, skipped_properties, method, asks[i], 0, '0')
63
+ test_shared_methods.assert_greater(exchange, skipped_properties, method, asks[i], 1, '0')
58
64
  if not ('spread' in skipped_properties):
59
65
  if bids_length and asks_length:
60
66
  first_bid = exchange.safe_string(bids[0], 0)
ccxt/test/test_async.py CHANGED
@@ -422,9 +422,13 @@ class testMainClass(baseMainTestClass):
422
422
  return result
423
423
 
424
424
  async def test_method(self, method_name, exchange, args, is_public):
425
+ # todo: temporary skip for c#
426
+ if 'OrderBook' in method_name and self.ext == 'cs':
427
+ exchange.options['checksum'] = False
425
428
  # todo: temporary skip for php
426
429
  if 'OrderBook' in method_name and self.ext == 'php':
427
430
  return
431
+ skipped_properties_for_method = self.get_skips(exchange, method_name)
428
432
  is_load_markets = (method_name == 'loadMarkets')
429
433
  is_fetch_currencies = (method_name == 'fetchCurrencies')
430
434
  is_proxy_test = (method_name == self.proxy_test_file_name)
@@ -437,7 +441,7 @@ class testMainClass(baseMainTestClass):
437
441
  skip_message = '[INFO] IGNORED_TEST'
438
442
  elif not is_load_markets and not supported_by_exchange and not is_proxy_test:
439
443
  skip_message = '[INFO] UNSUPPORTED_TEST' # keep it aligned with the longest message
440
- elif (method_name in self.skipped_methods) and (isinstance(self.skipped_methods[method_name], str)):
444
+ elif isinstance(skipped_properties_for_method, str):
441
445
  skip_message = '[INFO] SKIPPED_TEST'
442
446
  elif not (method_name in self.test_files):
443
447
  skip_message = '[INFO] UNIMPLEMENTED_TEST'
@@ -451,15 +455,24 @@ class testMainClass(baseMainTestClass):
451
455
  if self.info:
452
456
  args_stringified = '(' + ','.join(args) + ')'
453
457
  dump(self.add_padding('[INFO] TESTING', 25), self.exchange_hint(exchange), method_name, args_stringified)
454
- await call_method(self.test_files, method_name, exchange, self.get_skips(exchange, method_name), args)
458
+ await call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
455
459
  # if it was passed successfully, add to the list of successfull tests
456
460
  if is_public:
457
461
  self.checked_public_tests[method_name] = True
458
462
  return
459
463
 
460
464
  def get_skips(self, exchange, method_name):
461
- # get "method-specific" skips
462
- skips_for_method = exchange.safe_value(self.skipped_methods, method_name, {})
465
+ final_skips = {}
466
+ # check the exact method (i.e. `fetchTrades`) and language-specific (i.e. `fetchTrades.php`)
467
+ method_names = [method_name, method_name + '.' + self.ext]
468
+ for i in range(0, len(method_names)):
469
+ m_name = method_names[i]
470
+ if m_name in self.skipped_methods:
471
+ # if whole method is skipped, by assigning a string to it, i.e. "fetchOrders":"blabla"
472
+ if isinstance(self.skipped_methods[m_name], str):
473
+ return self.skipped_methods[m_name]
474
+ else:
475
+ final_skips = exchange.deep_extend(final_skips, self.skipped_methods[m_name])
463
476
  # get "object-specific" skips
464
477
  object_skips = {
465
478
  'orderBook': ['fetchOrderBook', 'fetchOrderBooks', 'fetchL2OrderBook', 'watchOrderBook', 'watchOrderBookForSymbols'],
@@ -475,9 +488,19 @@ class testMainClass(baseMainTestClass):
475
488
  object_name = object_names[i]
476
489
  object_methods = object_skips[object_name]
477
490
  if exchange.in_array(method_name, object_methods):
491
+ # if whole object is skipped, by assigning a string to it, i.e. "orderBook":"blabla"
492
+ if (object_name in self.skipped_methods) and (isinstance(self.skipped_methods[object_name], str)):
493
+ return self.skipped_methods[object_name]
478
494
  extra_skips = exchange.safe_dict(self.skipped_methods, object_name, {})
479
- return exchange.deep_extend(skips_for_method, extra_skips)
480
- return skips_for_method
495
+ final_skips = exchange.deep_extend(final_skips, extra_skips)
496
+ # extend related skips
497
+ # - if 'timestamp' is skipped, we should do so for 'datetime' too
498
+ # - if 'bid' is skipped, skip 'ask' too
499
+ if ('timestamp' in final_skips) and not ('datetime' in final_skips):
500
+ final_skips['datetime'] = final_skips['timestamp']
501
+ if ('bid' in final_skips) and not ('ask' in final_skips):
502
+ final_skips['ask'] = final_skips['bid']
503
+ return final_skips
481
504
 
482
505
  async def test_safe(self, method_name, exchange, args=[], is_public=False):
483
506
  # `testSafe` method does not throw an exception, instead mutes it. The reason we
@@ -569,11 +592,14 @@ class testMainClass(baseMainTestClass):
569
592
  if self.ws_tests:
570
593
  tests = {
571
594
  'watchOHLCV': [symbol],
595
+ 'watchOHLCVForSymbols': [symbol],
572
596
  'watchTicker': [symbol],
573
597
  'watchTickers': [symbol],
574
598
  'watchBidsAsks': [symbol],
575
599
  'watchOrderBook': [symbol],
600
+ 'watchOrderBookForSymbols': [[symbol]],
576
601
  'watchTrades': [symbol],
602
+ 'watchTradesForSymbols': [[symbol]],
577
603
  }
578
604
  market = exchange.market(symbol)
579
605
  is_spot = market['spot']
ccxt/test/test_sync.py CHANGED
@@ -421,9 +421,13 @@ class testMainClass(baseMainTestClass):
421
421
  return result
422
422
 
423
423
  def test_method(self, method_name, exchange, args, is_public):
424
+ # todo: temporary skip for c#
425
+ if 'OrderBook' in method_name and self.ext == 'cs':
426
+ exchange.options['checksum'] = False
424
427
  # todo: temporary skip for php
425
428
  if 'OrderBook' in method_name and self.ext == 'php':
426
429
  return
430
+ skipped_properties_for_method = self.get_skips(exchange, method_name)
427
431
  is_load_markets = (method_name == 'loadMarkets')
428
432
  is_fetch_currencies = (method_name == 'fetchCurrencies')
429
433
  is_proxy_test = (method_name == self.proxy_test_file_name)
@@ -436,7 +440,7 @@ class testMainClass(baseMainTestClass):
436
440
  skip_message = '[INFO] IGNORED_TEST'
437
441
  elif not is_load_markets and not supported_by_exchange and not is_proxy_test:
438
442
  skip_message = '[INFO] UNSUPPORTED_TEST' # keep it aligned with the longest message
439
- elif (method_name in self.skipped_methods) and (isinstance(self.skipped_methods[method_name], str)):
443
+ elif isinstance(skipped_properties_for_method, str):
440
444
  skip_message = '[INFO] SKIPPED_TEST'
441
445
  elif not (method_name in self.test_files):
442
446
  skip_message = '[INFO] UNIMPLEMENTED_TEST'
@@ -450,15 +454,24 @@ class testMainClass(baseMainTestClass):
450
454
  if self.info:
451
455
  args_stringified = '(' + ','.join(args) + ')'
452
456
  dump(self.add_padding('[INFO] TESTING', 25), self.exchange_hint(exchange), method_name, args_stringified)
453
- call_method(self.test_files, method_name, exchange, self.get_skips(exchange, method_name), args)
457
+ call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
454
458
  # if it was passed successfully, add to the list of successfull tests
455
459
  if is_public:
456
460
  self.checked_public_tests[method_name] = True
457
461
  return
458
462
 
459
463
  def get_skips(self, exchange, method_name):
460
- # get "method-specific" skips
461
- skips_for_method = exchange.safe_value(self.skipped_methods, method_name, {})
464
+ final_skips = {}
465
+ # check the exact method (i.e. `fetchTrades`) and language-specific (i.e. `fetchTrades.php`)
466
+ method_names = [method_name, method_name + '.' + self.ext]
467
+ for i in range(0, len(method_names)):
468
+ m_name = method_names[i]
469
+ if m_name in self.skipped_methods:
470
+ # if whole method is skipped, by assigning a string to it, i.e. "fetchOrders":"blabla"
471
+ if isinstance(self.skipped_methods[m_name], str):
472
+ return self.skipped_methods[m_name]
473
+ else:
474
+ final_skips = exchange.deep_extend(final_skips, self.skipped_methods[m_name])
462
475
  # get "object-specific" skips
463
476
  object_skips = {
464
477
  'orderBook': ['fetchOrderBook', 'fetchOrderBooks', 'fetchL2OrderBook', 'watchOrderBook', 'watchOrderBookForSymbols'],
@@ -474,9 +487,19 @@ class testMainClass(baseMainTestClass):
474
487
  object_name = object_names[i]
475
488
  object_methods = object_skips[object_name]
476
489
  if exchange.in_array(method_name, object_methods):
490
+ # if whole object is skipped, by assigning a string to it, i.e. "orderBook":"blabla"
491
+ if (object_name in self.skipped_methods) and (isinstance(self.skipped_methods[object_name], str)):
492
+ return self.skipped_methods[object_name]
477
493
  extra_skips = exchange.safe_dict(self.skipped_methods, object_name, {})
478
- return exchange.deep_extend(skips_for_method, extra_skips)
479
- return skips_for_method
494
+ final_skips = exchange.deep_extend(final_skips, extra_skips)
495
+ # extend related skips
496
+ # - if 'timestamp' is skipped, we should do so for 'datetime' too
497
+ # - if 'bid' is skipped, skip 'ask' too
498
+ if ('timestamp' in final_skips) and not ('datetime' in final_skips):
499
+ final_skips['datetime'] = final_skips['timestamp']
500
+ if ('bid' in final_skips) and not ('ask' in final_skips):
501
+ final_skips['ask'] = final_skips['bid']
502
+ return final_skips
480
503
 
481
504
  def test_safe(self, method_name, exchange, args=[], is_public=False):
482
505
  # `testSafe` method does not throw an exception, instead mutes it. The reason we
@@ -568,11 +591,14 @@ class testMainClass(baseMainTestClass):
568
591
  if self.ws_tests:
569
592
  tests = {
570
593
  'watchOHLCV': [symbol],
594
+ 'watchOHLCVForSymbols': [symbol],
571
595
  'watchTicker': [symbol],
572
596
  'watchTickers': [symbol],
573
597
  'watchBidsAsks': [symbol],
574
598
  'watchOrderBook': [symbol],
599
+ 'watchOrderBookForSymbols': [[symbol]],
575
600
  'watchTrades': [symbol],
601
+ 'watchTradesForSymbols': [[symbol]],
576
602
  }
577
603
  market = exchange.market(symbol)
578
604
  is_spot = market['spot']
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.2.96
3
+ Version: 4.2.98
4
4
  Summary: A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges
5
5
  Home-page: https://ccxt.com
6
6
  Author: Igor Kroitor
@@ -261,13 +261,13 @@ console.log(version, Object.keys(exchanges));
261
261
 
262
262
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
263
263
 
264
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.96/dist/ccxt.browser.js
265
- * unpkg: https://unpkg.com/ccxt@4.2.96/dist/ccxt.browser.js
264
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.98/dist/ccxt.browser.js
265
+ * unpkg: https://unpkg.com/ccxt@4.2.98/dist/ccxt.browser.js
266
266
 
267
267
  CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.
268
268
 
269
269
  ```HTML
270
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.96/dist/ccxt.browser.js"></script>
270
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.98/dist/ccxt.browser.js"></script>
271
271
  ```
272
272
 
273
273
  Creates a global `ccxt` object:
@@ -1,10 +1,10 @@
1
- ccxt/__init__.py,sha256=43zJhs0hiTK99gkjK-1h479YAkJyEQU8IMiMQfgMk4U,15656
1
+ ccxt/__init__.py,sha256=hwc6b-49WBIAq4eWEXFgYDG2T41qHgkeCTilPkDk9hA,15656
2
2
  ccxt/ace.py,sha256=yGGKYViya2zCyr1DjWhEu9mknkDAEVsobHmrvJxHfX0,41420
3
3
  ccxt/alpaca.py,sha256=6P2wAEGJQOjjoKQbzv1KvSuZvEZmOX987a1NqB7z9mk,46908
4
4
  ccxt/ascendex.py,sha256=AeDB6xaWaOGBMlsmm8886etqQ3_IOxhtvY5201sjGYc,151300
5
5
  ccxt/bequant.py,sha256=RBiAmaTbL35DgiV3Hl6uchLUd78V0z1T9riTlNsrpdc,1174
6
6
  ccxt/bigone.py,sha256=rgg8BdMqBPa0jJjDh9xP7Y7Y6lMKAIJXzmE-g6EEm4I,92185
7
- ccxt/binance.py,sha256=SQi-_meSeR9xqGr7m9w-C7WJrvu9OAlyJ_QEcE75xBw,596881
7
+ ccxt/binance.py,sha256=9asBcH4nAt_DKfg1IViC7TXFbaARjAJSwAdxfOz127w,596976
8
8
  ccxt/binancecoinm.py,sha256=pncdw6Xw2X1Po-vEvAB4nL37scoS_axGAVxetPy1YQs,1645
9
9
  ccxt/binanceus.py,sha256=hdcT4OnadcdFFFjF3GtM0nWv90jqojqwdVS3xWGuW40,9163
10
10
  ccxt/binanceusdm.py,sha256=KPQGlCalQ0eGlPCs2tSanOxaP8O0zFRQjGntA16Yprw,2480
@@ -37,7 +37,7 @@ ccxt/btcmarkets.py,sha256=XOoDrXKNLvqMbNTUmTNMkQzsyy7oOh_Dw1USiJ8WjEs,51328
37
37
  ccxt/btcturk.py,sha256=p-_zpUEu0aIK5kR4PXQKnAqr9P0ajFsaszyFylUOHeE,36506
38
38
  ccxt/bybit.py,sha256=PgvPYqeTrs9z-qzhjlr6Tqy7heLOQDc1ENH_5FSlcbU,401635
39
39
  ccxt/cex.py,sha256=CfQ_1t-Em16bYl-5DmzqJzC8rxrdk9CCxq7Q0ON7vOM,69653
40
- ccxt/coinbase.py,sha256=Ca2SGlOvxeVmSh0b2AZ0j-OTkkegwq46rYf7EbStHyo,201436
40
+ ccxt/coinbase.py,sha256=Xq1Hm1Dshq9BRSh4aJj60-_gZsKeZoHKB_6aZwXBFzU,201676
41
41
  ccxt/coinbaseinternational.py,sha256=RnTdgTmkia2wpMBW2pZR_yvUzWIC-7hfXFun8v6pW0k,87123
42
42
  ccxt/coinbasepro.py,sha256=JdHrR6nr9sBmxsPfiql_pRGM5y8mP4NRUV1viSCeKwU,78377
43
43
  ccxt/coincheck.py,sha256=16rD9tUt0Ww8pjSTDD1CQ28wusKil0FnFRiUvzj9FwQ,35513
@@ -51,7 +51,7 @@ ccxt/coinspot.py,sha256=rtHhup6v6HbDCAVrZyVJJqOooJ_zoRWU0OqkEjLYL3E,23463
51
51
  ccxt/cryptocom.py,sha256=PhTk81lXAMzD_nD7VPsDxSfZ7Kko5Xz4iYY1bSLXy4I,128158
52
52
  ccxt/currencycom.py,sha256=Y0foIftGaqxSRpkjgO-XTGifgFKnAINXYtrJRtBODYM,86759
53
53
  ccxt/delta.py,sha256=vAGScpoJrch6xduLxdMsbvXA4aqQrtxcoUhZG3Z2Ejo,150437
54
- ccxt/deribit.py,sha256=w7y7FM3NhN9HJ5603lVbzoWC7Tnw8vRzLROjK4CavGo,160139
54
+ ccxt/deribit.py,sha256=_3JG8JYuZWPY94a-iOANaaTvihCQoVxyry9ZbN8Iu0k,160448
55
55
  ccxt/digifinex.py,sha256=tDUe72Dhuh6SIDLkEnVZJ_Xad8eCJOiFoi9KfJj6Ss0,167871
56
56
  ccxt/exmo.py,sha256=iL0IFXeCLadEn4SS8vjz-_5cC_k22iMJsgYVpUO6Kqs,114203
57
57
  ccxt/flowbtc.py,sha256=YPvm6tbsHJJUQBspFcHuVPQfVmiWzwnVvfzRqBdQX6U,1169
@@ -84,13 +84,13 @@ ccxt/ndax.py,sha256=XnKg7cvTovRChHoBKWvmpw_gPqQqEzRhwnNMYqWCahk,108368
84
84
  ccxt/novadax.py,sha256=lIEsXXc0JhVvJHosOx6OgAD8348nwkJGUaHTawv3R7g,64105
85
85
  ccxt/oceanex.py,sha256=YH3tUzegvfG0fUCjtmtb3USOQtlL1tlqQ40B_i-xx7w,37860
86
86
  ccxt/okcoin.py,sha256=11q59Tj1zKA4yWG2ppTpF9PQJmATnpXDYZqeiNdW8nE,151105
87
- ccxt/okx.py,sha256=MGj7A_61zDoAs_HdRef148cWFi1g985ZFqq6cDYf0Vk,354637
87
+ ccxt/okx.py,sha256=lLSjyfj7V7OjMIOsYLoG2S60i8nbUsBJgtH3XRuFlBo,354715
88
88
  ccxt/onetrading.py,sha256=-Jda6aa1YmjfiiJ80SuncaNxaWjyNKnmLL5ZZ9wialo,87957
89
89
  ccxt/p2b.py,sha256=Uea-rKf4-h9G3h9OmrmPU17IGmRqZMhqKdD8h_RLj_M,54074
90
90
  ccxt/paymium.py,sha256=2mBwmyT93k-dXBEKEix48G8PsA2IEN_5yScEM985Z10,24203
91
91
  ccxt/phemex.py,sha256=qQXlWB0pgUtL9A3G7-ubFhd68rTkPczynH4GoRFo95Y,218625
92
92
  ccxt/poloniex.py,sha256=koq79DTlr9oJF0tnzPpt-JRh1sTc0ScBf-GFT4bLhpo,101948
93
- ccxt/poloniexfutures.py,sha256=qsryuAIQtD8YWhZ6-nIKkjpT6ngSf5DRFjx4c0njnDw,77370
93
+ ccxt/poloniexfutures.py,sha256=zXGjift4nWCN5fzWPFaYTJyhAqxTI29tJXZIqg7u05w,77605
94
94
  ccxt/probit.py,sha256=RwgQAxfYjhYY_YxbUtsfqGFI3bJ09JlUUGQwYqvQ-CE,76208
95
95
  ccxt/timex.py,sha256=h8R1F-PPV0IBXhHF0EuX_b7Q7vdgRyC5j-H8TA0VJFw,71136
96
96
  ccxt/tokocrypto.py,sha256=4k0Rk6278w8JQAIZwNU-Pr33ApYHkrPQXxUXRZlT06U,123002
@@ -207,13 +207,13 @@ ccxt/abstract/woo.py,sha256=E-QXVJKVI4EOW72NX6wv99px9EyitWtd9KWvXUc9Tyo,10216
207
207
  ccxt/abstract/yobit.py,sha256=8ycfCO8ORFly9hc0Aa47sZyX4_ZKPXS9h9yJzI-uQ7Q,1339
208
208
  ccxt/abstract/zaif.py,sha256=m15WHdl3gYy0GOXNZ8NEH8eE7sVh8c0T_ITNuU8vXeU,3935
209
209
  ccxt/abstract/zonda.py,sha256=aSfewvRojzmuymX6QbOnDR8v9VFqWTULMHX9Y7kKD1M,5820
210
- ccxt/async_support/__init__.py,sha256=SteHw_iRK4tWZl09wtTZFsl25vmQGUQLaCxwHXuAd9Q,15409
210
+ ccxt/async_support/__init__.py,sha256=QkyvCUCebG19z0MknUqav-XQlxZkx3LaObH2-TEv42s,15409
211
211
  ccxt/async_support/ace.py,sha256=kbkibefA6HaHJSNoL_MPmbPUn7n2wyruxBOR7BXmUmQ,41644
212
212
  ccxt/async_support/alpaca.py,sha256=Nsaff9RczBhiNF19RlqI6wggvEibV_2ICgB8H5Qiuck,47120
213
213
  ccxt/async_support/ascendex.py,sha256=QGyP437RJJutP1Wau_B5JyMLtvwgvaMg15zlQXDhfUE,152088
214
214
  ccxt/async_support/bequant.py,sha256=1hTwHovo1bW1XTIc8ZKjvJ-Xg6LfmpGdzT7TepykaVM,1188
215
215
  ccxt/async_support/bigone.py,sha256=_B8qO9qQWVMSd5c-CeBmYtm_IsrkweAZPTLUf7hiQaI,92639
216
- ccxt/async_support/binance.py,sha256=EvCLyzD7cFNot2y99wAkl2AlqrkUtqN4WBkgweyCVww,599459
216
+ ccxt/async_support/binance.py,sha256=eQbd5uw_bRqM_wbwyVUeQHQk2ZIZd9j1YThtuppflHw,599554
217
217
  ccxt/async_support/binancecoinm.py,sha256=IY3RLZptQA2nmZaUYRGfTa5ZY4VMWBpFYfwHc8zTHw0,1683
218
218
  ccxt/async_support/binanceus.py,sha256=c-K3Tk7LaRJjmYdCx8vBOqsx01uXrtvt0PC2ekBiD0g,9177
219
219
  ccxt/async_support/binanceusdm.py,sha256=-1r4A4tmV2pCiLGO80hzq7MIIj4MTzOD7buZGv6JauA,2518
@@ -246,7 +246,7 @@ ccxt/async_support/btcmarkets.py,sha256=b6izd3cD8P3swetbESyX1N0qD3K0sZI7PX4qMjWm
246
246
  ccxt/async_support/btcturk.py,sha256=nz0nAY_whtiOupBWqdKjrYvpe6Ynu82b_SsB8kd5DC0,36724
247
247
  ccxt/async_support/bybit.py,sha256=DMTulzeqpQj-jFsY7qH2dyQbnvoXKa41awkEqWhdAFs,403379
248
248
  ccxt/async_support/cex.py,sha256=_zLkiZaE0dT7yTuJtgkFQlmuzj6M5dQQvI_VXkKsBCc,70003
249
- ccxt/async_support/coinbase.py,sha256=NWq5AqztGfaKJQuYDhIkGtmBoyKAhSTzBnPnDkbccv4,202488
249
+ ccxt/async_support/coinbase.py,sha256=VEGeIYJEiZ0JvAl7cUd_bPMrm-ddXbGO-dJednAFRDc,202728
250
250
  ccxt/async_support/coinbaseinternational.py,sha256=d_6C7iQFn1giEh1Sr7Wm2fhG9QtGYx1pMkeJXpwjZvM,87677
251
251
  ccxt/async_support/coinbasepro.py,sha256=H32l_mejuo2ATe4_Hac3vFgRTIxSPuDDFHz2pdQOLnw,78883
252
252
  ccxt/async_support/coincheck.py,sha256=LbgeqG4WkPMXZid_LZstU6Vzv6C4-xRkt_mLb4wudGc,35719
@@ -260,7 +260,7 @@ ccxt/async_support/coinspot.py,sha256=DqWK2WouFRRfchKlNFOAIhDcVK3pFfI-kHyg1BgH8P
260
260
  ccxt/async_support/cryptocom.py,sha256=FKgdtYv8afwM9TE0utX6SQYlWCRF3KTSE_MYY7IDzw4,128712
261
261
  ccxt/async_support/currencycom.py,sha256=6mRnCI8zMKEUqiB-eyKE7i1fRsxPKIvxWRF6xMbMTf0,87181
262
262
  ccxt/async_support/delta.py,sha256=YGWYhjcWIhcynx54aveJVUeoHhsSOrSa71sqhWmOUKA,151045
263
- ccxt/async_support/deribit.py,sha256=C8ueXWQkSmVQJcsLzC0ABjWas4PfGM-vkrp42I0NSII,160915
263
+ ccxt/async_support/deribit.py,sha256=svkhUyDROv1LoeK6KPU3UajeYAoBBlwr4yTAFqadgII,161224
264
264
  ccxt/async_support/digifinex.py,sha256=dAaeJtZfUkjQRrL2XDqMqZPBocl7DcHkJEJcZq6shDc,168841
265
265
  ccxt/async_support/exmo.py,sha256=itC3KzmIz0g8gAWktPyYFeFo2n4pLuRpGpUi9sH2eY8,114835
266
266
  ccxt/async_support/flowbtc.py,sha256=bCnvtcNnPxxaxqVjI1GGXKhIpz_1r4GIFWqqPokvCR0,1183
@@ -293,13 +293,13 @@ ccxt/async_support/ndax.py,sha256=lqc75WD0M9_N8wFJnQNcrP4kB4BdBZoqL2l2xfQH0Kc,10
293
293
  ccxt/async_support/novadax.py,sha256=DqIJouf8L_fhyPVH0b4xIrWgC0R3tWjbWHutQkMOZKo,64473
294
294
  ccxt/async_support/oceanex.py,sha256=aYdYRl42FDFpaPaoLaiGYxvDM_7aq0dEjAhUa0NsJQQ,38180
295
295
  ccxt/async_support/okcoin.py,sha256=EywGLmOM6VkZ_hsqMfpdcWHJxyEL-HilinJH36TAW1E,151629
296
- ccxt/async_support/okx.py,sha256=PCSGzeQWMzNmoN6QyUBWOlbwFsNpiEej9t2ntxE8KN4,356098
296
+ ccxt/async_support/okx.py,sha256=gTvw2byqPmBkSwOgolgfEakTDVppX81gAgQTBPVpLqk,356176
297
297
  ccxt/async_support/onetrading.py,sha256=i-h-aTHva9IWTOIA1Sryg-21H0FXrHJKqe51vPuYoVk,88409
298
298
  ccxt/async_support/p2b.py,sha256=Y3mBeLU4XdmQfeeh-QVsZ4NcdYSI4xEMBRBs8S2RiZU,54316
299
299
  ccxt/async_support/paymium.py,sha256=3P1J9OcDOqQKG5fUs6Xte9Xu8NB5lWu-OD-AHHGZbkM,24391
300
300
  ccxt/async_support/phemex.py,sha256=Sy8EDSFulp0s8CLYF6OQfAQqY7oUz4-aRW1JI3hLaSc,219437
301
301
  ccxt/async_support/poloniex.py,sha256=2w6mGXvypjJeM_Tpwg3nKdkPEdW4-ANvhUXM1-Gdf9U,102496
302
- ccxt/async_support/poloniexfutures.py,sha256=gJjkpIOFaFXmGdSGak8ASJ1sZCoWsLQdTP3O7ko5Vno,77756
302
+ ccxt/async_support/poloniexfutures.py,sha256=owKl-FpawlL9d246wIjzgrc24h-3-t7Sae6RBUOBEa0,77991
303
303
  ccxt/async_support/probit.py,sha256=WPa-iBe9AHFAqURTZrooIVeeKfYWqBde9ouJxMrOoAk,76600
304
304
  ccxt/async_support/timex.py,sha256=1-mmOLWujFwMn9peJYGZzLraq-JxwXwSmS4uyfMOK6E,71498
305
305
  ccxt/async_support/tokocrypto.py,sha256=dHcnzGmwK9Nh7Dtu8e3p0_VLjId_iCNYsOyBxZ8UaD4,123364
@@ -313,7 +313,7 @@ ccxt/async_support/yobit.py,sha256=EgBPquMnD4GU32jnWp1FXUxlMyC1nYPtRzJCZUG_HMY,5
313
313
  ccxt/async_support/zaif.py,sha256=PaHcaNijKkhocrw6DZoSBNUjBOLNlkUYtsJvPAqkx68,28134
314
314
  ccxt/async_support/zonda.py,sha256=89EXub_DW_p4Rpza9iiW-hAaj3ucKbNdZyV2ETQ3ESY,80866
315
315
  ccxt/async_support/base/__init__.py,sha256=aVYSsFi--b4InRs9zDN_wtCpj8odosAB726JdUHavrk,67
316
- ccxt/async_support/base/exchange.py,sha256=GxzE-RR0i3IciUMk4R_wDp6zcURMwuc4SB_TqkdMnKs,91521
316
+ ccxt/async_support/base/exchange.py,sha256=daITri9ZoszB5Hb2ThUQflE4LellhrjrBR-IEHnh3DY,91521
317
317
  ccxt/async_support/base/throttler.py,sha256=tvDVcdRUVYi8fZRlEcnqtgzcgB_KMUMRs5Pu8tuU-tU,1847
318
318
  ccxt/async_support/base/ws/__init__.py,sha256=uockzpLuwntKGZbs5EOWFe-Zg-k6Cj7GhNJLc_RX0so,1791
319
319
  ccxt/async_support/base/ws/aiohttp_client.py,sha256=Ed1765emEde2Hj8Ys6f5EjS54ZI1wQ0qIhd04eB7yhU,5751
@@ -327,14 +327,14 @@ ccxt/async_support/base/ws/order_book_side.py,sha256=Pxrq22nCODckJ6G1OXkYEmUunIu
327
327
  ccxt/base/__init__.py,sha256=eTx1OE3HJjspFUQjGm6LBhaQiMKJnXjkdP-JUXknyQ0,1320
328
328
  ccxt/base/decimal_to_precision.py,sha256=fgWRBzRTtsf3r2INyS4f7WHlzgjB5YM1ekiwqD21aac,6634
329
329
  ccxt/base/errors.py,sha256=u_zxABGVPU_K5oLEEZQWOI0_F5Q-SAUq1g1q6AFh7IM,4107
330
- ccxt/base/exchange.py,sha256=ivqA8JO-K-YTPMPlosGtvDjCUrKaFkpwXW4__F4wL9w,255306
330
+ ccxt/base/exchange.py,sha256=IPI7A-fnmEAlKzzcWMVoXC0B-PHVdbxi2lwSXhCB8A0,256006
331
331
  ccxt/base/precise.py,sha256=_xfu54sV0vWNnOfGTKRFykeuWP8mn4K1m9lk1tcllX4,8565
332
332
  ccxt/base/types.py,sha256=x9KoAaFdEPJD2l8ottMk4xKr-tEdby77jKaAK8XcIgo,7903
333
- ccxt/pro/__init__.py,sha256=KFxYWtyqUKEScFlDqv_cB5o4UlzC3HHyFMdRSAeWRkw,6999
333
+ ccxt/pro/__init__.py,sha256=xbCziscNlw7IQbrr5tOFNnV2xZ4G1YxAaaasOdr7aVI,6999
334
334
  ccxt/pro/alpaca.py,sha256=7ePyWli0949ti5UheIn553xmnFpedrNc2W5CKauSZio,27167
335
335
  ccxt/pro/ascendex.py,sha256=fCM3EujSfJvtvffqI56UAstTtwjXFIocwukm15cF8rE,35432
336
336
  ccxt/pro/bequant.py,sha256=5zbsP8BHQTUZ8ZNL6uaACxDbUClgkOV4SYfXT_LfQVg,1351
337
- ccxt/pro/binance.py,sha256=njEW27VdaClaBwWv6pQXcHvB3NeJZFtJDMLNooSTShs,136416
337
+ ccxt/pro/binance.py,sha256=tw7tPX290U2L_mpzlTtjCzoFXJn47glbns5JCzgG0JM,136683
338
338
  ccxt/pro/binancecoinm.py,sha256=s_evAyeT23VqscMRuSjrCK2CSaNsP-oc8A8noSuaLwQ,976
339
339
  ccxt/pro/binanceus.py,sha256=mpvmzc7kK3cGShM5EOvadOvwlj1xWsWzX9fIapuq2eQ,2321
340
340
  ccxt/pro/binanceusdm.py,sha256=S0eT662O2ReplsihWk42nhJWqw1XsODpeDQa9eFVVt8,1357
@@ -389,7 +389,7 @@ ccxt/pro/onetrading.py,sha256=9-WTi6ZNjsG7TJ6CA6pGpnm_6Jg2gg21ny4GZypjr6s,54634
389
389
  ccxt/pro/p2b.py,sha256=lO8mTtBCOU1yHQnmOQAI3USn67tsZd4nTGHDqFd4qEE,17877
390
390
  ccxt/pro/phemex.py,sha256=lD4r2KQdpkgeXGors3jtEMxoaxpEF0tl6MYXZ99GSYg,61032
391
391
  ccxt/pro/poloniex.py,sha256=rfZq2B_hXdc3JFJ4NhXV2KxV0flNV82nzKBbv39S1Hc,51236
392
- ccxt/pro/poloniexfutures.py,sha256=T7dH-SVEaxWqf_NeDkJOpt3IaGz_iouj4-WRikDPRqU,41480
392
+ ccxt/pro/poloniexfutures.py,sha256=8qEEqKc7_zMgv-iz0KffE8RnYBqmiyNCiDcmuyqM0Xs,41652
393
393
  ccxt/pro/probit.py,sha256=RLTnROQUmX31XQ3ymIZkiDkop3eiSVK70Yw81yDcde4,22822
394
394
  ccxt/pro/upbit.py,sha256=CSqwaNCxECo9FI7aq_7ege0c8IjWEmsoPZL06Kw9KDo,9654
395
395
  ccxt/pro/wazirx.py,sha256=UVZa0W3hMBwRAaDw5zboSa0wGzp-jS66xIp9fhmIYk4,30004
@@ -493,8 +493,8 @@ ccxt/static_dependencies/toolz/curried/__init__.py,sha256=iOuFY4c1kixe_h8lxuWIW5
493
493
  ccxt/static_dependencies/toolz/curried/exceptions.py,sha256=gKFOHDIayAWnX2uC8Z2KrUwpP-UpoqI5Tx1a859QdVY,344
494
494
  ccxt/static_dependencies/toolz/curried/operator.py,sha256=ML92mknkAwzBl2NCm-4werSUmJEtSHNY9NSzhseNM9s,525
495
495
  ccxt/test/__init__.py,sha256=GKPbEcj0Rrz5HG-GUm-iY1IHhDYmlvcBXZAGk6-m2CI,141
496
- ccxt/test/test_async.py,sha256=QM2fYOc923oQ-GqhjoDDSwKWO2wDnIIe475lsZChC8U,77013
497
- ccxt/test/test_sync.py,sha256=zHaiAXSP6EPiUq0aoGEwwQ58SlsX1QxTOJl0d8sJ4xc,75994
496
+ ccxt/test/test_async.py,sha256=OQ8PUmnIoizgCnq2qRitcM7HmWQRd3YzDfuwL2RHhIA,78570
497
+ ccxt/test/test_sync.py,sha256=oFegh-RygJtlJRQ5GL0mA6t297hBY22qfJi7l3vRYTg,77551
498
498
  ccxt/test/base/__init__.py,sha256=LvE9DEw5mNiyFrE-XnfzFFuSOvZOyi7ec__PF7lpnYs,1889
499
499
  ccxt/test/base/test_account.py,sha256=lxwZXsY8qZgomBoEiomUmWcseSp--orJx-xmm3E1vYs,978
500
500
  ccxt/test/base/test_balance.py,sha256=W-IcVRiJNLtdKEWEEhmhWjtFRuHFtoywNiGQNtYSuc0,2931
@@ -520,7 +520,7 @@ ccxt/test/base/test_number.py,sha256=vBis6fh9mJ5KnzGsUkcoh_cJxU1LR0x7CG0NMp6SejY
520
520
  ccxt/test/base/test_ohlcv.py,sha256=4LbTPW6sPP_p2d9cdvS-swHNaNVr6CYdNnyjwKqgnLI,2036
521
521
  ccxt/test/base/test_open_interest.py,sha256=u689028CAIbR-MmgN8SfGShHmculqWgDouI4qsB-waQ,1547
522
522
  ccxt/test/base/test_order.py,sha256=WvW1DtUvdX7Msv7tjdLlpVt2KoqoMDJXtpY2JnHEzy8,3964
523
- ccxt/test/base/test_order_book.py,sha256=hwJKB8yFHndY2HcQWm3BdGH3qmX7mUc0fiISSwSKC6U,3586
523
+ ccxt/test/base/test_order_book.py,sha256=-Hf1UZ7ELyg4UZacyal49FkwN-0DnKcHA-lk6HXv1HU,3949
524
524
  ccxt/test/base/test_position.py,sha256=MUH0Pr_-uCE5JFQTZYqdSXJe-tKd1sbkK312MON7g-A,3884
525
525
  ccxt/test/base/test_shared_methods.py,sha256=99FfxMPEcdhbkJeOclHs9et7p49rgF1AVrMXjwRzTKc,19998
526
526
  ccxt/test/base/test_status.py,sha256=ueP98IjPN7-PIEnWbPCUB3ObqgSgjRwfCoyNeAtK1_w,722
@@ -529,7 +529,7 @@ ccxt/test/base/test_ticker.py,sha256=cMTIMb1oySNORUCmqI5ZzMswlEyCF6gJMah3vfvo8wQ
529
529
  ccxt/test/base/test_trade.py,sha256=PMtmB8V38dpaP-eb8h488xYMlR6D69yCOhsA1RuWrUA,2336
530
530
  ccxt/test/base/test_trading_fee.py,sha256=2aDCNJtqBkTC_AieO0l1HYGq5hz5qkWlkWb9Nv_fcwk,1066
531
531
  ccxt/test/base/test_transaction.py,sha256=BTbB4UHHXkrvYgwbrhh867nVRlevmIkIrz1W_odlQJI,1434
532
- ccxt-4.2.96.dist-info/METADATA,sha256=SQvd_Z6iYzEHpAQUY2GSg7xBCwCveo7h3WFHZP4_5jQ,110281
533
- ccxt-4.2.96.dist-info/WHEEL,sha256=P2T-6epvtXQ2cBOE_U1K4_noqlJFN3tj15djMgEu4NM,110
534
- ccxt-4.2.96.dist-info/top_level.txt,sha256=CkQDuCTDKNcImPV60t36G6MdYfxsAPNiSaEwifVoVMo,5
535
- ccxt-4.2.96.dist-info/RECORD,,
532
+ ccxt-4.2.98.dist-info/METADATA,sha256=XxLB4oeG5H2pvjdi9tW9RsJf1mXgHBPF2lmBFhmoMno,110281
533
+ ccxt-4.2.98.dist-info/WHEEL,sha256=P2T-6epvtXQ2cBOE_U1K4_noqlJFN3tj15djMgEu4NM,110
534
+ ccxt-4.2.98.dist-info/top_level.txt,sha256=CkQDuCTDKNcImPV60t36G6MdYfxsAPNiSaEwifVoVMo,5
535
+ ccxt-4.2.98.dist-info/RECORD,,
File without changes