ccxt 4.4.23__py2.py3-none-any.whl → 4.4.25__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 (47) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/binance.py +1 -1
  3. ccxt/abstract/binancecoinm.py +1 -1
  4. ccxt/abstract/binanceus.py +1 -1
  5. ccxt/abstract/binanceusdm.py +1 -1
  6. ccxt/abstract/kucoin.py +1 -0
  7. ccxt/abstract/kucoinfutures.py +1 -0
  8. ccxt/async_support/__init__.py +1 -1
  9. ccxt/async_support/base/exchange.py +1 -1
  10. ccxt/async_support/binance.py +1 -1
  11. ccxt/async_support/bitmex.py +8 -7
  12. ccxt/async_support/bybit.py +37 -4
  13. ccxt/async_support/coincatch.py +1 -1
  14. ccxt/async_support/coinex.py +45 -21
  15. ccxt/async_support/gate.py +177 -59
  16. ccxt/async_support/hitbtc.py +5 -9
  17. ccxt/async_support/htx.py +16 -16
  18. ccxt/async_support/hyperliquid.py +1 -1
  19. ccxt/async_support/kucoin.py +15 -8
  20. ccxt/async_support/woofipro.py +1 -1
  21. ccxt/async_support/xt.py +4 -1
  22. ccxt/async_support/yobit.py +1 -1
  23. ccxt/base/exchange.py +5 -4
  24. ccxt/binance.py +1 -1
  25. ccxt/bitmex.py +8 -7
  26. ccxt/bybit.py +37 -4
  27. ccxt/coincatch.py +1 -1
  28. ccxt/coinex.py +45 -21
  29. ccxt/gate.py +177 -59
  30. ccxt/hitbtc.py +5 -9
  31. ccxt/htx.py +16 -16
  32. ccxt/hyperliquid.py +1 -1
  33. ccxt/kucoin.py +15 -8
  34. ccxt/pro/__init__.py +1 -1
  35. ccxt/pro/kucoin.py +2 -1
  36. ccxt/pro/onetrading.py +2 -1
  37. ccxt/test/tests_async.py +14 -5
  38. ccxt/test/tests_sync.py +14 -5
  39. ccxt/woofipro.py +1 -1
  40. ccxt/xt.py +4 -1
  41. ccxt/yobit.py +1 -1
  42. ccxt-4.4.25.dist-info/METADATA +636 -0
  43. {ccxt-4.4.23.dist-info → ccxt-4.4.25.dist-info}/RECORD +46 -46
  44. ccxt-4.4.23.dist-info/METADATA +0 -636
  45. {ccxt-4.4.23.dist-info → ccxt-4.4.25.dist-info}/LICENSE.txt +0 -0
  46. {ccxt-4.4.23.dist-info → ccxt-4.4.25.dist-info}/WHEEL +0 -0
  47. {ccxt-4.4.23.dist-info → ccxt-4.4.25.dist-info}/top_level.txt +0 -0
ccxt/async_support/htx.py CHANGED
@@ -4905,15 +4905,15 @@ class htx(Exchange, ImplicitAPI):
4905
4905
  orderType = type.replace('buy-', '')
4906
4906
  orderType = orderType.replace('sell-', '')
4907
4907
  options = self.safe_value(self.options, market['type'], {})
4908
- stopPrice = self.safe_string_2(params, 'stopPrice', 'stop-price')
4909
- if stopPrice is None:
4908
+ triggerPrice = self.safe_string_n(params, ['triggerPrice', 'stopPrice', 'stop-price'])
4909
+ if triggerPrice is None:
4910
4910
  stopOrderTypes = self.safe_value(options, 'stopOrderTypes', {})
4911
4911
  if orderType in stopOrderTypes:
4912
- raise ArgumentsRequired(self.id + ' createOrder() requires a stopPrice or a stop-price parameter for a stop order')
4912
+ raise ArgumentsRequired(self.id + ' createOrder() requires a triggerPrice for a stop order')
4913
4913
  else:
4914
4914
  defaultOperator = 'lte' if (side == 'sell') else 'gte'
4915
4915
  stopOperator = self.safe_string(params, 'operator', defaultOperator)
4916
- request['stop-price'] = self.price_to_precision(symbol, stopPrice)
4916
+ request['stop-price'] = self.price_to_precision(symbol, triggerPrice)
4917
4917
  request['operator'] = stopOperator
4918
4918
  if (orderType == 'limit') or (orderType == 'limit-fok'):
4919
4919
  orderType = 'stop-' + orderType
@@ -4971,7 +4971,7 @@ class htx(Exchange, ImplicitAPI):
4971
4971
  limitOrderTypes = self.safe_value(options, 'limitOrderTypes', {})
4972
4972
  if orderType in limitOrderTypes:
4973
4973
  request['price'] = self.price_to_precision(symbol, price)
4974
- params = self.omit(params, ['stopPrice', 'stop-price', 'clientOrderId', 'client-order-id', 'operator', 'timeInForce'])
4974
+ params = self.omit(params, ['triggerPrice', 'stopPrice', 'stop-price', 'clientOrderId', 'client-order-id', 'operator', 'timeInForce'])
4975
4975
  return self.extend(request, params)
4976
4976
 
4977
4977
  def create_contract_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
@@ -5004,16 +5004,16 @@ class htx(Exchange, ImplicitAPI):
5004
5004
  type = 'fok'
5005
5005
  elif timeInForce == 'IOC':
5006
5006
  type = 'ioc'
5007
- triggerPrice = self.safe_number_2(params, 'stopPrice', 'trigger_price')
5007
+ triggerPrice = self.safe_number_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
5008
5008
  stopLossTriggerPrice = self.safe_number_2(params, 'stopLossPrice', 'sl_trigger_price')
5009
5009
  takeProfitTriggerPrice = self.safe_number_2(params, 'takeProfitPrice', 'tp_trigger_price')
5010
5010
  trailingPercent = self.safe_string_2(params, 'trailingPercent', 'callback_rate')
5011
5011
  trailingTriggerPrice = self.safe_number(params, 'trailingTriggerPrice', price)
5012
5012
  isTrailingPercentOrder = trailingPercent is not None
5013
- isStop = triggerPrice is not None
5013
+ isTrigger = triggerPrice is not None
5014
5014
  isStopLossTriggerOrder = stopLossTriggerPrice is not None
5015
5015
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
5016
- if isStop:
5016
+ if isTrigger:
5017
5017
  triggerType = self.safe_string_2(params, 'triggerType', 'trigger_type', 'le')
5018
5018
  request['trigger_type'] = triggerType
5019
5019
  request['trigger_price'] = self.price_to_precision(symbol, triggerPrice)
@@ -5052,7 +5052,7 @@ class htx(Exchange, ImplicitAPI):
5052
5052
  broker = self.safe_value(self.options, 'broker', {})
5053
5053
  brokerId = self.safe_string(broker, 'id')
5054
5054
  request['channel_code'] = brokerId
5055
- params = self.omit(params, ['reduceOnly', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'triggerType', 'leverRate', 'timeInForce', 'leverage', 'trailingPercent', 'trailingTriggerPrice'])
5055
+ params = self.omit(params, ['reduceOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'triggerType', 'leverRate', 'timeInForce', 'leverage', 'trailingPercent', 'trailingTriggerPrice'])
5056
5056
  return self.extend(request, params)
5057
5057
 
5058
5058
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
@@ -5073,7 +5073,7 @@ class htx(Exchange, ImplicitAPI):
5073
5073
  :param float amount: how much you want to trade in units of the base currency
5074
5074
  :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
5075
5075
  :param dict [params]: extra parameters specific to the exchange API endpoint
5076
- :param float [params.stopPrice]: the price a trigger order is triggered at
5076
+ :param float [params.triggerPrice]: the price a trigger order is triggered at
5077
5077
  :param str [params.triggerType]: *contract trigger orders only* ge: greater than or equal to, le: less than or equal to
5078
5078
  :param float [params.stopLossPrice]: *contract only* the price a stop-loss order is triggered at
5079
5079
  :param float [params.takeProfitPrice]: *contract only* the price a take-profit order is triggered at
@@ -5089,12 +5089,12 @@ class htx(Exchange, ImplicitAPI):
5089
5089
  """
5090
5090
  await self.load_markets()
5091
5091
  market = self.market(symbol)
5092
- triggerPrice = self.safe_number_2(params, 'stopPrice', 'trigger_price')
5092
+ triggerPrice = self.safe_number_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
5093
5093
  stopLossTriggerPrice = self.safe_number_2(params, 'stopLossPrice', 'sl_trigger_price')
5094
5094
  takeProfitTriggerPrice = self.safe_number_2(params, 'takeProfitPrice', 'tp_trigger_price')
5095
5095
  trailingPercent = self.safe_number(params, 'trailingPercent')
5096
5096
  isTrailingPercentOrder = trailingPercent is not None
5097
- isStop = triggerPrice is not None
5097
+ isTrigger = triggerPrice is not None
5098
5098
  isStopLossTriggerOrder = stopLossTriggerPrice is not None
5099
5099
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
5100
5100
  response = None
@@ -5110,7 +5110,7 @@ class htx(Exchange, ImplicitAPI):
5110
5110
  marginMode, contractRequest = self.handle_margin_mode_and_params('createOrder', contractRequest)
5111
5111
  marginMode = 'cross' if (marginMode is None) else marginMode
5112
5112
  if marginMode == 'isolated':
5113
- if isStop:
5113
+ if isTrigger:
5114
5114
  response = await self.contractPrivatePostLinearSwapApiV1SwapTriggerOrder(contractRequest)
5115
5115
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
5116
5116
  response = await self.contractPrivatePostLinearSwapApiV1SwapTpslOrder(contractRequest)
@@ -5119,7 +5119,7 @@ class htx(Exchange, ImplicitAPI):
5119
5119
  else:
5120
5120
  response = await self.contractPrivatePostLinearSwapApiV1SwapOrder(contractRequest)
5121
5121
  elif marginMode == 'cross':
5122
- if isStop:
5122
+ if isTrigger:
5123
5123
  response = await self.contractPrivatePostLinearSwapApiV1SwapCrossTriggerOrder(contractRequest)
5124
5124
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
5125
5125
  response = await self.contractPrivatePostLinearSwapApiV1SwapCrossTpslOrder(contractRequest)
@@ -5132,7 +5132,7 @@ class htx(Exchange, ImplicitAPI):
5132
5132
  if offset is None:
5133
5133
  raise ArgumentsRequired(self.id + ' createOrder() requires an extra parameter params["offset"] to be set to "open" or "close" when placing orders in inverse markets')
5134
5134
  if market['swap']:
5135
- if isStop:
5135
+ if isTrigger:
5136
5136
  response = await self.contractPrivatePostSwapApiV1SwapTriggerOrder(contractRequest)
5137
5137
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
5138
5138
  response = await self.contractPrivatePostSwapApiV1SwapTpslOrder(contractRequest)
@@ -5141,7 +5141,7 @@ class htx(Exchange, ImplicitAPI):
5141
5141
  else:
5142
5142
  response = await self.contractPrivatePostSwapApiV1SwapOrder(contractRequest)
5143
5143
  elif market['future']:
5144
- if isStop:
5144
+ if isTrigger:
5145
5145
  response = await self.contractPrivatePostApiV1ContractTriggerOrder(contractRequest)
5146
5146
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
5147
5147
  response = await self.contractPrivatePostApiV1ContractTpslOrder(contractRequest)
@@ -2139,7 +2139,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2139
2139
  'notional': self.safe_number(entry, 'positionValue'),
2140
2140
  'leverage': self.safe_number(leverage, 'value'),
2141
2141
  'collateral': self.safe_number(entry, 'marginUsed'),
2142
- 'initialMargin': initialMargin,
2142
+ 'initialMargin': self.parse_number(initialMargin),
2143
2143
  'maintenanceMargin': None,
2144
2144
  'initialMarginPercentage': None,
2145
2145
  'maintenanceMarginPercentage': None,
@@ -223,6 +223,7 @@ class kucoin(Exchange, ImplicitAPI):
223
223
  'market/orderbook/level{level}': 3, # 3SW
224
224
  'market/orderbook/level2': 3, # 3SW
225
225
  'market/orderbook/level3': 3, # 3SW
226
+ 'hf/accounts/opened': 2, #
226
227
  'hf/orders/active': 2, # 2SW
227
228
  'hf/orders/active/symbols': 2, # 2SW
228
229
  'hf/margin/order/active/symbols': 2, # 2SW
@@ -652,7 +653,7 @@ class kucoin(Exchange, ImplicitAPI):
652
653
  'FUD': 'FTX Users\' Debt',
653
654
  },
654
655
  'options': {
655
- 'hf': False,
656
+ 'hf': None, # would be auto set to `true/false` after first load
656
657
  'version': 'v1',
657
658
  'symbolSeparator': '-',
658
659
  'fetchMyTradesMethod': 'private_get_fills',
@@ -1084,7 +1085,8 @@ class kucoin(Exchange, ImplicitAPI):
1084
1085
  # "enableTrading": True
1085
1086
  # },
1086
1087
  #
1087
- requestMarginables = self.check_required_credentials(False)
1088
+ credentialsSet = self.check_required_credentials(False)
1089
+ requestMarginables = credentialsSet and self.safe_bool(params, 'marginables', True)
1088
1090
  if requestMarginables:
1089
1091
  promises.append(self.privateGetMarginSymbols(params)) # cross margin symbols
1090
1092
  #
@@ -1147,6 +1149,9 @@ class kucoin(Exchange, ImplicitAPI):
1147
1149
  # "makerCoefficient": "1" # Maker Fee Coefficient
1148
1150
  # }
1149
1151
  #
1152
+ if credentialsSet:
1153
+ # load migration status for account
1154
+ promises.append(self.load_migration_status())
1150
1155
  responses = await asyncio.gather(*promises)
1151
1156
  symbolsData = self.safe_list(responses[0], 'data')
1152
1157
  crossData = self.safe_dict(responses[1], 'data', {}) if requestMarginables else {}
@@ -1233,14 +1238,16 @@ class kucoin(Exchange, ImplicitAPI):
1233
1238
  return result
1234
1239
 
1235
1240
  async def load_migration_status(self, force: bool = False):
1236
- if not ('hfMigrated' in self.options) or (self.options['hfMigrated'] is None) or force:
1237
- result: dict = await self.privateGetMigrateUserAccountStatus()
1238
- data: dict = self.safe_dict(result, 'data', {})
1239
- status: Int = self.safe_integer(data, 'status')
1240
- self.options['hfMigrated'] = (status == 2)
1241
+ """
1242
+ loads the migration status for the account(hf or not)
1243
+ :see: https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/get-user-type
1244
+ """
1245
+ if not ('hf' in self.options) or (self.options['hf'] is None) or force:
1246
+ result: dict = await self.privateGetHfAccountsOpened()
1247
+ self.options['hf'] = self.safe_bool(result, 'data')
1241
1248
 
1242
1249
  def handle_hf_and_params(self, params={}):
1243
- migrated: Bool = self.safe_bool_2(self.options, 'hfMigrated', 'hf', False)
1250
+ migrated: Bool = self.safe_bool(self.options, 'hf', False)
1244
1251
  loadedHf: Bool = None
1245
1252
  if migrated is not None:
1246
1253
  if migrated:
@@ -133,7 +133,7 @@ class woofipro(Exchange, ImplicitAPI):
133
133
  '1y': '1y',
134
134
  },
135
135
  'urls': {
136
- 'logo': 'https://github.com/ccxt/ccxt/assets/43336371/b1e7b348-a0fc-4605-8b7f-91176958fd69',
136
+ 'logo': 'https://github.com/user-attachments/assets/9ba21b8a-a9c7-4770-b7f1-ce3bcbde68c1',
137
137
  'api': {
138
138
  'public': 'https://api-evm.orderly.org',
139
139
  'private': 'https://api-evm.orderly.org',
ccxt/async_support/xt.py CHANGED
@@ -1699,6 +1699,9 @@ class xt(Exchange, ImplicitAPI):
1699
1699
  market = self.safe_market(marketId, market, '_', marketType)
1700
1700
  symbol = market['symbol']
1701
1701
  timestamp = self.safe_integer(ticker, 't')
1702
+ percentage = self.safe_string_2(ticker, 'cr', 'r')
1703
+ if percentage is not None:
1704
+ percentage = Precise.string_mul(percentage, '100')
1702
1705
  return self.safe_ticker({
1703
1706
  'symbol': symbol,
1704
1707
  'timestamp': timestamp,
@@ -1715,7 +1718,7 @@ class xt(Exchange, ImplicitAPI):
1715
1718
  'last': self.safe_string(ticker, 'c'),
1716
1719
  'previousClose': None,
1717
1720
  'change': self.safe_number(ticker, 'cv'),
1718
- 'percentage': self.safe_number_2(ticker, 'cr', 'r'),
1721
+ 'percentage': self.parse_number(percentage),
1719
1722
  'average': None,
1720
1723
  'baseVolume': None,
1721
1724
  'quoteVolume': self.safe_number_2(ticker, 'a', 'v'),
@@ -1125,7 +1125,7 @@ class yobit(Exchange, ImplicitAPI):
1125
1125
  ids = list(trades.keys())
1126
1126
  result = []
1127
1127
  for i in range(0, len(ids)):
1128
- id = ids[i]
1128
+ id = self.safe_string(ids, i)
1129
1129
  trade = self.parse_trade(self.extend(trades[id], {
1130
1130
  'trade_id': id,
1131
1131
  }), market)
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.23'
7
+ __version__ = '4.4.25'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -3001,9 +3001,10 @@ class Exchange(object):
3001
3001
  isTriggerOrSLTpOrder = ((self.safe_string(order, 'triggerPrice') is not None or (self.safe_string(order, 'stopLossPrice') is not None)) or (self.safe_string(order, 'takeProfitPrice') is not None))
3002
3002
  if parseFilled or parseCost or shouldParseFees:
3003
3003
  rawTrades = self.safe_value(order, 'trades', trades)
3004
- oldNumber = self.number
3004
+ # oldNumber = self.number
3005
3005
  # we parse trades here!
3006
- self.number = str
3006
+ # i don't think self is needed anymore
3007
+ # self.number = str
3007
3008
  firstTrade = self.safe_value(rawTrades, 0)
3008
3009
  # parse trades if they haven't already been parsed
3009
3010
  tradesAreParsed = ((firstTrade is not None) and ('info' in firstTrade) and ('id' in firstTrade))
@@ -3011,7 +3012,7 @@ class Exchange(object):
3011
3012
  trades = self.parse_trades(rawTrades, market)
3012
3013
  else:
3013
3014
  trades = rawTrades
3014
- self.number = oldNumber
3015
+ # self.number = oldNumber; why parse trades if you read the value using `safeString` ?
3015
3016
  tradesLength = 0
3016
3017
  isArray = isinstance(trades, list)
3017
3018
  if isArray:
ccxt/binance.py CHANGED
@@ -1117,7 +1117,7 @@ class binance(Exchange, ImplicitAPI):
1117
1117
  'cm/adlQuantile': 5,
1118
1118
  'um/trade/asyn': 300,
1119
1119
  'um/trade/asyn/id': 2,
1120
- 'um/order/asyn/': 300,
1120
+ 'um/order/asyn': 300,
1121
1121
  'um/order/asyn/id': 2,
1122
1122
  'um/income/asyn': 300,
1123
1123
  'um/income/asyn/id': 2,
ccxt/bitmex.py CHANGED
@@ -1108,17 +1108,18 @@ class bitmex(Exchange, ImplicitAPI):
1108
1108
  # set the timestamp to zero, 1970 Jan 1 00:00:00
1109
1109
  # for unrealized pnl and other transactions without a timestamp
1110
1110
  timestamp = 0 # see comments above
1111
+ fee = None
1111
1112
  feeCost = self.safe_string(item, 'fee')
1112
1113
  if feeCost is not None:
1113
1114
  feeCost = self.convert_to_real_amount(code, feeCost)
1114
- fee = {
1115
- 'cost': self.parse_to_numeric(feeCost),
1116
- 'currency': code,
1117
- }
1115
+ fee = {
1116
+ 'cost': self.parse_number(feeCost),
1117
+ 'currency': code,
1118
+ }
1118
1119
  after = self.safe_string(item, 'walletBalance')
1119
1120
  if after is not None:
1120
1121
  after = self.convert_to_real_amount(code, after)
1121
- before = self.parse_to_numeric(Precise.string_sub(self.number_to_string(after), self.number_to_string(amount)))
1122
+ before = self.parse_number(Precise.string_sub(self.number_to_string(after), self.number_to_string(amount)))
1122
1123
  direction = None
1123
1124
  if Precise.string_lt(amountString, '0'):
1124
1125
  direction = 'out'
@@ -1137,9 +1138,9 @@ class bitmex(Exchange, ImplicitAPI):
1137
1138
  'referenceAccount': referenceAccount,
1138
1139
  'type': type,
1139
1140
  'currency': code,
1140
- 'amount': self.parse_to_numeric(amount),
1141
+ 'amount': self.parse_number(amount),
1141
1142
  'before': before,
1142
- 'after': self.parse_to_numeric(after),
1143
+ 'after': self.parse_number(after),
1143
1144
  'status': status,
1144
1145
  'fee': fee,
1145
1146
  }, currency)
ccxt/bybit.py CHANGED
@@ -1026,6 +1026,7 @@ class bybit(Exchange, ImplicitAPI):
1026
1026
  },
1027
1027
  'enableUnifiedMargin': None,
1028
1028
  'enableUnifiedAccount': None,
1029
+ 'unifiedMarginStatus': None,
1029
1030
  'createMarketBuyOrderRequiresPrice': True, # only True for classic accounts
1030
1031
  'createUnifiedMarginAccount': False,
1031
1032
  'defaultType': 'swap', # 'swap', 'future', 'option', 'spot'
@@ -1145,6 +1146,8 @@ class bybit(Exchange, ImplicitAPI):
1145
1146
 
1146
1147
  def is_unified_enabled(self, params={}):
1147
1148
  """
1149
+ :see: https://bybit-exchange.github.io/docs/v5/user/apikey-info#http-request
1150
+ :see: https://bybit-exchange.github.io/docs/v5/account/account-info
1148
1151
  returns [enableUnifiedMargin, enableUnifiedAccount] so the user can check if unified account is enabled
1149
1152
  """
1150
1153
  # The API key of user id must own one of permissions will be allowed to call following API endpoints.
@@ -1158,8 +1161,12 @@ class bybit(Exchange, ImplicitAPI):
1158
1161
  # so we're assuming UTA is enabled
1159
1162
  self.options['enableUnifiedMargin'] = False
1160
1163
  self.options['enableUnifiedAccount'] = True
1164
+ self.options['unifiedMarginStatus'] = 3
1161
1165
  return [self.options['enableUnifiedMargin'], self.options['enableUnifiedAccount']]
1162
- response = self.privateGetV5UserQueryApi(params)
1166
+ rawPromises = [self.privateGetV5UserQueryApi(params), self.privateGetV5AccountInfo(params)]
1167
+ promises = rawPromises
1168
+ response = promises[0]
1169
+ accountInfo = promises[1]
1163
1170
  #
1164
1171
  # {
1165
1172
  # "retCode": 0,
@@ -1199,13 +1206,34 @@ class bybit(Exchange, ImplicitAPI):
1199
1206
  # "retExtInfo": {},
1200
1207
  # "time": 1676891757649
1201
1208
  # }
1209
+ # account info
1210
+ # {
1211
+ # "retCode": 0,
1212
+ # "retMsg": "OK",
1213
+ # "result": {
1214
+ # "marginMode": "REGULAR_MARGIN",
1215
+ # "updatedTime": "1697078946000",
1216
+ # "unifiedMarginStatus": 4,
1217
+ # "dcpStatus": "OFF",
1218
+ # "timeWindow": 10,
1219
+ # "smpGroup": 0,
1220
+ # "isMasterTrader": False,
1221
+ # "spotHedgingStatus": "OFF"
1222
+ # }
1223
+ # }
1202
1224
  #
1203
1225
  result = self.safe_dict(response, 'result', {})
1226
+ accountResult = self.safe_dict(accountInfo, 'result', {})
1204
1227
  self.options['enableUnifiedMargin'] = self.safe_integer(result, 'unified') == 1
1205
1228
  self.options['enableUnifiedAccount'] = self.safe_integer(result, 'uta') == 1
1229
+ self.options['unifiedMarginStatus'] = self.safe_integer(accountResult, 'unifiedMarginStatus', 3) # default to uta.1 if not found
1206
1230
  return [self.options['enableUnifiedMargin'], self.options['enableUnifiedAccount']]
1207
1231
 
1208
1232
  def upgrade_unified_trade_account(self, params={}):
1233
+ """
1234
+ :see: https://bybit-exchange.github.io/docs/v5/account/upgrade-unified-account
1235
+ upgrades the account to unified trade account *warning* self is irreversible
1236
+ """
1209
1237
  return self.privatePostV5AccountUpgradeToUta(params)
1210
1238
 
1211
1239
  def create_expired_option_market(self, symbol: str):
@@ -3018,10 +3046,15 @@ class bybit(Exchange, ImplicitAPI):
3018
3046
  isInverse = (type == 'inverse')
3019
3047
  isFunding = (lowercaseRawType == 'fund') or (lowercaseRawType == 'funding')
3020
3048
  if isUnifiedAccount:
3021
- if isInverse:
3022
- type = 'contract'
3049
+ unifiedMarginStatus = self.safe_integer(self.options, 'unifiedMarginStatus', 3)
3050
+ if unifiedMarginStatus < 5:
3051
+ # it's not uta.20 where inverse are unified
3052
+ if isInverse:
3053
+ type = 'contract'
3054
+ else:
3055
+ type = 'unified'
3023
3056
  else:
3024
- type = 'unified'
3057
+ type = 'unified' # uta.20 where inverse are unified
3025
3058
  else:
3026
3059
  if isLinear or isInverse:
3027
3060
  type = 'contract'
ccxt/coincatch.py CHANGED
@@ -154,7 +154,7 @@ class coincatch(Exchange, ImplicitAPI):
154
154
  '1M': '1M',
155
155
  },
156
156
  'urls': {
157
- 'logo': 'https://private-user-images.githubusercontent.com/43336371/379178446-b99d8af1-3016-4775-ac37-d5016dccb000.jpeg?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mjk2NzMxOTksIm5iZiI6MTcyOTY3Mjg5OSwicGF0aCI6Ii80MzMzNjM3MS8zNzkxNzg0NDYtYjk5ZDhhZjEtMzAxNi00Nzc1LWFjMzctZDUwMTZkY2NiMDAwLmpwZWc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjQxMDIzJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI0MTAyM1QwODQxMzlaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0xMTkzNTAzYjhlYzg5ODU4ZjFhYzgwZTg3MGFmYjk5MWViMjMwNDY5ZGU4NDRlNGU0NmUxYTgxMzM3OTNlZWM4JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.tosowLHE9p_cKbY8dPPduHXFVJQrUZ8qzGBOTCCznvw',
157
+ 'logo': 'https://github.com/user-attachments/assets/3d49065f-f05d-4573-88a2-1b5201ec6ff3',
158
158
  'api': {
159
159
  'public': 'https://api.coincatch.com',
160
160
  'private': 'https://api.coincatch.com',
ccxt/coinex.py CHANGED
@@ -473,9 +473,43 @@ class coinex(Exchange, ImplicitAPI):
473
473
  'FUTURES': 'swap',
474
474
  },
475
475
  'networks': {
476
+ 'BTC': 'BTC',
476
477
  'BEP20': 'BSC',
477
- 'TRX': 'TRC20',
478
- 'ETH': 'ERC20',
478
+ 'TRC20': 'TRC20',
479
+ 'ERC20': 'ERC20',
480
+ 'BRC20': 'BRC20',
481
+ 'SOL': 'SOL',
482
+ 'TON': 'SOL',
483
+ 'BSV': 'BSV',
484
+ 'AVAXC': 'AVA_C',
485
+ 'AVAXX': 'AVA',
486
+ 'SUI': 'SUI',
487
+ 'ACA': 'ACA',
488
+ 'CHZ': 'CHILIZ',
489
+ 'ADA': 'ADA',
490
+ 'ARB': 'ARBITRUM',
491
+ 'ARBNOVA': 'ARBITRUM_NOVA',
492
+ 'OP': 'OPTIMISM',
493
+ 'APT': 'APTOS',
494
+ 'ATOM': 'ATOM',
495
+ 'FTM': 'FTM',
496
+ 'BCH': 'BCH',
497
+ 'ASTR': 'ASTR',
498
+ 'LTC': 'LTC',
499
+ 'MATIC': 'MATIC',
500
+ 'CRONOS': 'CRONOS',
501
+ 'DASH': 'DASH',
502
+ 'DOT': 'DOT',
503
+ 'ETC': 'ETC',
504
+ 'ETHW': 'ETHPOW',
505
+ 'FIL': 'FIL',
506
+ 'ZIL': 'ZIL',
507
+ 'DOGE': 'DOGE',
508
+ 'TIA': 'CELESTIA',
509
+ 'SEI': 'SEI',
510
+ 'XRP': 'XRP',
511
+ 'XMR': 'XMR',
512
+ # CSC, AE, BASE, AIPG, AKASH, POLKADOTASSETHUB ?, ALEO, STX, ALGO, ALPH, BLAST, AR, ARCH, ARDR, ARK, ARRR, MANTA, NTRN, LUNA, AURORA, AVAIL, ASC20, AVA, AYA, AZERO, BAN, BAND, BB, RUNES, BEAM, BELLSCOIN, BITCI, NEAR, AGORIC, BLOCX, BNC, BOBA, BRISE, KRC20, CANTO, CAPS, CCD, CELO, CFX, CHI, CKB, CLORE, CLV, CORE, CSPR, CTXC, DAG, DCR, DERO, DESO, DEFI, DGB, DNX, DOCK, DOGECHAIN, DYDX, DYMENSION, EGLD, ELA, ELF, ENJIN, EOSIO, ERG, ETN_SC, EVMOS, EWC, SGB, FACT, FB, FET, FIO, FIRO, NEO3, FLOW, FLARE, FLUX, LINEA, FREN, FSN, FB_BRC20, GLMR, GRIN, GRS, HACASH, HBAR, HERB, HIVE, MAPO, HMND, HNS, ZKSYNC, HTR, HUAHUA, MERLIN, ICP, ICX, INJ, IOST, IOTA, IOTX, IRIS, IRON, ONE, JOYSTREAM, KAI, KAR, KAS, KAVA, KCN, KDA, KLAY, KLY, KMD, KSM, KUB, KUJIRA, LAT, LBC, LUNC, LUKSO, MARS, METIS, MINA, MANTLE, MOB, MODE, MONA, MOVR, MTL, NEOX, NEXA, NIBI, NIMIQ, NMC, ONOMY, NRG, WAVES, NULS, OAS, OCTA, OLT, ONT, OORT, ORAI, OSMO, P3D, COMPOSABLE, PIVX, RON, POKT, POLYMESH, PRE_MARKET, PYI, QKC, QTUM, QUBIC, RSK, ROSE, ROUTE, RTM, THORCHAIN, RVN, RADIANT, SAGA, SALVIUM, SATOX, SC, SCP, _NULL, SCRT, SDN, RGBPP, SELF, SMH, SPACE, STARGAZE, STC, STEEM, STRATISEVM, STRD, STARKNET, SXP, SYS, TAIKO, TAO, TARA, TENET, THETA, TT, VENOM, VECHAIN, TOMO, VITE, VLX, VSYS, VTC, WAN, WAXP, WEMIX, XCH, XDC, XEC, XELIS, NEM, XHV, XLM, XNA, NANO, XPLA, XPR, XPRT, XRD, XTZ, XVG, XYM, ZANO, ZEC, ZEN, ZEPH, ZETA
479
513
  },
480
514
  },
481
515
  'commonCurrencies': {
@@ -3546,20 +3580,14 @@ class coinex(Exchange, ImplicitAPI):
3546
3580
  """
3547
3581
  self.load_markets()
3548
3582
  currency = self.currency(code)
3549
- networks = self.safe_dict(currency, 'networks', {})
3550
- network = self.safe_string_2(params, 'network', 'chain')
3551
- params = self.omit(params, 'network')
3552
- networksKeys = list(networks.keys())
3553
- numOfNetworks = len(networksKeys)
3554
- if networks is not None and numOfNetworks > 1:
3555
- if network is None:
3556
- raise ArgumentsRequired(self.id + ' fetchDepositAddress() ' + code + ' requires a network parameter')
3557
- if not (network in networks):
3558
- raise ExchangeError(self.id + ' fetchDepositAddress() ' + network + ' network not supported for ' + code)
3559
3583
  request: dict = {
3560
3584
  'ccy': currency['id'],
3561
- 'chain': network,
3562
3585
  }
3586
+ networkCode = None
3587
+ networkCode, params = self.handle_network_code_and_params(params)
3588
+ if networkCode is None:
3589
+ raise ArgumentsRequired(self.id + ' fetchDepositAddress() requires a "network" parameter')
3590
+ request['chain'] = self.network_code_to_id(networkCode) # required for on-chain, not required for inter-user transfer
3563
3591
  response = self.v2PrivateGetAssetsDepositAddress(self.extend(request, params))
3564
3592
  #
3565
3593
  # {
@@ -3572,12 +3600,7 @@ class coinex(Exchange, ImplicitAPI):
3572
3600
  # }
3573
3601
  #
3574
3602
  data = self.safe_dict(response, 'data', {})
3575
- depositAddress = self.parse_deposit_address(data, currency)
3576
- options = self.safe_dict(self.options, 'fetchDepositAddress', {})
3577
- fillResponseFromRequest = self.safe_bool(options, 'fillResponseFromRequest', True)
3578
- if fillResponseFromRequest:
3579
- depositAddress['network'] = self.network_id_to_code(network, currency).upper()
3580
- return depositAddress
3603
+ return self.parse_deposit_address(data, currency)
3581
3604
 
3582
3605
  def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
3583
3606
  #
@@ -4417,8 +4440,6 @@ class coinex(Exchange, ImplicitAPI):
4417
4440
  self.check_address(address)
4418
4441
  self.load_markets()
4419
4442
  currency = self.currency(code)
4420
- networkCode = self.safe_string_upper_2(params, 'network', 'chain')
4421
- params = self.omit(params, 'network')
4422
4443
  if tag:
4423
4444
  address = address + ':' + tag
4424
4445
  request: dict = {
@@ -4426,6 +4447,8 @@ class coinex(Exchange, ImplicitAPI):
4426
4447
  'to_address': address, # must be authorized, inter-user transfer by a registered mobile phone number or an email address is supported
4427
4448
  'amount': self.number_to_string(amount), # the actual amount without fees, https://www.coinex.com/fees
4428
4449
  }
4450
+ networkCode = None
4451
+ networkCode, params = self.handle_network_code_and_params(params)
4429
4452
  if networkCode is not None:
4430
4453
  request['chain'] = self.network_code_to_id(networkCode) # required for on-chain, not required for inter-user transfer
4431
4454
  response = self.v2PrivatePostAssetsWithdraw(self.extend(request, params))
@@ -4462,6 +4485,7 @@ class coinex(Exchange, ImplicitAPI):
4462
4485
  statuses: dict = {
4463
4486
  'audit': 'pending',
4464
4487
  'pass': 'pending',
4488
+ 'audit_required': 'pending',
4465
4489
  'processing': 'pending',
4466
4490
  'confirming': 'pending',
4467
4491
  'not_pass': 'failed',