ccxt 4.4.95__py2.py3-none-any.whl → 4.4.97__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 (110) hide show
  1. ccxt/__init__.py +3 -1
  2. ccxt/abstract/binance.py +3 -0
  3. ccxt/abstract/binancecoinm.py +3 -0
  4. ccxt/abstract/binanceus.py +3 -0
  5. ccxt/abstract/binanceusdm.py +3 -0
  6. ccxt/abstract/foxbit.py +26 -0
  7. ccxt/abstract/hyperliquid.py +1 -1
  8. ccxt/abstract/phemex.py +1 -0
  9. ccxt/apex.py +3 -3
  10. ccxt/ascendex.py +2 -2
  11. ccxt/async_support/__init__.py +3 -1
  12. ccxt/async_support/apex.py +3 -3
  13. ccxt/async_support/ascendex.py +2 -2
  14. ccxt/async_support/base/exchange.py +10 -5
  15. ccxt/async_support/base/ws/future.py +5 -3
  16. ccxt/async_support/binance.py +90 -34
  17. ccxt/async_support/binancecoinm.py +5 -1
  18. ccxt/async_support/binanceus.py +3 -1
  19. ccxt/async_support/binanceusdm.py +3 -1
  20. ccxt/async_support/bingx.py +1 -1
  21. ccxt/async_support/bitget.py +30 -143
  22. ccxt/async_support/bitmart.py +2 -2
  23. ccxt/async_support/bitrue.py +13 -8
  24. ccxt/async_support/bybit.py +14 -5
  25. ccxt/async_support/coinbaseexchange.py +4 -2
  26. ccxt/async_support/coinbaseinternational.py +2 -2
  27. ccxt/async_support/coinspot.py +36 -1
  28. ccxt/async_support/cryptocom.py +78 -3
  29. ccxt/async_support/cryptomus.py +41 -1
  30. ccxt/async_support/defx.py +1 -1
  31. ccxt/async_support/derive.py +1 -1
  32. ccxt/async_support/ellipx.py +40 -0
  33. ccxt/async_support/exmo.py +1 -1
  34. ccxt/async_support/foxbit.py +1935 -0
  35. ccxt/async_support/gate.py +1 -2
  36. ccxt/async_support/hashkey.py +39 -0
  37. ccxt/async_support/hyperliquid.py +42 -27
  38. ccxt/async_support/independentreserve.py +35 -0
  39. ccxt/async_support/indodax.py +34 -0
  40. ccxt/async_support/kucoin.py +3 -2
  41. ccxt/async_support/kucoinfutures.py +3 -2
  42. ccxt/async_support/latoken.py +42 -0
  43. ccxt/async_support/luno.py +36 -0
  44. ccxt/async_support/mercado.py +34 -0
  45. ccxt/async_support/mexc.py +31 -32
  46. ccxt/async_support/modetrade.py +3 -3
  47. ccxt/async_support/okcoin.py +1 -1
  48. ccxt/async_support/okx.py +10 -3
  49. ccxt/async_support/onetrading.py +1 -1
  50. ccxt/async_support/oxfun.py +2 -1
  51. ccxt/async_support/paradex.py +2 -2
  52. ccxt/async_support/phemex.py +36 -31
  53. ccxt/async_support/vertex.py +3 -2
  54. ccxt/async_support/woo.py +6 -2
  55. ccxt/async_support/woofipro.py +2 -2
  56. ccxt/base/decimal_to_precision.py +16 -10
  57. ccxt/base/errors.py +6 -0
  58. ccxt/base/exchange.py +60 -17
  59. ccxt/binance.py +90 -34
  60. ccxt/binancecoinm.py +5 -1
  61. ccxt/binanceus.py +3 -1
  62. ccxt/binanceusdm.py +3 -1
  63. ccxt/bingx.py +1 -1
  64. ccxt/bitget.py +30 -143
  65. ccxt/bitmart.py +2 -2
  66. ccxt/bitrue.py +13 -8
  67. ccxt/bybit.py +14 -5
  68. ccxt/coinbaseexchange.py +4 -2
  69. ccxt/coinbaseinternational.py +2 -2
  70. ccxt/coinspot.py +36 -1
  71. ccxt/cryptocom.py +78 -3
  72. ccxt/cryptomus.py +41 -1
  73. ccxt/defx.py +1 -1
  74. ccxt/derive.py +1 -1
  75. ccxt/ellipx.py +40 -0
  76. ccxt/exmo.py +1 -1
  77. ccxt/foxbit.py +1935 -0
  78. ccxt/gate.py +1 -2
  79. ccxt/hashkey.py +39 -0
  80. ccxt/hyperliquid.py +42 -27
  81. ccxt/independentreserve.py +35 -0
  82. ccxt/indodax.py +34 -0
  83. ccxt/kucoin.py +3 -2
  84. ccxt/kucoinfutures.py +3 -2
  85. ccxt/latoken.py +42 -0
  86. ccxt/luno.py +36 -0
  87. ccxt/mercado.py +34 -0
  88. ccxt/mexc.py +31 -32
  89. ccxt/modetrade.py +3 -3
  90. ccxt/okcoin.py +1 -1
  91. ccxt/okx.py +10 -3
  92. ccxt/onetrading.py +1 -1
  93. ccxt/oxfun.py +2 -1
  94. ccxt/paradex.py +2 -2
  95. ccxt/phemex.py +36 -31
  96. ccxt/pro/__init__.py +1 -1
  97. ccxt/pro/binancecoinm.py +3 -1
  98. ccxt/pro/binanceus.py +3 -1
  99. ccxt/pro/binanceusdm.py +3 -1
  100. ccxt/pro/bybit.py +33 -1
  101. ccxt/test/tests_async.py +15 -0
  102. ccxt/test/tests_sync.py +15 -0
  103. ccxt/vertex.py +3 -2
  104. ccxt/woo.py +6 -2
  105. ccxt/woofipro.py +2 -2
  106. {ccxt-4.4.95.dist-info → ccxt-4.4.97.dist-info}/METADATA +19 -19
  107. {ccxt-4.4.95.dist-info → ccxt-4.4.97.dist-info}/RECORD +110 -107
  108. {ccxt-4.4.95.dist-info → ccxt-4.4.97.dist-info}/LICENSE.txt +0 -0
  109. {ccxt-4.4.95.dist-info → ccxt-4.4.97.dist-info}/WHEEL +0 -0
  110. {ccxt-4.4.95.dist-info → ccxt-4.4.97.dist-info}/top_level.txt +0 -0
ccxt/async_support/woo.py CHANGED
@@ -1503,8 +1503,11 @@ class woo(Exchange, ImplicitAPI):
1503
1503
  if symbol is not None:
1504
1504
  market = self.market(symbol)
1505
1505
  request['symbol'] = market['id']
1506
+ response = None
1506
1507
  if trigger:
1507
- return await self.v3PrivateDeleteTradeAlgoOrders(params)
1508
+ response = await self.v3PrivateDeleteTradeAlgoOrders(params)
1509
+ else:
1510
+ response = await self.v3PrivateDeleteTradeOrders(self.extend(request, params))
1508
1511
  #
1509
1512
  # {
1510
1513
  # "success": True,
@@ -1514,7 +1517,8 @@ class woo(Exchange, ImplicitAPI):
1514
1517
  # "timestamp": 1751941988134
1515
1518
  # }
1516
1519
  #
1517
- return await self.v3PrivateDeleteTradeOrders(self.extend(request, params))
1520
+ data = self.safe_dict(response, 'data', {})
1521
+ return [self.safe_order({'info': data})]
1518
1522
 
1519
1523
  async def cancel_all_orders_after(self, timeout: Int, params={}):
1520
1524
  """
@@ -1761,9 +1761,9 @@ class woofipro(Exchange, ImplicitAPI):
1761
1761
  # }
1762
1762
  #
1763
1763
  return [
1764
- {
1764
+ self.safe_order({
1765
1765
  'info': response,
1766
- },
1766
+ }),
1767
1767
  ]
1768
1768
 
1769
1769
  async def fetch_order(self, id: str, symbol: Str = None, params={}):
@@ -33,18 +33,24 @@ NO_PADDING = 5
33
33
  PAD_WITH_ZERO = 6
34
34
 
35
35
 
36
- def decimal_to_precision(n, rounding_mode=ROUND, precision=None, counting_mode=DECIMAL_PLACES, padding_mode=NO_PADDING):
37
- assert precision is not None
36
+ def decimal_to_precision(n, rounding_mode=ROUND, numPrecisionDigits=None, counting_mode=DECIMAL_PLACES, padding_mode=NO_PADDING):
37
+ assert numPrecisionDigits is not None, 'numPrecisionDigits should not be None'
38
+
39
+ if isinstance(numPrecisionDigits, str):
40
+ numPrecisionDigits = float(numPrecisionDigits)
41
+ assert isinstance(numPrecisionDigits, float) or isinstance(numPrecisionDigits, decimal.Decimal) or isinstance(numPrecisionDigits, numbers.Integral), 'numPrecisionDigits has an invalid number'
42
+
38
43
  if counting_mode == TICK_SIZE:
39
- assert(isinstance(precision, float) or isinstance(precision, decimal.Decimal) or isinstance(precision, numbers.Integral) or isinstance(precision, str))
44
+ assert numPrecisionDigits > 0, 'negative or zero numPrecisionDigits can not be used with TICK_SIZE precisionMode'
40
45
  else:
41
- assert(isinstance(precision, numbers.Integral))
46
+ assert isinstance(numPrecisionDigits, numbers.Integral)
47
+
42
48
  assert rounding_mode in [TRUNCATE, ROUND]
43
49
  assert counting_mode in [DECIMAL_PLACES, SIGNIFICANT_DIGITS, TICK_SIZE]
44
50
  assert padding_mode in [NO_PADDING, PAD_WITH_ZERO]
51
+ # end of checks
45
52
 
46
- if isinstance(precision, str):
47
- precision = float(precision)
53
+ precision = numPrecisionDigits # "precision" variable name was in signature, but to make function signature similar to php/js, I had to change the argument name to "numPrecisionDigits". however, the below codes use "precision" variable name, so we have to assign that name here (you can change the usage of 'precision' variable name below everywhere, but i've refrained to do that to avoid many changes)
48
54
 
49
55
  context = decimal.getcontext()
50
56
 
@@ -78,12 +84,12 @@ def decimal_to_precision(n, rounding_mode=ROUND, precision=None, counting_mode=D
78
84
  if missing != 0:
79
85
  if rounding_mode == ROUND:
80
86
  if dec > 0:
81
- if missing >= precision / 2:
87
+ if missing >= precision_dec / 2:
82
88
  dec = dec - missing + precision_dec
83
89
  else:
84
90
  dec = dec - missing
85
91
  else:
86
- if missing >= precision / 2:
92
+ if missing >= precision_dec / 2:
87
93
  dec = dec + missing - precision_dec
88
94
  else:
89
95
  dec = dec + missing
@@ -117,7 +123,7 @@ def decimal_to_precision(n, rounding_mode=ROUND, precision=None, counting_mode=D
117
123
  precise = '{:f}'.format(min((below, above), key=lambda x: abs(x - dec)))
118
124
  else:
119
125
  precise = '{:f}'.format(dec.quantize(sigfig))
120
- if precise == ('-0.' + len(precise) * '0')[:2] or precise == '-0':
126
+ if precise.startswith('-0') and all(c in '0.' for c in precise[1:]):
121
127
  precise = precise[1:]
122
128
 
123
129
  elif rounding_mode == TRUNCATE:
@@ -138,7 +144,7 @@ def decimal_to_precision(n, rounding_mode=ROUND, precision=None, counting_mode=D
138
144
  precise = string
139
145
  else:
140
146
  precise = string[:end].ljust(dot, '0')
141
- if precise == ('-0.' + len(precise) * '0')[:3] or precise == '-0':
147
+ if precise.startswith('-0') and all(c in '0.' for c in precise[1:]):
142
148
  precise = precise[1:]
143
149
  precise = precise.rstrip('.')
144
150
 
ccxt/base/errors.py CHANGED
@@ -1,3 +1,9 @@
1
+ # ----------------------------------------------------------------------------
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+ # EDIT THE CORRESPONDENT .ts FILE INSTEAD
6
+
1
7
  error_hierarchy = {
2
8
  'BaseError': {
3
9
  'ExchangeError': {
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.95'
7
+ __version__ = '4.4.97'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -229,6 +229,7 @@ class Exchange(object):
229
229
  'chrome100': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36',
230
230
  }
231
231
  headers = None
232
+ returnResponseHeaders = False
232
233
  origin = '*' # CORS origin
233
234
  MAX_VALUE = float('inf')
234
235
  #
@@ -579,6 +580,8 @@ class Exchange(object):
579
580
  if self.verbose:
580
581
  self.log("\nfetch Response:", self.id, method, url, http_status_code, "ResponseHeaders:", headers, "ResponseBody:", http_response)
581
582
  self.logger.debug("%s %s, Response: %s %s %s", method, url, http_status_code, headers, http_response)
583
+ if json_response and not isinstance(json_response, list) and self.returnResponseHeaders:
584
+ json_response['responseHeaders'] = headers
582
585
  response.raise_for_status()
583
586
 
584
587
  except Timeout as e:
@@ -2130,6 +2133,17 @@ class Exchange(object):
2130
2133
  'watchLiquidations': None,
2131
2134
  'watchLiquidationsForSymbols': None,
2132
2135
  'watchMyLiquidations': None,
2136
+ 'unWatchOrders': None,
2137
+ 'unWatchTrades': None,
2138
+ 'unWatchTradesForSymbols': None,
2139
+ 'unWatchOHLCVForSymbols': None,
2140
+ 'unWatchOrderBookForSymbols': None,
2141
+ 'unWatchPositions': None,
2142
+ 'unWatchOrderBook': None,
2143
+ 'unWatchTickers': None,
2144
+ 'unWatchMyTrades': None,
2145
+ 'unWatchTicker': None,
2146
+ 'unWatchOHLCV': None,
2133
2147
  'watchMyLiquidationsForSymbols': None,
2134
2148
  'withdraw': None,
2135
2149
  'ws': None,
@@ -2616,6 +2630,9 @@ class Exchange(object):
2616
2630
  def un_watch_order_book_for_symbols(self, symbols: List[str], params={}):
2617
2631
  raise NotSupported(self.id + ' unWatchOrderBookForSymbols() is not supported yet')
2618
2632
 
2633
+ def un_watch_positions(self, symbols: Strings = None, params={}):
2634
+ raise NotSupported(self.id + ' unWatchPositions() is not supported yet')
2635
+
2619
2636
  def fetch_deposit_addresses(self, codes: Strings = None, params={}):
2620
2637
  raise NotSupported(self.id + ' fetchDepositAddresses() is not supported yet')
2621
2638
 
@@ -3584,18 +3601,7 @@ class Exchange(object):
3584
3601
  symbol = market['symbol'] if (market is not None) else None
3585
3602
  return self.filter_by_symbol_since_limit(results, symbol, since, limit)
3586
3603
 
3587
- def calculate_fee(self, symbol: str, type: str, side: str, amount: float, price: float, takerOrMaker='taker', params={}):
3588
- """
3589
- calculates the presumptive fee that would be charged for an order
3590
- :param str symbol: unified market symbol
3591
- :param str type: 'market' or 'limit'
3592
- :param str side: 'buy' or 'sell'
3593
- :param float amount: how much you want to trade, in units of the base currency on most exchanges, or number of contracts
3594
- :param float price: the price for the order to be filled at, in units of the quote currency
3595
- :param str takerOrMaker: 'taker' or 'maker'
3596
- :param dict params:
3597
- :returns dict: contains the rate, the percentage multiplied to the order amount to obtain the fee amount, and cost, the total value of the fee in units of the quote currency, for the order
3598
- """
3604
+ def calculate_fee_with_rate(self, symbol: str, type: str, side: str, amount: float, price: float, takerOrMaker='taker', feeRate: Num = None, params={}):
3599
3605
  if type == 'market' and takerOrMaker == 'maker':
3600
3606
  raise ArgumentsRequired(self.id + ' calculateFee() - you have provided incompatible arguments - "market" type order can not be "maker". Change either the "type" or the "takerOrMaker" argument to calculate the fee.')
3601
3607
  market = self.markets[symbol]
@@ -3624,7 +3630,7 @@ class Exchange(object):
3624
3630
  # even if `takerOrMaker` argument was set to 'maker', for 'market' orders we should forcefully override it to 'taker'
3625
3631
  if type == 'market':
3626
3632
  takerOrMaker = 'taker'
3627
- rate = self.safe_string(market, takerOrMaker)
3633
+ rate = self.number_to_string(feeRate) if (feeRate is not None) else self.safe_string(market, takerOrMaker)
3628
3634
  cost = Precise.string_mul(cost, rate)
3629
3635
  return {
3630
3636
  'type': takerOrMaker,
@@ -3633,6 +3639,20 @@ class Exchange(object):
3633
3639
  'cost': self.parse_number(cost),
3634
3640
  }
3635
3641
 
3642
+ def calculate_fee(self, symbol: str, type: str, side: str, amount: float, price: float, takerOrMaker='taker', params={}):
3643
+ """
3644
+ calculates the presumptive fee that would be charged for an order
3645
+ :param str symbol: unified market symbol
3646
+ :param str type: 'market' or 'limit'
3647
+ :param str side: 'buy' or 'sell'
3648
+ :param float amount: how much you want to trade, in units of the base currency on most exchanges, or number of contracts
3649
+ :param float price: the price for the order to be filled at, in units of the quote currency
3650
+ :param str takerOrMaker: 'taker' or 'maker'
3651
+ :param dict params:
3652
+ :returns dict: contains the rate, the percentage multiplied to the order amount to obtain the fee amount, and cost, the total value of the fee in units of the quote currency, for the order
3653
+ """
3654
+ return self.calculate_fee_with_rate(symbol, type, side, amount, price, takerOrMaker, None, params)
3655
+
3636
3656
  def safe_liquidation(self, liquidation: dict, market: Market = None):
3637
3657
  contracts = self.safe_string(liquidation, 'contracts')
3638
3658
  contractSize = self.safe_string(market, 'contractSize')
@@ -3672,6 +3692,21 @@ class Exchange(object):
3672
3692
  trade['cost'] = self.parse_number(cost)
3673
3693
  return trade
3674
3694
 
3695
+ def create_ccxt_trade_id(self, timestamp=None, side=None, amount=None, price=None, takerOrMaker=None):
3696
+ # self approach is being used by multiple exchanges(mexc, woo, coinsbit, dydx, ...)
3697
+ id = None
3698
+ if timestamp is not None:
3699
+ id = self.number_to_string(timestamp)
3700
+ if side is not None:
3701
+ id += '-' + side
3702
+ if amount is not None:
3703
+ id += '-' + self.number_to_string(amount)
3704
+ if price is not None:
3705
+ id += '-' + self.number_to_string(price)
3706
+ if takerOrMaker is not None:
3707
+ id += '-' + takerOrMaker
3708
+ return id
3709
+
3675
3710
  def parsed_fee_and_fees(self, container: Any):
3676
3711
  fee = self.safe_dict(container, 'fee')
3677
3712
  fees = self.safe_list(container, 'fees')
@@ -5495,10 +5530,10 @@ class Exchange(object):
5495
5530
  """
5496
5531
  raise NotSupported(self.id + ' fetchDepositsWithdrawals() is not supported yet')
5497
5532
 
5498
- def fetch_deposits(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
5533
+ def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
5499
5534
  raise NotSupported(self.id + ' fetchDeposits() is not supported yet')
5500
5535
 
5501
- def fetch_withdrawals(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
5536
+ def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
5502
5537
  raise NotSupported(self.id + ' fetchWithdrawals() is not supported yet')
5503
5538
 
5504
5539
  def fetch_deposits_ws(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
@@ -6426,7 +6461,7 @@ class Exchange(object):
6426
6461
  calls = 0
6427
6462
  result = []
6428
6463
  errors = 0
6429
- until = self.safe_integer_2(params, 'untill', 'till') # do not omit it from params here
6464
+ until = self.safe_integer_n(params, ['until', 'untill', 'till']) # do not omit it from params here
6430
6465
  maxEntriesPerRequest, params = self.handle_max_entries_per_request_and_params(method, maxEntriesPerRequest, params)
6431
6466
  if (paginationDirection == 'forward'):
6432
6467
  if since is None:
@@ -6988,6 +7023,14 @@ class Exchange(object):
6988
7023
  self.myTrades = None
6989
7024
  elif topic == 'orders' and (self.orders is not None):
6990
7025
  self.orders = None
7026
+ elif topic == 'positions' and (self.positions is not None):
7027
+ self.positions = None
7028
+ clients = list(self.clients.values())
7029
+ for i in range(0, len(clients)):
7030
+ client = clients[i]
7031
+ futures = self.safe_dict(client, 'futures')
7032
+ if (futures is not None) and ('fetchPositionsSnapshot' in futures):
7033
+ del futures['fetchPositionsSnapshot']
6991
7034
  elif topic == 'ticker' and (self.tickers is not None):
6992
7035
  tickerSymbols = list(self.tickers.keys())
6993
7036
  for i in range(0, len(tickerSymbols)):
ccxt/binance.py CHANGED
@@ -505,6 +505,7 @@ class binance(Exchange, ImplicitAPI):
505
505
  'portfolio/balance': 2,
506
506
  'portfolio/negative-balance-exchange-record': 2,
507
507
  'portfolio/pmloan-history': 5,
508
+ 'portfolio/earn-asset-balance': 150, # Weight(IP): 1500 => cost = 0.1 * 1500 = 150
508
509
  # staking
509
510
  'staking/productList': 0.1,
510
511
  'staking/position': 0.1,
@@ -663,6 +664,7 @@ class binance(Exchange, ImplicitAPI):
663
664
  'portfolio/repay-futures-negative-balance': 150, # Weight(IP): 1500 => cost = 0.1 * 1500 = 150
664
665
  'portfolio/mint': 20,
665
666
  'portfolio/redeem': 20,
667
+ 'portfolio/earn-asset-transfer': 150, # Weight(IP): 1500 => cost = 0.1 * 1500 = 150
666
668
  'lending/auto-invest/plan/add': 0.1, # Weight(IP): 1 => cost = 0.1 * 1 = 0.1
667
669
  'lending/auto-invest/plan/edit': 0.1, # Weight(IP): 1 => cost = 0.1 * 1 = 0.1
668
670
  'lending/auto-invest/plan/edit-status': 0.1, # Weight(IP): 1 => cost = 0.1 * 1 = 0.1
@@ -851,6 +853,7 @@ class binance(Exchange, ImplicitAPI):
851
853
  'apiTradingStatus': {'cost': 1, 'noSymbol': 10},
852
854
  'lvtKlines': 1,
853
855
  'convert/exchangeInfo': 4,
856
+ 'insuranceBalance': 1,
854
857
  },
855
858
  },
856
859
  'fapiData': {
@@ -1288,12 +1291,14 @@ class binance(Exchange, ImplicitAPI):
1288
1291
  'options': {
1289
1292
  'sandboxMode': False,
1290
1293
  'fetchMargins': True,
1291
- 'fetchMarkets': [
1292
- 'spot', # allows CORS in browsers
1293
- 'linear', # allows CORS in browsers
1294
- 'inverse', # allows CORS in browsers
1295
- # 'option', # does not allow CORS, enable outside of the browser only
1296
- ],
1294
+ 'fetchMarkets': {
1295
+ 'types': [
1296
+ 'spot', # allows CORS in browsers
1297
+ 'linear', # allows CORS in browsers
1298
+ 'inverse', # allows CORS in browsers
1299
+ # 'option', # does not allow CORS, enable outside of the browser only
1300
+ ],
1301
+ },
1297
1302
  'loadAllOptions': False,
1298
1303
  'fetchCurrencies': True, # self is a private call and it requires API keys
1299
1304
  # 'fetchTradesMethod': 'publicGetAggTrades', # publicGetTrades, publicGetHistoricalTrades, eapiPublicGetTrades
@@ -3021,7 +3026,14 @@ class binance(Exchange, ImplicitAPI):
3021
3026
  :returns dict[]: an array of objects representing market data
3022
3027
  """
3023
3028
  promisesRaw = []
3024
- rawFetchMarkets = self.safe_list(self.options, 'fetchMarkets', ['spot', 'linear', 'inverse'])
3029
+ rawFetchMarkets = None
3030
+ defaultTypes = ['spot', 'linear', 'inverse']
3031
+ fetchMarketsOptions = self.safe_dict(self.options, 'fetchMarkets')
3032
+ if fetchMarketsOptions is not None:
3033
+ rawFetchMarkets = self.safe_list(fetchMarketsOptions, 'types', defaultTypes)
3034
+ else:
3035
+ # for backward-compatibility
3036
+ rawFetchMarkets = self.safe_list(self.options, 'fetchMarkets', defaultTypes)
3025
3037
  # handle loadAllOptions option
3026
3038
  loadAllOptions = self.safe_bool(self.options, 'loadAllOptions', False)
3027
3039
  if loadAllOptions:
@@ -3913,29 +3925,52 @@ class binance(Exchange, ImplicitAPI):
3913
3925
  # "time": 1597370495002
3914
3926
  # }
3915
3927
  #
3916
- # {
3917
- # "symbol": "ETHBTC",
3918
- # "priceChange": "0.00068700",
3919
- # "priceChangePercent": "2.075",
3920
- # "weightedAvgPrice": "0.03342681",
3921
- # "prevClosePrice": "0.03310300",
3922
- # "lastPrice": "0.03378900",
3923
- # "lastQty": "0.07700000",
3924
- # "bidPrice": "0.03378900",
3925
- # "bidQty": "7.16800000",
3926
- # "askPrice": "0.03379000",
3927
- # "askQty": "24.00000000",
3928
- # "openPrice": "0.03310200",
3929
- # "highPrice": "0.03388900",
3930
- # "lowPrice": "0.03306900",
3931
- # "volume": "205478.41000000",
3932
- # "quoteVolume": "6868.48826294",
3933
- # "openTime": 1601469986932,
3934
- # "closeTime": 1601556386932,
3935
- # "firstId": 196098772,
3936
- # "lastId": 196186315,
3937
- # "count": 87544
3938
- # }
3928
+ # spot - ticker
3929
+ #
3930
+ # {
3931
+ # "symbol": "BTCUSDT",
3932
+ # "priceChange": "-188.18000000",
3933
+ # "priceChangePercent": "-0.159",
3934
+ # "weightedAvgPrice": "118356.64734074",
3935
+ # "lastPrice": "118449.03000000",
3936
+ # "prevClosePrice": "118637.22000000", # field absent in rolling ticker
3937
+ # "lastQty": "0.00731000", # field absent in rolling ticker
3938
+ # "bidPrice": "118449.02000000", # field absent in rolling ticker
3939
+ # "bidQty": "7.15931000", # field absent in rolling ticker
3940
+ # "askPrice": "118449.03000000", # field absent in rolling ticker
3941
+ # "askQty": "0.09592000", # field absent in rolling ticker
3942
+ # "openPrice": "118637.21000000",
3943
+ # "highPrice": "119273.36000000",
3944
+ # "lowPrice": "117427.50000000",
3945
+ # "volume": "14741.41491000",
3946
+ # "quoteVolume": "1744744445.80640740",
3947
+ # "openTime": "1753701474013",
3948
+ # "closeTime": "1753787874013",
3949
+ # "firstId": "5116031635",
3950
+ # "lastId": "5117964946",
3951
+ # "count": "1933312"
3952
+ # }
3953
+ #
3954
+ # usdm tickers
3955
+ #
3956
+ # {
3957
+ # "symbol": "SUSDT",
3958
+ # "priceChange": "-0.0229000",
3959
+ # "priceChangePercent": "-6.777",
3960
+ # "weightedAvgPrice": "0.3210035",
3961
+ # "lastPrice": "0.3150000",
3962
+ # "lastQty": "16",
3963
+ # "openPrice": "0.3379000",
3964
+ # "highPrice": "0.3411000",
3965
+ # "lowPrice": "0.3071000",
3966
+ # "volume": "120588225",
3967
+ # "quoteVolume": "38709237.2289000",
3968
+ # "openTime": "1753701720000",
3969
+ # "closeTime": "1753788172414",
3970
+ # "firstId": "72234973",
3971
+ # "lastId": "72423677",
3972
+ # "count": "188700"
3973
+ # }
3939
3974
  #
3940
3975
  # coinm
3941
3976
  #
@@ -4286,16 +4321,37 @@ class binance(Exchange, ImplicitAPI):
4286
4321
  elif self.is_inverse(type, subType):
4287
4322
  response = self.dapiPublicGetTicker24hr(params)
4288
4323
  elif type == 'spot':
4289
- request: dict = {}
4290
- if symbols is not None:
4291
- request['symbols'] = self.json(self.market_ids(symbols))
4292
- response = self.publicGetTicker24hr(self.extend(request, params))
4324
+ rolling = self.safe_bool(params, 'rolling', False)
4325
+ params = self.omit(params, 'rolling')
4326
+ if rolling:
4327
+ symbols = self.market_symbols(symbols)
4328
+ request: dict = {
4329
+ 'symbols': self.json(self.market_ids(symbols)),
4330
+ }
4331
+ response = self.publicGetTicker(self.extend(request, params))
4332
+ # parseTicker is not able to handle marketType for spot-rolling ticker fields, so we need custom parsing
4333
+ return self.parse_tickers_for_rolling(response, symbols)
4334
+ else:
4335
+ request: dict = {}
4336
+ if symbols is not None:
4337
+ request['symbols'] = self.json(self.market_ids(symbols))
4338
+ response = self.publicGetTicker24hr(self.extend(request, params))
4293
4339
  elif type == 'option':
4294
4340
  response = self.eapiPublicGetTicker(params)
4295
4341
  else:
4296
4342
  raise NotSupported(self.id + ' fetchTickers() does not support ' + type + ' markets yet')
4297
4343
  return self.parse_tickers(response, symbols)
4298
4344
 
4345
+ def parse_tickers_for_rolling(self, response, symbols):
4346
+ results = []
4347
+ for i in range(0, len(response)):
4348
+ marketId = self.safe_string(response[i], 'symbol')
4349
+ tickerMarket = self.safe_market(marketId, None, None, 'spot')
4350
+ parsedTicker = self.parse_ticker(response[i])
4351
+ parsedTicker['symbol'] = tickerMarket['symbol']
4352
+ results.append(parsedTicker)
4353
+ return self.filter_by_array(results, 'symbol', symbols)
4354
+
4299
4355
  def fetch_mark_price(self, symbol: str, params={}) -> Ticker:
4300
4356
  """
4301
4357
  fetches mark price for the market
ccxt/binancecoinm.py CHANGED
@@ -32,7 +32,11 @@ class binancecoinm(binance, ImplicitAPI):
32
32
  'createStopMarketOrder': True,
33
33
  },
34
34
  'options': {
35
- 'fetchMarkets': ['inverse'],
35
+ 'fetchMarkets': {
36
+ 'types': [
37
+ 'inverse',
38
+ ],
39
+ },
36
40
  'defaultSubType': 'inverse',
37
41
  'leverageBrackets': None,
38
42
  },
ccxt/binanceus.py CHANGED
@@ -43,7 +43,9 @@ class binanceus(binance, ImplicitAPI):
43
43
  },
44
44
  },
45
45
  'options': {
46
- 'fetchMarkets': ['spot'],
46
+ 'fetchMarkets': {
47
+ 'types': ['spot'],
48
+ },
47
49
  'defaultType': 'spot',
48
50
  'fetchMargins': False,
49
51
  'quoteOrderQty': False,
ccxt/binanceusdm.py CHANGED
@@ -33,7 +33,9 @@ class binanceusdm(binance, ImplicitAPI):
33
33
  'createStopMarketOrder': True,
34
34
  },
35
35
  'options': {
36
- 'fetchMarkets': ['linear'],
36
+ 'fetchMarkets': {
37
+ 'types': ['linear'],
38
+ },
37
39
  'defaultSubType': 'linear',
38
40
  # https://www.binance.com/en/support/faq/360033162192
39
41
  # tier amount, maintenance margin, initial margin,
ccxt/bingx.py CHANGED
@@ -5057,7 +5057,7 @@ class bingx(Exchange, ImplicitAPI):
5057
5057
  id = self.safe_string(transaction, 'id', dataId)
5058
5058
  address = self.safe_string(transaction, 'address')
5059
5059
  tag = self.safe_string(transaction, 'addressTag')
5060
- timestamp = self.safe_integer(transaction, 'insertTime')
5060
+ timestamp = self.safe_integer_2(transaction, 'insertTime', 'timestamp')
5061
5061
  datetime = self.iso8601(timestamp)
5062
5062
  if timestamp is None:
5063
5063
  datetime = self.safe_string(transaction, 'applyTime')