ccxt 4.3.15__py2.py3-none-any.whl → 4.3.17__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.

Potentially problematic release.


This version of ccxt might be problematic. Click here for more details.

Files changed (68) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/alpaca.py +1 -0
  3. ccxt/ascendex.py +1 -0
  4. ccxt/async_support/__init__.py +1 -1
  5. ccxt/async_support/alpaca.py +1 -0
  6. ccxt/async_support/ascendex.py +1 -0
  7. ccxt/async_support/base/exchange.py +18 -13
  8. ccxt/async_support/binance.py +10 -9
  9. ccxt/async_support/bingx.py +1 -0
  10. ccxt/async_support/bitmex.py +1 -0
  11. ccxt/async_support/bybit.py +11 -7
  12. ccxt/async_support/coinbaseinternational.py +1 -0
  13. ccxt/async_support/coinmetro.py +1 -0
  14. ccxt/async_support/cryptocom.py +1 -0
  15. ccxt/async_support/currencycom.py +1 -0
  16. ccxt/async_support/deribit.py +1 -0
  17. ccxt/async_support/gate.py +1 -0
  18. ccxt/async_support/gemini.py +1 -0
  19. ccxt/async_support/hitbtc.py +1 -0
  20. ccxt/async_support/hollaex.py +1 -0
  21. ccxt/async_support/hyperliquid.py +4 -0
  22. ccxt/async_support/idex.py +1 -0
  23. ccxt/async_support/krakenfutures.py +1 -0
  24. ccxt/async_support/ndax.py +1 -0
  25. ccxt/async_support/okx.py +19 -0
  26. ccxt/async_support/phemex.py +1 -0
  27. ccxt/async_support/poloniex.py +1 -0
  28. ccxt/async_support/probit.py +1 -0
  29. ccxt/async_support/wavesexchange.py +1 -0
  30. ccxt/async_support/woo.py +1 -0
  31. ccxt/async_support/zaif.py +1 -1
  32. ccxt/base/exchange.py +18 -13
  33. ccxt/binance.py +10 -9
  34. ccxt/bingx.py +1 -0
  35. ccxt/bitmex.py +1 -0
  36. ccxt/bybit.py +11 -7
  37. ccxt/coinbaseinternational.py +1 -0
  38. ccxt/coinmetro.py +1 -0
  39. ccxt/cryptocom.py +1 -0
  40. ccxt/currencycom.py +1 -0
  41. ccxt/deribit.py +1 -0
  42. ccxt/gate.py +1 -0
  43. ccxt/gemini.py +1 -0
  44. ccxt/hitbtc.py +1 -0
  45. ccxt/hollaex.py +1 -0
  46. ccxt/hyperliquid.py +4 -0
  47. ccxt/idex.py +1 -0
  48. ccxt/krakenfutures.py +1 -0
  49. ccxt/ndax.py +1 -0
  50. ccxt/okx.py +19 -0
  51. ccxt/phemex.py +1 -0
  52. ccxt/poloniex.py +1 -0
  53. ccxt/pro/__init__.py +1 -1
  54. ccxt/pro/bitfinex2.py +2 -0
  55. ccxt/pro/bitget.py +3 -0
  56. ccxt/pro/bybit.py +3 -3
  57. ccxt/pro/htx.py +2 -0
  58. ccxt/pro/independentreserve.py +2 -0
  59. ccxt/pro/kraken.py +2 -0
  60. ccxt/pro/okx.py +22 -18
  61. ccxt/probit.py +1 -0
  62. ccxt/wavesexchange.py +1 -0
  63. ccxt/woo.py +1 -0
  64. ccxt/zaif.py +1 -1
  65. {ccxt-4.3.15.dist-info → ccxt-4.3.17.dist-info}/METADATA +4 -4
  66. {ccxt-4.3.15.dist-info → ccxt-4.3.17.dist-info}/RECORD +68 -68
  67. {ccxt-4.3.15.dist-info → ccxt-4.3.17.dist-info}/WHEEL +0 -0
  68. {ccxt-4.3.15.dist-info → ccxt-4.3.17.dist-info}/top_level.txt +0 -0
ccxt/__init__.py CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.3.15'
25
+ __version__ = '4.3.17'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
ccxt/alpaca.py CHANGED
@@ -98,6 +98,7 @@ class alpaca(Exchange, ImplicitAPI):
98
98
  'fetchTransactions': False,
99
99
  'fetchTransfers': False,
100
100
  'fetchWithdrawals': False,
101
+ 'sandbox': True,
101
102
  'setLeverage': False,
102
103
  'setMarginMode': False,
103
104
  'transfer': False,
ccxt/ascendex.py CHANGED
@@ -102,6 +102,7 @@ class ascendex(Exchange, ImplicitAPI):
102
102
  'fetchWithdrawal': False,
103
103
  'fetchWithdrawals': True,
104
104
  'reduceMargin': True,
105
+ 'sandbox': True,
105
106
  'setLeverage': True,
106
107
  'setMarginMode': True,
107
108
  'setPositionMode': False,
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.15'
7
+ __version__ = '4.3.17'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -98,6 +98,7 @@ class alpaca(Exchange, ImplicitAPI):
98
98
  'fetchTransactions': False,
99
99
  'fetchTransfers': False,
100
100
  'fetchWithdrawals': False,
101
+ 'sandbox': True,
101
102
  'setLeverage': False,
102
103
  'setMarginMode': False,
103
104
  'transfer': False,
@@ -102,6 +102,7 @@ class ascendex(Exchange, ImplicitAPI):
102
102
  'fetchWithdrawal': False,
103
103
  'fetchWithdrawals': True,
104
104
  'reduceMargin': True,
105
+ 'sandbox': True,
105
106
  'setLeverage': True,
106
107
  'setMarginMode': True,
107
108
  'setPositionMode': False,
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.3.15'
5
+ __version__ = '4.3.17'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -1775,18 +1775,19 @@ class Exchange(BaseExchange):
1775
1775
  maxRetries = None
1776
1776
  maxRetries, params = self.handle_option_and_params(params, method, 'maxRetries', 3)
1777
1777
  errors = 0
1778
- try:
1779
- if timeframe and method != 'fetchFundingRateHistory':
1780
- return await getattr(self, method)(symbol, timeframe, since, limit, params)
1781
- else:
1782
- return await getattr(self, method)(symbol, since, limit, params)
1783
- except Exception as e:
1784
- if isinstance(e, RateLimitExceeded):
1785
- raise e # if we are rate limited, we should not retry and fail fast
1786
- errors += 1
1787
- if errors > maxRetries:
1788
- raise e
1789
- return None
1778
+ while(errors <= maxRetries):
1779
+ try:
1780
+ if timeframe and method != 'fetchFundingRateHistory':
1781
+ return await getattr(self, method)(symbol, timeframe, since, limit, params)
1782
+ else:
1783
+ return await getattr(self, method)(symbol, since, limit, params)
1784
+ except Exception as e:
1785
+ if isinstance(e, RateLimitExceeded):
1786
+ raise e # if we are rate limited, we should not retry and fail fast
1787
+ errors += 1
1788
+ if errors > maxRetries:
1789
+ raise e
1790
+ return []
1790
1791
 
1791
1792
  async def fetch_paginated_call_deterministic(self, method: str, symbol: Str = None, since: Int = None, limit: Int = None, timeframe: Str = None, params={}, maxEntriesPerRequest=None):
1792
1793
  maxCalls = None
@@ -1799,6 +1800,8 @@ class Exchange(BaseExchange):
1799
1800
  currentSince = current - (maxCalls * step) - 1
1800
1801
  if since is not None:
1801
1802
  currentSince = max(currentSince, since)
1803
+ else:
1804
+ currentSince = max(currentSince, 1241440531000) # avoid timestamps older than 2009
1802
1805
  until = self.safe_integer_2(params, 'until', 'till') # do not omit it here
1803
1806
  if until is not None:
1804
1807
  requiredCalls = int(math.ceil((until - since)) / step)
@@ -1807,6 +1810,8 @@ class Exchange(BaseExchange):
1807
1810
  for i in range(0, maxCalls):
1808
1811
  if (until is not None) and (currentSince >= until):
1809
1812
  break
1813
+ if currentSince >= current:
1814
+ break
1810
1815
  tasks.append(self.safe_deterministic_call(method, symbol, currentSince, maxEntriesPerRequest, timeframe, params))
1811
1816
  currentSince = self.sum(currentSince, step) - 1
1812
1817
  results = await asyncio.gather(*tasks)
@@ -178,6 +178,7 @@ class binance(Exchange, ImplicitAPI):
178
178
  'reduceMargin': True,
179
179
  'repayCrossMargin': True,
180
180
  'repayIsolatedMargin': True,
181
+ 'sandbox': True,
181
182
  'setLeverage': True,
182
183
  'setMargin': False,
183
184
  'setMarginMode': True,
@@ -2611,7 +2612,7 @@ class binance(Exchange, ImplicitAPI):
2611
2612
  :param dict [params]: extra parameters specific to the exchange API endpoint
2612
2613
  :returns dict: an associative dictionary of currencies
2613
2614
  """
2614
- fetchCurrenciesEnabled = self.safe_value(self.options, 'fetchCurrencies')
2615
+ fetchCurrenciesEnabled = self.safe_bool(self.options, 'fetchCurrencies')
2615
2616
  if not fetchCurrenciesEnabled:
2616
2617
  return None
2617
2618
  # self endpoint requires authentication
@@ -4398,7 +4399,7 @@ class binance(Exchange, ImplicitAPI):
4398
4399
  market = self.safe_market(marketId, market, None, marketType)
4399
4400
  symbol = market['symbol']
4400
4401
  side = None
4401
- buyerMaker = self.safe_value_2(trade, 'm', 'isBuyerMaker')
4402
+ buyerMaker = self.safe_bool_2(trade, 'm', 'isBuyerMaker')
4402
4403
  takerOrMaker = None
4403
4404
  if buyerMaker is not None:
4404
4405
  side = 'sell' if buyerMaker else 'buy' # self is reversed intentionally
@@ -4674,14 +4675,14 @@ class binance(Exchange, ImplicitAPI):
4674
4675
  uppercaseType = 'STOP_LOSS'
4675
4676
  elif uppercaseType == 'LIMIT':
4676
4677
  uppercaseType = 'STOP_LOSS_LIMIT'
4677
- validOrderTypes = self.safe_value(market['info'], 'orderTypes')
4678
+ validOrderTypes = self.safe_list(market['info'], 'orderTypes')
4678
4679
  if not self.in_array(uppercaseType, validOrderTypes):
4679
4680
  if initialUppercaseType != uppercaseType:
4680
4681
  raise InvalidOrder(self.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders')
4681
4682
  else:
4682
4683
  raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market')
4683
4684
  if clientOrderId is None:
4684
- broker = self.safe_value(self.options, 'broker')
4685
+ broker = self.safe_dict(self.options, 'broker')
4685
4686
  if broker is not None:
4686
4687
  brokerId = self.safe_string(broker, 'spot')
4687
4688
  if brokerId is not None:
@@ -7149,7 +7150,7 @@ class binance(Exchange, ImplicitAPI):
7149
7150
  if until is not None:
7150
7151
  request['endTime'] = until
7151
7152
  raw = await self.sapiGetFiatOrders(self.extend(request, params))
7152
- response = self.safe_value(raw, 'data')
7153
+ response = self.safe_list(raw, 'data', [])
7153
7154
  # {
7154
7155
  # "code": "000000",
7155
7156
  # "message": "success",
@@ -7251,7 +7252,7 @@ class binance(Exchange, ImplicitAPI):
7251
7252
  if since is not None:
7252
7253
  request['beginTime'] = since
7253
7254
  raw = await self.sapiGetFiatOrders(self.extend(request, params))
7254
- response = self.safe_value(raw, 'data')
7255
+ response = self.safe_list(raw, 'data', [])
7255
7256
  # {
7256
7257
  # "code": "000000",
7257
7258
  # "message": "success",
@@ -7458,7 +7459,7 @@ class binance(Exchange, ImplicitAPI):
7458
7459
  txType = self.safe_string(transaction, 'transactionType')
7459
7460
  if txType is not None:
7460
7461
  type = 'deposit' if (txType == '0') else 'withdrawal'
7461
- legalMoneyCurrenciesById = self.safe_value(self.options, 'legalMoneyCurrenciesById')
7462
+ legalMoneyCurrenciesById = self.safe_dict(self.options, 'legalMoneyCurrenciesById')
7462
7463
  code = self.safe_string(legalMoneyCurrenciesById, code, code)
7463
7464
  status = self.parse_transaction_status_by_type(self.safe_string(transaction, 'status'), type)
7464
7465
  amount = self.safe_number(transaction, 'amount')
@@ -7772,7 +7773,7 @@ class binance(Exchange, ImplicitAPI):
7772
7773
  if subLevel is not None:
7773
7774
  topLevel = topLevel + '/' + subLevel
7774
7775
  impliedNetwork = self.safe_string(reverseNetworks, topLevel)
7775
- impliedNetworks = self.safe_value(self.options, 'impliedNetworks', {
7776
+ impliedNetworks = self.safe_dict(self.options, 'impliedNetworks', {
7776
7777
  'ETH': {'ERC20': 'ETH'},
7777
7778
  'TRX': {'TRC20': 'TRX'},
7778
7779
  })
@@ -8980,7 +8981,7 @@ class binance(Exchange, ImplicitAPI):
8980
8981
  await self.load_markets()
8981
8982
  # by default cache the leverage bracket
8982
8983
  # it contains useful stuff like the maintenance margin and initial margin for positions
8983
- leverageBrackets = self.safe_value(self.options, 'leverageBrackets')
8984
+ leverageBrackets = self.safe_dict(self.options, 'leverageBrackets', {})
8984
8985
  if (leverageBrackets is None) or (reload):
8985
8986
  defaultType = self.safe_string(self.options, 'defaultType', 'future')
8986
8987
  type = self.safe_string(params, 'type', defaultType)
@@ -98,6 +98,7 @@ class bingx(Exchange, ImplicitAPI):
98
98
  'fetchTransfers': True,
99
99
  'fetchWithdrawals': True,
100
100
  'reduceMargin': True,
101
+ 'sandbox': True,
101
102
  'setLeverage': True,
102
103
  'setMargin': True,
103
104
  'setMarginMode': True,
@@ -100,6 +100,7 @@ class bitmex(Exchange, ImplicitAPI):
100
100
  'fetchTransfer': False,
101
101
  'fetchTransfers': False,
102
102
  'reduceMargin': None,
103
+ 'sandbox': True,
103
104
  'setLeverage': True,
104
105
  'setMargin': None,
105
106
  'setMarginMode': True,
@@ -134,6 +134,7 @@ class bybit(Exchange, ImplicitAPI):
134
134
  'fetchVolatilityHistory': True,
135
135
  'fetchWithdrawals': True,
136
136
  'repayCrossMargin': True,
137
+ 'sandbox': True,
137
138
  'setLeverage': True,
138
139
  'setMarginMode': True,
139
140
  'setPositionMode': True,
@@ -1469,6 +1470,7 @@ class bybit(Exchange, ImplicitAPI):
1469
1470
  # "quoteCoin": "USDT",
1470
1471
  # "innovation": "0",
1471
1472
  # "status": "Trading",
1473
+ # "marginTrading": "both",
1472
1474
  # "lotSizeFilter": {
1473
1475
  # "basePrecision": "0.000001",
1474
1476
  # "quotePrecision": "0.00000001",
@@ -1505,7 +1507,9 @@ class bybit(Exchange, ImplicitAPI):
1505
1507
  lotSizeFilter = self.safe_dict(market, 'lotSizeFilter')
1506
1508
  priceFilter = self.safe_dict(market, 'priceFilter')
1507
1509
  quotePrecision = self.safe_number(lotSizeFilter, 'quotePrecision')
1508
- result.append({
1510
+ marginTrading = self.safe_string(market, 'marginTrading', 'none')
1511
+ allowsMargin = marginTrading != 'none'
1512
+ result.append(self.safe_market_structure({
1509
1513
  'id': id,
1510
1514
  'symbol': symbol,
1511
1515
  'base': base,
@@ -1516,7 +1520,7 @@ class bybit(Exchange, ImplicitAPI):
1516
1520
  'settleId': None,
1517
1521
  'type': 'spot',
1518
1522
  'spot': True,
1519
- 'margin': None,
1523
+ 'margin': allowsMargin,
1520
1524
  'swap': False,
1521
1525
  'future': False,
1522
1526
  'option': False,
@@ -1555,7 +1559,7 @@ class bybit(Exchange, ImplicitAPI):
1555
1559
  },
1556
1560
  'created': None,
1557
1561
  'info': market,
1558
- })
1562
+ }))
1559
1563
  return result
1560
1564
 
1561
1565
  async def fetch_future_markets(self, params):
@@ -1668,7 +1672,7 @@ class bybit(Exchange, ImplicitAPI):
1668
1672
  if expiry is not None:
1669
1673
  symbol = symbol + '-' + self.yymmdd(expiry)
1670
1674
  contractSize = self.safe_number_2(lotSizeFilter, 'minTradingQty', 'minOrderQty') if inverse else self.parse_number('1')
1671
- result.append({
1675
+ result.append(self.safe_market_structure({
1672
1676
  'id': id,
1673
1677
  'symbol': symbol,
1674
1678
  'base': base,
@@ -1718,7 +1722,7 @@ class bybit(Exchange, ImplicitAPI):
1718
1722
  },
1719
1723
  'created': self.safe_integer(market, 'launchTime'),
1720
1724
  'info': market,
1721
- })
1725
+ }))
1722
1726
  return result
1723
1727
 
1724
1728
  async def fetch_option_markets(self, params):
@@ -1796,7 +1800,7 @@ class bybit(Exchange, ImplicitAPI):
1796
1800
  optionLetter = self.safe_string(splitId, 3)
1797
1801
  isActive = (status == 'Trading')
1798
1802
  if isActive or (self.options['loadAllOptions']) or (self.options['loadExpiredOptions']):
1799
- result.append({
1803
+ result.append(self.safe_market_structure({
1800
1804
  'id': id,
1801
1805
  'symbol': base + '/' + quote + ':' + settle + '-' + self.yymmdd(expiry) + '-' + strike + '-' + optionLetter,
1802
1806
  'base': base,
@@ -1846,7 +1850,7 @@ class bybit(Exchange, ImplicitAPI):
1846
1850
  },
1847
1851
  'created': self.safe_integer(market, 'launchTime'),
1848
1852
  'info': market,
1849
- })
1853
+ }))
1850
1854
  return result
1851
1855
 
1852
1856
  def parse_ticker(self, ticker, market: Market = None) -> Ticker:
@@ -113,6 +113,7 @@ class coinbaseinternational(Exchange, ImplicitAPI):
113
113
  'fetchTradingFees': False,
114
114
  'fetchWithdrawals': True,
115
115
  'reduceMargin': False,
116
+ 'sandbox': True,
116
117
  'setLeverage': False,
117
118
  'setMargin': True,
118
119
  'setMarginMode': False,
@@ -122,6 +122,7 @@ class coinmetro(Exchange, ImplicitAPI):
122
122
  'reduceMargin': False,
123
123
  'repayCrossMargin': False,
124
124
  'repayIsolatedMargin': False,
125
+ 'sandbox': True,
125
126
  'setLeverage': False,
126
127
  'setMargin': False,
127
128
  'setMarginMode': False,
@@ -117,6 +117,7 @@ class cryptocom(Exchange, ImplicitAPI):
117
117
  'reduceMargin': False,
118
118
  'repayCrossMargin': False,
119
119
  'repayIsolatedMargin': False,
120
+ 'sandbox': True,
120
121
  'setLeverage': False,
121
122
  'setMarginMode': False,
122
123
  'setPositionMode': False,
@@ -114,6 +114,7 @@ class currencycom(Exchange, ImplicitAPI):
114
114
  'fetchWithdrawal': None,
115
115
  'fetchWithdrawals': True,
116
116
  'reduceMargin': None,
117
+ 'sandbox': True,
117
118
  'setLeverage': None,
118
119
  'setMarginMode': None,
119
120
  'setPositionMode': None,
@@ -107,6 +107,7 @@ class deribit(Exchange, ImplicitAPI):
107
107
  'fetchVolatilityHistory': True,
108
108
  'fetchWithdrawal': False,
109
109
  'fetchWithdrawals': True,
110
+ 'sandbox': True,
110
111
  'transfer': True,
111
112
  'withdraw': True,
112
113
  },
@@ -176,6 +176,7 @@ class gate(Exchange, ImplicitAPI):
176
176
  'reduceMargin': True,
177
177
  'repayCrossMargin': True,
178
178
  'repayIsolatedMargin': True,
179
+ 'sandbox': True,
179
180
  'setLeverage': True,
180
181
  'setMarginMode': False,
181
182
  'setPositionMode': True,
@@ -96,6 +96,7 @@ class gemini(Exchange, ImplicitAPI):
96
96
  'fetchTransactions': 'emulated',
97
97
  'postOnly': True,
98
98
  'reduceMargin': False,
99
+ 'sandbox': True,
99
100
  'setLeverage': False,
100
101
  'setMarginMode': False,
101
102
  'setPositionMode': False,
@@ -108,6 +108,7 @@ class hitbtc(Exchange, ImplicitAPI):
108
108
  'fetchTransactions': 'emulated',
109
109
  'fetchWithdrawals': True,
110
110
  'reduceMargin': True,
111
+ 'sandbox': True,
111
112
  'setLeverage': True,
112
113
  'setMargin': False,
113
114
  'setMarginMode': False,
@@ -96,6 +96,7 @@ class hollaex(Exchange, ImplicitAPI):
96
96
  'fetchWithdrawal': True,
97
97
  'fetchWithdrawals': True,
98
98
  'reduceMargin': False,
99
+ 'sandbox': True,
99
100
  'setLeverage': False,
100
101
  'setMarginMode': False,
101
102
  'setPositionMode': False,
@@ -114,6 +114,7 @@ class hyperliquid(Exchange, ImplicitAPI):
114
114
  'reduceMargin': True,
115
115
  'repayCrossMargin': False,
116
116
  'repayIsolatedMargin': False,
117
+ 'sandbox': True,
117
118
  'setLeverage': True,
118
119
  'setMarginMode': True,
119
120
  'setPositionMode': False,
@@ -443,6 +444,9 @@ class hyperliquid(Exchange, ImplicitAPI):
443
444
  for i in range(0, len(meta)):
444
445
  market = self.safe_dict(meta, i, {})
445
446
  marketName = self.safe_string(market, 'name')
447
+ if marketName.find('/') < 0:
448
+ # there are some weird spot markets in testnet, eg @2
449
+ continue
446
450
  marketParts = marketName.split('/')
447
451
  baseName = self.safe_string(marketParts, 0)
448
452
  quoteId = self.safe_string(marketParts, 1)
@@ -106,6 +106,7 @@ class idex(Exchange, ImplicitAPI):
106
106
  'fetchWithdrawal': True,
107
107
  'fetchWithdrawals': True,
108
108
  'reduceMargin': False,
109
+ 'sandbox': True,
109
110
  'setLeverage': False,
110
111
  'setMarginMode': False,
111
112
  'setPositionMode': False,
@@ -86,6 +86,7 @@ class krakenfutures(Exchange, ImplicitAPI):
86
86
  'fetchPremiumIndexOHLCV': False,
87
87
  'fetchTickers': True,
88
88
  'fetchTrades': True,
89
+ 'sandbox': True,
89
90
  'setLeverage': True,
90
91
  'setMarginMode': False,
91
92
  'transfer': True,
@@ -91,6 +91,7 @@ class ndax(Exchange, ImplicitAPI):
91
91
  'fetchTradingFees': False,
92
92
  'fetchWithdrawals': True,
93
93
  'reduceMargin': False,
94
+ 'sandbox': True,
94
95
  'setLeverage': False,
95
96
  'setMarginMode': False,
96
97
  'setPositionMode': False,
ccxt/async_support/okx.py CHANGED
@@ -26,6 +26,7 @@ from ccxt.base.errors import CancelPending
26
26
  from ccxt.base.errors import ContractUnavailable
27
27
  from ccxt.base.errors import NotSupported
28
28
  from ccxt.base.errors import NetworkError
29
+ from ccxt.base.errors import DDoSProtection
29
30
  from ccxt.base.errors import RateLimitExceeded
30
31
  from ccxt.base.errors import ExchangeNotAvailable
31
32
  from ccxt.base.errors import OnMaintenance
@@ -162,6 +163,7 @@ class okx(Exchange, ImplicitAPI):
162
163
  'fetchWithdrawalWhitelist': False,
163
164
  'reduceMargin': True,
164
165
  'repayCrossMargin': True,
166
+ 'sandbox': True,
165
167
  'setLeverage': True,
166
168
  'setMargin': False,
167
169
  'setMarginMode': True,
@@ -912,7 +914,24 @@ class okx(Exchange, ImplicitAPI):
912
914
  '60017': BadRequest, # Invalid url path
913
915
  '60018': BadRequest, # The {0} {1} {2} {3} {4} does not exist
914
916
  '60019': BadRequest, # Invalid op {op}
917
+ '60020': ExchangeError, # APIKey subscription amount exceeds the limit
918
+ '60021': AccountNotEnabled, # This operation does not support multiple accounts login
919
+ '60022': AuthenticationError, # Bulk login partially succeeded
920
+ '60023': DDoSProtection, # Bulk login requests too frequent
921
+ '60024': AuthenticationError, # Wrong passphrase
922
+ '60025': ExchangeError, # Token subscription amount exceeds the limit
923
+ '60026': AuthenticationError, # Batch login by APIKey and token simultaneously is not supported
924
+ '60027': ArgumentsRequired, # Parameter {0} can not be empty
925
+ '60028': NotSupported, # The current operation is not supported by self URL
926
+ '60029': AccountNotEnabled, # Only users who are VIP5 and above in trading fee tier are allowed to subscribe to books-l2-tbt channel
927
+ '60030': AccountNotEnabled, # Only users who are VIP4 and above in trading fee tier are allowed to subscribe to books50-l2-tbt channel
928
+ '60031': AuthenticationError, # The WebSocket endpoint does not support multiple account batch login,
929
+ '60032': AuthenticationError, # API key doesn't exist,
915
930
  '63999': ExchangeError, # Internal system error
931
+ '64000': BadRequest, # Subscription parameter uly is unavailable anymore, please replace uly with instFamily. More details can refer to: https://www.okx.com/help-center/changes-to-v5-api-websocket-subscription-parameter-and-url,
932
+ '64001': BadRequest, # This channel has been migrated to the business URL. Please subscribe using the new URL. More details can refer to: https://www.okx.com/help-center/changes-to-v5-api-websocket-subscription-parameter-and-url,
933
+ '64002': BadRequest, # This channel is not supported by business URL. Please use "/private" URL(for private channels), or "/public" URL(for public channels). More details can refer to: https://www.okx.com/help-center/changes-to-v5-api-websocket-subscription-parameter-and-url,
934
+ '64003': AccountNotEnabled, # Your trading fee tier doesnt meet the requirement to access self channel
916
935
  '70010': BadRequest, # Timestamp parameters need to be in Unix timestamp format in milliseconds.
917
936
  '70013': BadRequest, # endTs needs to be bigger than or equal to beginTs.
918
937
  '70016': BadRequest, # Please specify your instrument settings for at least one instType.
@@ -96,6 +96,7 @@ class phemex(Exchange, ImplicitAPI):
96
96
  'fetchTransfers': True,
97
97
  'fetchWithdrawals': True,
98
98
  'reduceMargin': False,
99
+ 'sandbox': True,
99
100
  'setLeverage': True,
100
101
  'setMargin': True,
101
102
  'setMarginMode': True,
@@ -84,6 +84,7 @@ class poloniex(Exchange, ImplicitAPI):
84
84
  'fetchTransfer': False,
85
85
  'fetchTransfers': False,
86
86
  'fetchWithdrawals': True,
87
+ 'sandbox': True,
87
88
  'transfer': True,
88
89
  'withdraw': True,
89
90
  },
@@ -101,6 +101,7 @@ class probit(Exchange, ImplicitAPI):
101
101
  'fetchWithdrawal': False,
102
102
  'fetchWithdrawals': True,
103
103
  'reduceMargin': False,
104
+ 'sandbox': True,
104
105
  'setLeverage': False,
105
106
  'setMarginMode': False,
106
107
  'setPositionMode': False,
@@ -93,6 +93,7 @@ class wavesexchange(Exchange, ImplicitAPI):
93
93
  'fetchTransfer': False,
94
94
  'fetchTransfers': False,
95
95
  'reduceMargin': False,
96
+ 'sandbox': True,
96
97
  'setLeverage': False,
97
98
  'setMarginMode': False,
98
99
  'setPositionMode': False,
ccxt/async_support/woo.py CHANGED
@@ -113,6 +113,7 @@ class woo(Exchange, ImplicitAPI):
113
113
  'fetchTransfers': True,
114
114
  'fetchWithdrawals': True,
115
115
  'reduceMargin': False,
116
+ 'sandbox': True,
116
117
  'setLeverage': True,
117
118
  'setMargin': False,
118
119
  'setPositionMode': True,
@@ -649,7 +649,7 @@ class zaif(Exchange, ImplicitAPI):
649
649
  }
650
650
 
651
651
  def custom_nonce(self):
652
- num = (self.milliseconds() / str(1000))
652
+ num = self.number_to_string(self.milliseconds() / 1000)
653
653
  nonce = float(num)
654
654
  return format(nonce, '.8f')
655
655
 
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.15'
7
+ __version__ = '4.3.17'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -5468,18 +5468,19 @@ class Exchange(object):
5468
5468
  maxRetries = None
5469
5469
  maxRetries, params = self.handle_option_and_params(params, method, 'maxRetries', 3)
5470
5470
  errors = 0
5471
- try:
5472
- if timeframe and method != 'fetchFundingRateHistory':
5473
- return getattr(self, method)(symbol, timeframe, since, limit, params)
5474
- else:
5475
- return getattr(self, method)(symbol, since, limit, params)
5476
- except Exception as e:
5477
- if isinstance(e, RateLimitExceeded):
5478
- raise e # if we are rate limited, we should not retry and fail fast
5479
- errors += 1
5480
- if errors > maxRetries:
5481
- raise e
5482
- return None
5471
+ while(errors <= maxRetries):
5472
+ try:
5473
+ if timeframe and method != 'fetchFundingRateHistory':
5474
+ return getattr(self, method)(symbol, timeframe, since, limit, params)
5475
+ else:
5476
+ return getattr(self, method)(symbol, since, limit, params)
5477
+ except Exception as e:
5478
+ if isinstance(e, RateLimitExceeded):
5479
+ raise e # if we are rate limited, we should not retry and fail fast
5480
+ errors += 1
5481
+ if errors > maxRetries:
5482
+ raise e
5483
+ return []
5483
5484
 
5484
5485
  def fetch_paginated_call_deterministic(self, method: str, symbol: Str = None, since: Int = None, limit: Int = None, timeframe: Str = None, params={}, maxEntriesPerRequest=None):
5485
5486
  maxCalls = None
@@ -5492,6 +5493,8 @@ class Exchange(object):
5492
5493
  currentSince = current - (maxCalls * step) - 1
5493
5494
  if since is not None:
5494
5495
  currentSince = max(currentSince, since)
5496
+ else:
5497
+ currentSince = max(currentSince, 1241440531000) # avoid timestamps older than 2009
5495
5498
  until = self.safe_integer_2(params, 'until', 'till') # do not omit it here
5496
5499
  if until is not None:
5497
5500
  requiredCalls = int(math.ceil((until - since)) / step)
@@ -5500,6 +5503,8 @@ class Exchange(object):
5500
5503
  for i in range(0, maxCalls):
5501
5504
  if (until is not None) and (currentSince >= until):
5502
5505
  break
5506
+ if currentSince >= current:
5507
+ break
5503
5508
  tasks.append(self.safe_deterministic_call(method, symbol, currentSince, maxEntriesPerRequest, timeframe, params))
5504
5509
  currentSince = self.sum(currentSince, step) - 1
5505
5510
  results = tasks