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/htx.py CHANGED
@@ -4904,15 +4904,15 @@ class htx(Exchange, ImplicitAPI):
4904
4904
  orderType = type.replace('buy-', '')
4905
4905
  orderType = orderType.replace('sell-', '')
4906
4906
  options = self.safe_value(self.options, market['type'], {})
4907
- stopPrice = self.safe_string_2(params, 'stopPrice', 'stop-price')
4908
- if stopPrice is None:
4907
+ triggerPrice = self.safe_string_n(params, ['triggerPrice', 'stopPrice', 'stop-price'])
4908
+ if triggerPrice is None:
4909
4909
  stopOrderTypes = self.safe_value(options, 'stopOrderTypes', {})
4910
4910
  if orderType in stopOrderTypes:
4911
- raise ArgumentsRequired(self.id + ' createOrder() requires a stopPrice or a stop-price parameter for a stop order')
4911
+ raise ArgumentsRequired(self.id + ' createOrder() requires a triggerPrice for a stop order')
4912
4912
  else:
4913
4913
  defaultOperator = 'lte' if (side == 'sell') else 'gte'
4914
4914
  stopOperator = self.safe_string(params, 'operator', defaultOperator)
4915
- request['stop-price'] = self.price_to_precision(symbol, stopPrice)
4915
+ request['stop-price'] = self.price_to_precision(symbol, triggerPrice)
4916
4916
  request['operator'] = stopOperator
4917
4917
  if (orderType == 'limit') or (orderType == 'limit-fok'):
4918
4918
  orderType = 'stop-' + orderType
@@ -4970,7 +4970,7 @@ class htx(Exchange, ImplicitAPI):
4970
4970
  limitOrderTypes = self.safe_value(options, 'limitOrderTypes', {})
4971
4971
  if orderType in limitOrderTypes:
4972
4972
  request['price'] = self.price_to_precision(symbol, price)
4973
- params = self.omit(params, ['stopPrice', 'stop-price', 'clientOrderId', 'client-order-id', 'operator', 'timeInForce'])
4973
+ params = self.omit(params, ['triggerPrice', 'stopPrice', 'stop-price', 'clientOrderId', 'client-order-id', 'operator', 'timeInForce'])
4974
4974
  return self.extend(request, params)
4975
4975
 
4976
4976
  def create_contract_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
@@ -5003,16 +5003,16 @@ class htx(Exchange, ImplicitAPI):
5003
5003
  type = 'fok'
5004
5004
  elif timeInForce == 'IOC':
5005
5005
  type = 'ioc'
5006
- triggerPrice = self.safe_number_2(params, 'stopPrice', 'trigger_price')
5006
+ triggerPrice = self.safe_number_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
5007
5007
  stopLossTriggerPrice = self.safe_number_2(params, 'stopLossPrice', 'sl_trigger_price')
5008
5008
  takeProfitTriggerPrice = self.safe_number_2(params, 'takeProfitPrice', 'tp_trigger_price')
5009
5009
  trailingPercent = self.safe_string_2(params, 'trailingPercent', 'callback_rate')
5010
5010
  trailingTriggerPrice = self.safe_number(params, 'trailingTriggerPrice', price)
5011
5011
  isTrailingPercentOrder = trailingPercent is not None
5012
- isStop = triggerPrice is not None
5012
+ isTrigger = triggerPrice is not None
5013
5013
  isStopLossTriggerOrder = stopLossTriggerPrice is not None
5014
5014
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
5015
- if isStop:
5015
+ if isTrigger:
5016
5016
  triggerType = self.safe_string_2(params, 'triggerType', 'trigger_type', 'le')
5017
5017
  request['trigger_type'] = triggerType
5018
5018
  request['trigger_price'] = self.price_to_precision(symbol, triggerPrice)
@@ -5051,7 +5051,7 @@ class htx(Exchange, ImplicitAPI):
5051
5051
  broker = self.safe_value(self.options, 'broker', {})
5052
5052
  brokerId = self.safe_string(broker, 'id')
5053
5053
  request['channel_code'] = brokerId
5054
- params = self.omit(params, ['reduceOnly', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'triggerType', 'leverRate', 'timeInForce', 'leverage', 'trailingPercent', 'trailingTriggerPrice'])
5054
+ params = self.omit(params, ['reduceOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'triggerType', 'leverRate', 'timeInForce', 'leverage', 'trailingPercent', 'trailingTriggerPrice'])
5055
5055
  return self.extend(request, params)
5056
5056
 
5057
5057
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
@@ -5072,7 +5072,7 @@ class htx(Exchange, ImplicitAPI):
5072
5072
  :param float amount: how much you want to trade in units of the base currency
5073
5073
  :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
5074
5074
  :param dict [params]: extra parameters specific to the exchange API endpoint
5075
- :param float [params.stopPrice]: the price a trigger order is triggered at
5075
+ :param float [params.triggerPrice]: the price a trigger order is triggered at
5076
5076
  :param str [params.triggerType]: *contract trigger orders only* ge: greater than or equal to, le: less than or equal to
5077
5077
  :param float [params.stopLossPrice]: *contract only* the price a stop-loss order is triggered at
5078
5078
  :param float [params.takeProfitPrice]: *contract only* the price a take-profit order is triggered at
@@ -5088,12 +5088,12 @@ class htx(Exchange, ImplicitAPI):
5088
5088
  """
5089
5089
  self.load_markets()
5090
5090
  market = self.market(symbol)
5091
- triggerPrice = self.safe_number_2(params, 'stopPrice', 'trigger_price')
5091
+ triggerPrice = self.safe_number_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
5092
5092
  stopLossTriggerPrice = self.safe_number_2(params, 'stopLossPrice', 'sl_trigger_price')
5093
5093
  takeProfitTriggerPrice = self.safe_number_2(params, 'takeProfitPrice', 'tp_trigger_price')
5094
5094
  trailingPercent = self.safe_number(params, 'trailingPercent')
5095
5095
  isTrailingPercentOrder = trailingPercent is not None
5096
- isStop = triggerPrice is not None
5096
+ isTrigger = triggerPrice is not None
5097
5097
  isStopLossTriggerOrder = stopLossTriggerPrice is not None
5098
5098
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
5099
5099
  response = None
@@ -5109,7 +5109,7 @@ class htx(Exchange, ImplicitAPI):
5109
5109
  marginMode, contractRequest = self.handle_margin_mode_and_params('createOrder', contractRequest)
5110
5110
  marginMode = 'cross' if (marginMode is None) else marginMode
5111
5111
  if marginMode == 'isolated':
5112
- if isStop:
5112
+ if isTrigger:
5113
5113
  response = self.contractPrivatePostLinearSwapApiV1SwapTriggerOrder(contractRequest)
5114
5114
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
5115
5115
  response = self.contractPrivatePostLinearSwapApiV1SwapTpslOrder(contractRequest)
@@ -5118,7 +5118,7 @@ class htx(Exchange, ImplicitAPI):
5118
5118
  else:
5119
5119
  response = self.contractPrivatePostLinearSwapApiV1SwapOrder(contractRequest)
5120
5120
  elif marginMode == 'cross':
5121
- if isStop:
5121
+ if isTrigger:
5122
5122
  response = self.contractPrivatePostLinearSwapApiV1SwapCrossTriggerOrder(contractRequest)
5123
5123
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
5124
5124
  response = self.contractPrivatePostLinearSwapApiV1SwapCrossTpslOrder(contractRequest)
@@ -5131,7 +5131,7 @@ class htx(Exchange, ImplicitAPI):
5131
5131
  if offset is None:
5132
5132
  raise ArgumentsRequired(self.id + ' createOrder() requires an extra parameter params["offset"] to be set to "open" or "close" when placing orders in inverse markets')
5133
5133
  if market['swap']:
5134
- if isStop:
5134
+ if isTrigger:
5135
5135
  response = self.contractPrivatePostSwapApiV1SwapTriggerOrder(contractRequest)
5136
5136
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
5137
5137
  response = self.contractPrivatePostSwapApiV1SwapTpslOrder(contractRequest)
@@ -5140,7 +5140,7 @@ class htx(Exchange, ImplicitAPI):
5140
5140
  else:
5141
5141
  response = self.contractPrivatePostSwapApiV1SwapOrder(contractRequest)
5142
5142
  elif market['future']:
5143
- if isStop:
5143
+ if isTrigger:
5144
5144
  response = self.contractPrivatePostApiV1ContractTriggerOrder(contractRequest)
5145
5145
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
5146
5146
  response = self.contractPrivatePostApiV1ContractTpslOrder(contractRequest)
ccxt/hyperliquid.py CHANGED
@@ -2138,7 +2138,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2138
2138
  'notional': self.safe_number(entry, 'positionValue'),
2139
2139
  'leverage': self.safe_number(leverage, 'value'),
2140
2140
  'collateral': self.safe_number(entry, 'marginUsed'),
2141
- 'initialMargin': initialMargin,
2141
+ 'initialMargin': self.parse_number(initialMargin),
2142
2142
  'maintenanceMargin': None,
2143
2143
  'initialMarginPercentage': None,
2144
2144
  'maintenanceMarginPercentage': None,
ccxt/kucoin.py CHANGED
@@ -222,6 +222,7 @@ class kucoin(Exchange, ImplicitAPI):
222
222
  'market/orderbook/level{level}': 3, # 3SW
223
223
  'market/orderbook/level2': 3, # 3SW
224
224
  'market/orderbook/level3': 3, # 3SW
225
+ 'hf/accounts/opened': 2, #
225
226
  'hf/orders/active': 2, # 2SW
226
227
  'hf/orders/active/symbols': 2, # 2SW
227
228
  'hf/margin/order/active/symbols': 2, # 2SW
@@ -651,7 +652,7 @@ class kucoin(Exchange, ImplicitAPI):
651
652
  'FUD': 'FTX Users\' Debt',
652
653
  },
653
654
  'options': {
654
- 'hf': False,
655
+ 'hf': None, # would be auto set to `true/false` after first load
655
656
  'version': 'v1',
656
657
  'symbolSeparator': '-',
657
658
  'fetchMyTradesMethod': 'private_get_fills',
@@ -1083,7 +1084,8 @@ class kucoin(Exchange, ImplicitAPI):
1083
1084
  # "enableTrading": True
1084
1085
  # },
1085
1086
  #
1086
- requestMarginables = self.check_required_credentials(False)
1087
+ credentialsSet = self.check_required_credentials(False)
1088
+ requestMarginables = credentialsSet and self.safe_bool(params, 'marginables', True)
1087
1089
  if requestMarginables:
1088
1090
  promises.append(self.privateGetMarginSymbols(params)) # cross margin symbols
1089
1091
  #
@@ -1146,6 +1148,9 @@ class kucoin(Exchange, ImplicitAPI):
1146
1148
  # "makerCoefficient": "1" # Maker Fee Coefficient
1147
1149
  # }
1148
1150
  #
1151
+ if credentialsSet:
1152
+ # load migration status for account
1153
+ promises.append(self.load_migration_status())
1149
1154
  responses = promises
1150
1155
  symbolsData = self.safe_list(responses[0], 'data')
1151
1156
  crossData = self.safe_dict(responses[1], 'data', {}) if requestMarginables else {}
@@ -1232,14 +1237,16 @@ class kucoin(Exchange, ImplicitAPI):
1232
1237
  return result
1233
1238
 
1234
1239
  def load_migration_status(self, force: bool = False):
1235
- if not ('hfMigrated' in self.options) or (self.options['hfMigrated'] is None) or force:
1236
- result: dict = self.privateGetMigrateUserAccountStatus()
1237
- data: dict = self.safe_dict(result, 'data', {})
1238
- status: Int = self.safe_integer(data, 'status')
1239
- self.options['hfMigrated'] = (status == 2)
1240
+ """
1241
+ loads the migration status for the account(hf or not)
1242
+ :see: https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/get-user-type
1243
+ """
1244
+ if not ('hf' in self.options) or (self.options['hf'] is None) or force:
1245
+ result: dict = self.privateGetHfAccountsOpened()
1246
+ self.options['hf'] = self.safe_bool(result, 'data')
1240
1247
 
1241
1248
  def handle_hf_and_params(self, params={}):
1242
- migrated: Bool = self.safe_bool_2(self.options, 'hfMigrated', 'hf', False)
1249
+ migrated: Bool = self.safe_bool(self.options, 'hf', False)
1243
1250
  loadedHf: Bool = None
1244
1251
  if migrated is not None:
1245
1252
  if migrated:
ccxt/pro/__init__.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
 
ccxt/pro/kucoin.py CHANGED
@@ -1088,7 +1088,8 @@ class kucoin(ccxt.async_support.kucoin):
1088
1088
  self.myTrades = ArrayCacheBySymbolById(limit)
1089
1089
  data = self.safe_dict(message, 'data')
1090
1090
  parsed = self.parse_ws_trade(data)
1091
- self.myTrades.append(parsed)
1091
+ myTrades = self.myTrades
1092
+ myTrades.append(parsed)
1092
1093
  messageHash = 'myTrades'
1093
1094
  client.resolve(self.myTrades, messageHash)
1094
1095
  symbolSpecificMessageHash = messageHash + ':' + parsed['symbol']
ccxt/pro/onetrading.py CHANGED
@@ -965,7 +965,8 @@ class onetrading(ccxt.async_support.onetrading):
965
965
  if updateType == 'TRADE_SETTLED':
966
966
  parsed = self.parse_trade(update)
967
967
  symbol = self.safe_string(parsed, 'symbol', '')
968
- self.myTrades.append(parsed)
968
+ myTrades = self.myTrades
969
+ myTrades.append(parsed)
969
970
  client.resolve(self.myTrades, 'myTrades:' + symbol)
970
971
  client.resolve(self.myTrades, 'myTrades')
971
972
 
ccxt/test/tests_async.py CHANGED
@@ -639,9 +639,10 @@ class testMainClass:
639
639
  # -----------------------------------------------------------------------------
640
640
  calculated_string = json_stringify(calculated_output)
641
641
  stored_string = json_stringify(stored_output)
642
- error_message = message + ' computed ' + stored_string + ' stored: ' + calculated_string
642
+ error_message = message
643
643
  if key is not None:
644
- error_message = ' | ' + key + ' | ' + 'computed value: ' + stored_string + ' stored value: ' + calculated_string
644
+ error_message = '[' + key + ']'
645
+ error_message += ' computed: ' + stored_string + ' stored: ' + calculated_string
645
646
  assert cond, error_message
646
647
 
647
648
  def load_markets_from_file(self, id):
@@ -752,9 +753,17 @@ class testMainClass:
752
753
  # when comparing the response we want to allow some flexibility, because a 50.0 can be equal to 50 after saving it to the json file
753
754
  self.assert_static_error(sanitized_new_output == sanitized_stored_output, message_error, stored_output, new_output, asserting_key)
754
755
  else:
755
- is_boolean = (isinstance(sanitized_new_output, bool)) or (isinstance(sanitized_stored_output, bool))
756
- is_string = (isinstance(sanitized_new_output, str)) or (isinstance(sanitized_stored_output, str))
757
- is_undefined = (sanitized_new_output is None) or (sanitized_stored_output is None) # undefined is a perfetly valid value
756
+ is_computed_bool = (isinstance(sanitized_new_output, bool))
757
+ is_stored_bool = (isinstance(sanitized_stored_output, bool))
758
+ is_computed_string = (isinstance(sanitized_new_output, str))
759
+ is_stored_string = (isinstance(sanitized_stored_output, str))
760
+ is_computed_undefined = (sanitized_new_output is None)
761
+ is_stored_undefined = (sanitized_stored_output is None)
762
+ should_be_same = (is_computed_bool == is_stored_bool) and (is_computed_string == is_stored_string) and (is_computed_undefined == is_stored_undefined)
763
+ self.assert_static_error(should_be_same, 'output type mismatch', stored_output, new_output, asserting_key)
764
+ is_boolean = is_computed_bool or is_stored_bool
765
+ is_string = is_computed_string or is_stored_string
766
+ is_undefined = is_computed_undefined or is_stored_undefined # undefined is a perfetly valid value
758
767
  if is_boolean or is_string or is_undefined:
759
768
  if self.lang == 'C#':
760
769
  # tmp c# number comparsion
ccxt/test/tests_sync.py CHANGED
@@ -636,9 +636,10 @@ class testMainClass:
636
636
  # -----------------------------------------------------------------------------
637
637
  calculated_string = json_stringify(calculated_output)
638
638
  stored_string = json_stringify(stored_output)
639
- error_message = message + ' computed ' + stored_string + ' stored: ' + calculated_string
639
+ error_message = message
640
640
  if key is not None:
641
- error_message = ' | ' + key + ' | ' + 'computed value: ' + stored_string + ' stored value: ' + calculated_string
641
+ error_message = '[' + key + ']'
642
+ error_message += ' computed: ' + stored_string + ' stored: ' + calculated_string
642
643
  assert cond, error_message
643
644
 
644
645
  def load_markets_from_file(self, id):
@@ -749,9 +750,17 @@ class testMainClass:
749
750
  # when comparing the response we want to allow some flexibility, because a 50.0 can be equal to 50 after saving it to the json file
750
751
  self.assert_static_error(sanitized_new_output == sanitized_stored_output, message_error, stored_output, new_output, asserting_key)
751
752
  else:
752
- is_boolean = (isinstance(sanitized_new_output, bool)) or (isinstance(sanitized_stored_output, bool))
753
- is_string = (isinstance(sanitized_new_output, str)) or (isinstance(sanitized_stored_output, str))
754
- is_undefined = (sanitized_new_output is None) or (sanitized_stored_output is None) # undefined is a perfetly valid value
753
+ is_computed_bool = (isinstance(sanitized_new_output, bool))
754
+ is_stored_bool = (isinstance(sanitized_stored_output, bool))
755
+ is_computed_string = (isinstance(sanitized_new_output, str))
756
+ is_stored_string = (isinstance(sanitized_stored_output, str))
757
+ is_computed_undefined = (sanitized_new_output is None)
758
+ is_stored_undefined = (sanitized_stored_output is None)
759
+ should_be_same = (is_computed_bool == is_stored_bool) and (is_computed_string == is_stored_string) and (is_computed_undefined == is_stored_undefined)
760
+ self.assert_static_error(should_be_same, 'output type mismatch', stored_output, new_output, asserting_key)
761
+ is_boolean = is_computed_bool or is_stored_bool
762
+ is_string = is_computed_string or is_stored_string
763
+ is_undefined = is_computed_undefined or is_stored_undefined # undefined is a perfetly valid value
755
764
  if is_boolean or is_string or is_undefined:
756
765
  if self.lang == 'C#':
757
766
  # tmp c# number comparsion
ccxt/woofipro.py CHANGED
@@ -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/xt.py CHANGED
@@ -1698,6 +1698,9 @@ class xt(Exchange, ImplicitAPI):
1698
1698
  market = self.safe_market(marketId, market, '_', marketType)
1699
1699
  symbol = market['symbol']
1700
1700
  timestamp = self.safe_integer(ticker, 't')
1701
+ percentage = self.safe_string_2(ticker, 'cr', 'r')
1702
+ if percentage is not None:
1703
+ percentage = Precise.string_mul(percentage, '100')
1701
1704
  return self.safe_ticker({
1702
1705
  'symbol': symbol,
1703
1706
  'timestamp': timestamp,
@@ -1714,7 +1717,7 @@ class xt(Exchange, ImplicitAPI):
1714
1717
  'last': self.safe_string(ticker, 'c'),
1715
1718
  'previousClose': None,
1716
1719
  'change': self.safe_number(ticker, 'cv'),
1717
- 'percentage': self.safe_number_2(ticker, 'cr', 'r'),
1720
+ 'percentage': self.parse_number(percentage),
1718
1721
  'average': None,
1719
1722
  'baseVolume': None,
1720
1723
  'quoteVolume': self.safe_number_2(ticker, 'a', 'v'),
ccxt/yobit.py CHANGED
@@ -1124,7 +1124,7 @@ class yobit(Exchange, ImplicitAPI):
1124
1124
  ids = list(trades.keys())
1125
1125
  result = []
1126
1126
  for i in range(0, len(ids)):
1127
- id = ids[i]
1127
+ id = self.safe_string(ids, i)
1128
1128
  trade = self.parse_trade(self.extend(trades[id], {
1129
1129
  'trade_id': id,
1130
1130
  }), market)