ccxt 4.4.92__py2.py3-none-any.whl → 4.4.93__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 (48) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/lbank.py +1 -1
  3. ccxt/ascendex.py +9 -8
  4. ccxt/async_support/__init__.py +1 -1
  5. ccxt/async_support/ascendex.py +9 -8
  6. ccxt/async_support/base/exchange.py +4 -1
  7. ccxt/async_support/base/ws/client.py +3 -0
  8. ccxt/async_support/binance.py +42 -1
  9. ccxt/async_support/bitmex.py +3 -3
  10. ccxt/async_support/bybit.py +81 -8
  11. ccxt/async_support/coinbaseexchange.py +53 -0
  12. ccxt/async_support/coincheck.py +45 -4
  13. ccxt/async_support/coinex.py +16 -12
  14. ccxt/async_support/cryptomus.py +30 -52
  15. ccxt/async_support/deribit.py +6 -6
  16. ccxt/async_support/exmo.py +64 -52
  17. ccxt/async_support/hyperliquid.py +2 -1
  18. ccxt/async_support/kucoin.py +12 -14
  19. ccxt/async_support/latoken.py +19 -71
  20. ccxt/async_support/lbank.py +2 -2
  21. ccxt/async_support/okx.py +149 -0
  22. ccxt/async_support/paradex.py +54 -0
  23. ccxt/async_support/phemex.py +3 -3
  24. ccxt/base/exchange.py +55 -12
  25. ccxt/binance.py +42 -1
  26. ccxt/bitmex.py +3 -3
  27. ccxt/bybit.py +81 -8
  28. ccxt/coinbaseexchange.py +53 -0
  29. ccxt/coincheck.py +45 -4
  30. ccxt/coinex.py +16 -12
  31. ccxt/cryptomus.py +30 -52
  32. ccxt/deribit.py +6 -6
  33. ccxt/exmo.py +64 -52
  34. ccxt/hyperliquid.py +2 -1
  35. ccxt/kucoin.py +12 -14
  36. ccxt/latoken.py +19 -71
  37. ccxt/lbank.py +2 -2
  38. ccxt/okx.py +149 -0
  39. ccxt/paradex.py +54 -0
  40. ccxt/phemex.py +3 -3
  41. ccxt/pro/__init__.py +1 -1
  42. ccxt/pro/bitstamp.py +48 -16
  43. ccxt/pro/bybit.py +2 -1
  44. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/METADATA +4 -4
  45. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/RECORD +48 -48
  46. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/LICENSE.txt +0 -0
  47. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/WHEEL +0 -0
  48. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/top_level.txt +0 -0
@@ -19,6 +19,7 @@ from ccxt.base.errors import InsufficientFunds
19
19
  from ccxt.base.errors import InvalidOrder
20
20
  from ccxt.base.errors import OrderNotFound
21
21
  from ccxt.base.errors import NotSupported
22
+ from ccxt.base.errors import OperationFailed
22
23
  from ccxt.base.errors import RateLimitExceeded
23
24
  from ccxt.base.errors import ExchangeNotAvailable
24
25
  from ccxt.base.errors import RequestTimeout
@@ -671,6 +672,7 @@ class coinex(Exchange, ImplicitAPI):
671
672
  'broad': {
672
673
  'ip not allow visit': PermissionDenied,
673
674
  'service too busy': ExchangeNotAvailable,
675
+ 'Service is not available during funding fee settlement': OperationFailed,
674
676
  },
675
677
  },
676
678
  })
@@ -795,7 +797,7 @@ class coinex(Exchange, ImplicitAPI):
795
797
  'max': None,
796
798
  },
797
799
  },
798
- 'networks': {},
800
+ 'networks': networks,
799
801
  'type': 'crypto',
800
802
  'info': coin,
801
803
  })
@@ -827,17 +829,19 @@ class coinex(Exchange, ImplicitAPI):
827
829
  # "code": 0,
828
830
  # "data": [
829
831
  # {
830
- # "base_ccy": "SORA",
832
+ # "market": "BTCUSDT",
833
+ # "taker_fee_rate": "0.002",
834
+ # "maker_fee_rate": "0.002",
835
+ # "min_amount": "0.0005",
836
+ # "base_ccy": "BTC",
837
+ # "quote_ccy": "USDT",
831
838
  # "base_ccy_precision": 8,
839
+ # "quote_ccy_precision": 2,
832
840
  # "is_amm_available": True,
833
- # "is_margin_available": False,
834
- # "maker_fee_rate": "0.003",
835
- # "market": "SORAUSDT",
836
- # "min_amount": "500",
837
- # "quote_ccy": "USDT",
838
- # "quote_ccy_precision": 6,
839
- # "taker_fee_rate": "0.003"
840
- # },
841
+ # "is_margin_available": True,
842
+ # "is_pre_trading_available": True,
843
+ # "is_api_trading_available": True
844
+ # }
841
845
  # ],
842
846
  # "message": "OK"
843
847
  # }
@@ -863,11 +867,11 @@ class coinex(Exchange, ImplicitAPI):
863
867
  'settleId': None,
864
868
  'type': 'spot',
865
869
  'spot': True,
866
- 'margin': None,
870
+ 'margin': self.safe_bool(market, 'is_margin_available'),
867
871
  'swap': False,
868
872
  'future': False,
869
873
  'option': False,
870
- 'active': None,
874
+ 'active': self.safe_bool(market, 'is_api_trading_available'),
871
875
  'contract': False,
872
876
  'linear': None,
873
877
  'inverse': None,
@@ -367,66 +367,44 @@ class cryptomus(Exchange, ImplicitAPI):
367
367
  # }
368
368
  #
369
369
  coins = self.safe_list(response, 'result')
370
+ groupedById = self.group_by(coins, 'currency_code')
371
+ keys = list(groupedById.keys())
370
372
  result: dict = {}
371
- for i in range(0, len(coins)):
372
- networkEntry = coins[i]
373
- currencyId = self.safe_string(networkEntry, 'currency_code')
374
- code = self.safe_currency_code(currencyId)
375
- if not (code in result):
376
- result[code] = {
377
- 'id': currencyId,
378
- 'code': code,
379
- 'precision': None,
380
- 'type': None,
381
- 'name': None,
382
- 'active': None,
383
- 'deposit': None,
384
- 'withdraw': None,
385
- 'fee': None,
373
+ for i in range(0, len(keys)):
374
+ id = keys[i]
375
+ code = self.safe_currency_code(id)
376
+ networks = {}
377
+ networkEntries = groupedById[id]
378
+ for j in range(0, len(networkEntries)):
379
+ networkEntry = networkEntries[j]
380
+ networkId = self.safe_string(networkEntry, 'network_code')
381
+ networkCode = self.network_id_to_code(networkId)
382
+ networks[networkCode] = {
383
+ 'id': networkId,
384
+ 'network': networkCode,
386
385
  'limits': {
387
386
  'withdraw': {
388
- 'min': None,
389
- 'max': None,
387
+ 'min': self.safe_number(networkEntry, 'min_withdraw'),
388
+ 'max': self.safe_number(networkEntry, 'max_withdraw'),
390
389
  },
391
390
  'deposit': {
392
- 'min': None,
393
- 'max': None,
391
+ 'min': self.safe_number(networkEntry, 'min_deposit'),
392
+ 'max': self.safe_number(networkEntry, 'max_deposit'),
394
393
  },
395
394
  },
396
- 'networks': {},
397
- 'info': {},
395
+ 'active': None,
396
+ 'deposit': self.safe_bool(networkEntry, 'can_withdraw'),
397
+ 'withdraw': self.safe_bool(networkEntry, 'can_deposit'),
398
+ 'fee': None,
399
+ 'precision': None,
400
+ 'info': networkEntry,
398
401
  }
399
- networkId = self.safe_string(networkEntry, 'network_code')
400
- networkCode = self.network_id_to_code(networkId)
401
- result[code]['networks'][networkCode] = {
402
- 'id': networkId,
403
- 'network': networkCode,
404
- 'limits': {
405
- 'withdraw': {
406
- 'min': self.safe_number(networkEntry, 'min_withdraw'),
407
- 'max': self.safe_number(networkEntry, 'max_withdraw'),
408
- },
409
- 'deposit': {
410
- 'min': self.safe_number(networkEntry, 'min_deposit'),
411
- 'max': self.safe_number(networkEntry, 'max_deposit'),
412
- },
413
- },
414
- 'active': None,
415
- 'deposit': self.safe_bool(networkEntry, 'can_withdraw'),
416
- 'withdraw': self.safe_bool(networkEntry, 'can_deposit'),
417
- 'fee': None,
418
- 'precision': None,
419
- 'info': networkEntry,
420
- }
421
- # add entry in info
422
- info = self.safe_list(result[code], 'info', [])
423
- info.append(networkEntry)
424
- result[code]['info'] = info
425
- # only after all entries are formed in currencies, restructure each entry
426
- allKeys = list(result.keys())
427
- for i in range(0, len(allKeys)):
428
- code = allKeys[i]
429
- result[code] = self.safe_currency_structure(result[code]) # self is needed after adding network entry
402
+ result[code] = self.safe_currency_structure({
403
+ 'id': id,
404
+ 'code': code,
405
+ 'networks': networks,
406
+ 'info': networkEntries,
407
+ })
430
408
  return result
431
409
 
432
410
  async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
@@ -2596,21 +2596,21 @@ class deribit(Exchange, ImplicitAPI):
2596
2596
  unrealizedPnl = self.safe_string(position, 'floating_profit_loss')
2597
2597
  initialMarginString = self.safe_string(position, 'initial_margin')
2598
2598
  notionalString = self.safe_string(position, 'size_currency')
2599
+ notionalStringAbs = Precise.string_abs(notionalString)
2599
2600
  maintenanceMarginString = self.safe_string(position, 'maintenance_margin')
2600
- currentTime = self.milliseconds()
2601
2601
  return self.safe_position({
2602
2602
  'info': position,
2603
2603
  'id': None,
2604
2604
  'symbol': self.safe_string(market, 'symbol'),
2605
- 'timestamp': currentTime,
2606
- 'datetime': self.iso8601(currentTime),
2605
+ 'timestamp': None,
2606
+ 'datetime': None,
2607
2607
  'lastUpdateTimestamp': None,
2608
2608
  'initialMargin': self.parse_number(initialMarginString),
2609
- 'initialMarginPercentage': self.parse_number(Precise.string_mul(Precise.string_div(initialMarginString, notionalString), '100')),
2609
+ 'initialMarginPercentage': self.parse_number(Precise.string_mul(Precise.string_div(initialMarginString, notionalStringAbs), '100')),
2610
2610
  'maintenanceMargin': self.parse_number(maintenanceMarginString),
2611
- 'maintenanceMarginPercentage': self.parse_number(Precise.string_mul(Precise.string_div(maintenanceMarginString, notionalString), '100')),
2611
+ 'maintenanceMarginPercentage': self.parse_number(Precise.string_mul(Precise.string_div(maintenanceMarginString, notionalStringAbs), '100')),
2612
2612
  'entryPrice': self.safe_number(position, 'average_price'),
2613
- 'notional': self.parse_number(notionalString),
2613
+ 'notional': self.parse_number(notionalStringAbs),
2614
2614
  'leverage': self.safe_integer(position, 'leverage'),
2615
2615
  'unrealizedPnl': self.parse_number(unrealizedPnl),
2616
2616
  'contracts': None,
@@ -710,73 +710,85 @@ class exmo(Exchange, ImplicitAPI):
710
710
  for i in range(0, len(currencyList)):
711
711
  currency = currencyList[i]
712
712
  currencyId = self.safe_string(currency, 'name')
713
- name = self.safe_string(currency, 'description')
714
- providers = self.safe_value(cryptoList, currencyId)
715
- active = False
713
+ code = self.safe_currency_code(currencyId)
716
714
  type = 'crypto'
717
- limits: dict = {
718
- 'deposit': {
719
- 'min': None,
720
- 'max': None,
721
- },
722
- 'withdraw': {
723
- 'min': None,
724
- 'max': None,
725
- },
726
- }
727
- fee = None
728
- depositEnabled = None
729
- withdrawEnabled = None
715
+ networks = {}
716
+ providers = self.safe_list(cryptoList, currencyId)
730
717
  if providers is None:
731
- active = True
732
718
  type = 'fiat'
733
719
  else:
734
720
  for j in range(0, len(providers)):
735
721
  provider = providers[j]
722
+ name = self.safe_string(provider, 'name')
723
+ # get network-id by removing extra things
724
+ networkId = name.replace(currencyId + ' ', '')
725
+ networkId = networkId.replace('(', '')
726
+ replaceChar = ')' # transpiler trick
727
+ networkId = networkId.replace(replaceChar, '')
728
+ networkCode = self.network_id_to_code(networkId)
729
+ if not (networkCode in networks):
730
+ networks[networkCode] = {
731
+ 'id': networkId,
732
+ 'network': networkCode,
733
+ 'active': None,
734
+ 'deposit': None,
735
+ 'withdraw': None,
736
+ 'fee': None,
737
+ 'limits': {
738
+ 'withdraw': {
739
+ 'min': None,
740
+ 'max': None,
741
+ },
742
+ 'deposit': {
743
+ 'min': None,
744
+ 'max': None,
745
+ },
746
+ },
747
+ 'info': [], # set, because of multiple network sub-entries
748
+ }
736
749
  typeInner = self.safe_string(provider, 'type')
737
750
  minValue = self.safe_string(provider, 'min')
738
751
  maxValue = self.safe_string(provider, 'max')
739
- if Precise.string_eq(maxValue, '0.0'):
740
- maxValue = None
741
- activeProvider = self.safe_value(provider, 'enabled')
752
+ activeProvider = self.safe_bool(provider, 'enabled')
753
+ networkEntry = networks[networkCode]
742
754
  if typeInner == 'deposit':
743
- if activeProvider and not depositEnabled:
744
- depositEnabled = True
745
- elif not activeProvider:
746
- depositEnabled = False
755
+ networkEntry['deposit'] = activeProvider
756
+ networkEntry['limits']['deposit']['min'] = minValue
757
+ networkEntry['limits']['deposit']['max'] = maxValue
747
758
  elif typeInner == 'withdraw':
748
- if activeProvider and not withdrawEnabled:
749
- withdrawEnabled = True
750
- elif not activeProvider:
751
- withdrawEnabled = False
752
- if activeProvider:
753
- active = True
754
- limitMin = self.number_to_string(limits[typeInner]['min'])
755
- if (limits[typeInner]['min'] is None) or (Precise.string_lt(minValue, limitMin)):
756
- limits[typeInner]['min'] = minValue
757
- limits[typeInner]['max'] = maxValue
758
- if typeInner == 'withdraw':
759
- commissionDesc = self.safe_string(provider, 'commission_desc')
760
- fee = self.parse_fixed_float_value(commissionDesc)
761
- code = self.safe_currency_code(currencyId)
762
- info = {
763
- 'currency': currency,
764
- 'providers': providers,
765
- }
766
- result[code] = {
759
+ networkEntry['withdraw'] = activeProvider
760
+ networkEntry['limits']['withdraw']['min'] = minValue
761
+ networkEntry['limits']['withdraw']['max'] = maxValue
762
+ info = self.safe_list(networkEntry, 'info')
763
+ info.append(provider)
764
+ networkEntry['info'] = info
765
+ networks[networkCode] = networkEntry
766
+ result[code] = self.safe_currency_structure({
767
767
  'id': currencyId,
768
768
  'code': code,
769
- 'name': name,
769
+ 'name': self.safe_string(currency, 'description'),
770
770
  'type': type,
771
- 'active': active,
772
- 'deposit': depositEnabled,
773
- 'withdraw': withdrawEnabled,
774
- 'fee': fee,
771
+ 'active': None,
772
+ 'deposit': None,
773
+ 'withdraw': None,
774
+ 'fee': None,
775
775
  'precision': self.parse_number('1e-8'),
776
- 'limits': limits,
777
- 'info': info,
778
- 'networks': {},
779
- }
776
+ 'limits': {
777
+ 'withdraw': {
778
+ 'min': None,
779
+ 'max': None,
780
+ },
781
+ 'deposit': {
782
+ 'min': None,
783
+ 'max': None,
784
+ },
785
+ },
786
+ 'info': {
787
+ 'currency': currency,
788
+ 'providers': providers,
789
+ },
790
+ 'networks': networks,
791
+ })
780
792
  return result
781
793
 
782
794
  async def fetch_markets(self, params={}) -> List[Market]:
@@ -696,7 +696,8 @@ class hyperliquid(Exchange, ImplicitAPI):
696
696
  # }
697
697
  #
698
698
  quoteId = 'USDC'
699
- base = self.safe_string(market, 'name')
699
+ baseName = self.safe_string(market, 'name')
700
+ base = self.safe_currency_code(baseName)
700
701
  quote = self.safe_currency_code(quoteId)
701
702
  baseId = self.safe_string(market, 'baseId')
702
703
  settleId = 'USDC'
@@ -1397,35 +1397,31 @@ class kucoin(Exchange, ImplicitAPI):
1397
1397
  # }
1398
1398
  #
1399
1399
  currenciesData = self.safe_list(response, 'data', [])
1400
+ brokenCurrencies = self.safe_list(self.options, 'brokenCurrencies', ['00', 'OPEN_ERROR', 'HUF', 'BDT'])
1401
+ otherFiats = self.safe_list(self.options, 'fiats', ['KWD', 'IRR', 'PKR'])
1400
1402
  result: dict = {}
1401
1403
  for i in range(0, len(currenciesData)):
1402
1404
  entry = currenciesData[i]
1403
1405
  id = self.safe_string(entry, 'currency')
1404
- name = self.safe_string(entry, 'fullName')
1406
+ if self.in_array(id, brokenCurrencies):
1407
+ continue # skip buggy entries: https://t.me/KuCoin_API/217798
1405
1408
  code = self.safe_currency_code(id)
1406
1409
  networks: dict = {}
1407
1410
  chains = self.safe_list(entry, 'chains', [])
1408
- rawPrecision = self.safe_string(entry, 'precision')
1409
- precision = self.parse_number(self.parse_precision(rawPrecision))
1410
1411
  chainsLength = len(chains)
1411
- if not chainsLength:
1412
- # one buggy coin, which doesn't contain info https://t.me/KuCoin_API/173118
1413
- continue
1414
1412
  for j in range(0, chainsLength):
1415
1413
  chain = chains[j]
1416
1414
  chainId = self.safe_string(chain, 'chainId')
1417
1415
  networkCode = self.network_id_to_code(chainId, code)
1418
- chainWithdrawEnabled = self.safe_bool(chain, 'isWithdrawEnabled', False)
1419
- chainDepositEnabled = self.safe_bool(chain, 'isDepositEnabled', False)
1420
1416
  networks[networkCode] = {
1421
1417
  'info': chain,
1422
1418
  'id': chainId,
1423
1419
  'name': self.safe_string(chain, 'chainName'),
1424
1420
  'code': networkCode,
1425
- 'active': chainWithdrawEnabled and chainDepositEnabled,
1421
+ 'active': None,
1426
1422
  'fee': self.safe_number(chain, 'withdrawalMinFee'),
1427
- 'deposit': chainDepositEnabled,
1428
- 'withdraw': chainWithdrawEnabled,
1423
+ 'deposit': self.safe_bool(chain, 'isDepositEnabled'),
1424
+ 'withdraw': self.safe_bool(chain, 'isWithdrawEnabled'),
1429
1425
  'precision': self.parse_number(self.parse_precision(self.safe_string(chain, 'withdrawPrecision'))),
1430
1426
  'limits': {
1431
1427
  'withdraw': {
@@ -1439,10 +1435,12 @@ class kucoin(Exchange, ImplicitAPI):
1439
1435
  },
1440
1436
  }
1441
1437
  # kucoin has determined 'fiat' currencies with below logic
1442
- isFiat = (rawPrecision == '2') and (chainsLength == 0)
1438
+ rawPrecision = self.safe_string(entry, 'precision')
1439
+ precision = self.parse_number(self.parse_precision(rawPrecision))
1440
+ isFiat = self.in_array(id, otherFiats) or ((rawPrecision == '2') and (chainsLength == 0))
1443
1441
  result[code] = self.safe_currency_structure({
1444
1442
  'id': id,
1445
- 'name': name,
1443
+ 'name': self.safe_string(entry, 'fullName'),
1446
1444
  'code': code,
1447
1445
  'type': 'fiat' if isFiat else 'crypto',
1448
1446
  'precision': precision,
@@ -2628,7 +2626,7 @@ class kucoin(Exchange, ImplicitAPI):
2628
2626
  """
2629
2627
  await self.load_markets()
2630
2628
  request: dict = {}
2631
- trigger = self.safe_bool(params, 'stop', False)
2629
+ trigger = self.safe_bool_2(params, 'trigger', 'stop', False)
2632
2630
  hf = None
2633
2631
  hf, params = self.handle_hf_and_params(params)
2634
2632
  params = self.omit(params, 'stop')
@@ -247,6 +247,8 @@ class latoken(Exchange, ImplicitAPI):
247
247
  'fetchTradingFee': {
248
248
  'method': 'fetchPrivateTradingFee', # or 'fetchPublicTradingFee'
249
249
  },
250
+ 'timeDifference': 0, # the difference between system clock and exchange clock
251
+ 'adjustForTimeDifference': True, # controls the adjustment logic upon instantiation
250
252
  },
251
253
  'features': {
252
254
  'spot': {
@@ -347,39 +349,6 @@ class latoken(Exchange, ImplicitAPI):
347
349
  :param dict [params]: extra parameters specific to the exchange API endpoint
348
350
  :returns dict[]: an array of objects representing market data
349
351
  """
350
- currencies = await self.fetch_currencies_from_cache(params)
351
- #
352
- # [
353
- # {
354
- # "id":"1a075819-9e0b-48fc-8784-4dab1d186d6d",
355
- # "status":"CURRENCY_STATUS_ACTIVE",
356
- # "type":"CURRENCY_TYPE_ALTERNATIVE", # CURRENCY_TYPE_CRYPTO, CURRENCY_TYPE_IEO
357
- # "name":"MyCryptoBank",
358
- # "tag":"MCB",
359
- # "description":"",
360
- # "logo":"",
361
- # "decimals":18,
362
- # "created":1572912000000,
363
- # "tier":1,
364
- # "assetClass":"ASSET_CLASS_UNKNOWN",
365
- # "minTransferAmount":0
366
- # },
367
- # {
368
- # "id":"db02758e-2507-46a5-a805-7bc60355b3eb",
369
- # "status":"CURRENCY_STATUS_ACTIVE",
370
- # "type":"CURRENCY_TYPE_FUTURES_CONTRACT",
371
- # "name":"BTC USDT Futures Contract",
372
- # "tag":"BTCUSDT",
373
- # "description":"",
374
- # "logo":"",
375
- # "decimals":8,
376
- # "created":1589459984395,
377
- # "tier":1,
378
- # "assetClass":"ASSET_CLASS_UNKNOWN",
379
- # "minTransferAmount":0
380
- # },
381
- # ]
382
- #
383
352
  response = await self.publicGetPair(params)
384
353
  #
385
354
  # [
@@ -401,8 +370,9 @@ class latoken(Exchange, ImplicitAPI):
401
370
  # }
402
371
  # ]
403
372
  #
404
- if self.safe_value(self.options, 'adjustForTimeDifference', True):
373
+ if self.safe_bool(self.options, 'adjustForTimeDifference', False):
405
374
  await self.load_time_difference()
375
+ currencies = self.safe_dict(self.options, 'cachedCurrencies', {})
406
376
  currenciesById = self.index_by(currencies, 'id')
407
377
  result = []
408
378
  for i in range(0, len(response)):
@@ -411,11 +381,13 @@ class latoken(Exchange, ImplicitAPI):
411
381
  # the exchange shows them inverted
412
382
  baseId = self.safe_string(market, 'baseCurrency')
413
383
  quoteId = self.safe_string(market, 'quoteCurrency')
414
- baseCurrency = self.safe_value(currenciesById, baseId)
415
- quoteCurrency = self.safe_value(currenciesById, quoteId)
416
- if baseCurrency is not None and quoteCurrency is not None:
417
- base = self.safe_currency_code(self.safe_string(baseCurrency, 'tag'))
418
- quote = self.safe_currency_code(self.safe_string(quoteCurrency, 'tag'))
384
+ baseCurrency = self.safe_dict(currenciesById, baseId)
385
+ quoteCurrency = self.safe_dict(currenciesById, quoteId)
386
+ baseCurrencyInfo = self.safe_dict(baseCurrency, 'info')
387
+ quoteCurrencyInfo = self.safe_dict(quoteCurrency, 'info')
388
+ if baseCurrencyInfo is not None and quoteCurrencyInfo is not None:
389
+ base = self.safe_currency_code(self.safe_string(baseCurrencyInfo, 'tag'))
390
+ quote = self.safe_currency_code(self.safe_string(quoteCurrencyInfo, 'tag'))
419
391
  lowercaseQuote = quote.lower()
420
392
  capitalizedQuote = self.capitalize(lowercaseQuote)
421
393
  status = self.safe_string(market, 'status')
@@ -470,28 +442,13 @@ class latoken(Exchange, ImplicitAPI):
470
442
  })
471
443
  return result
472
444
 
473
- async def fetch_currencies_from_cache(self, params={}):
474
- # self method is now redundant
475
- # currencies are now fetched before markets
476
- options = self.safe_value(self.options, 'fetchCurrencies', {})
477
- timestamp = self.safe_integer(options, 'timestamp')
478
- expires = self.safe_integer(options, 'expires', 1000)
479
- now = self.milliseconds()
480
- if (timestamp is None) or ((now - timestamp) > expires):
481
- response = await self.publicGetCurrency(params)
482
- self.options['fetchCurrencies'] = self.extend(options, {
483
- 'response': response,
484
- 'timestamp': now,
485
- })
486
- return self.safe_value(self.options['fetchCurrencies'], 'response')
487
-
488
445
  async def fetch_currencies(self, params={}) -> Currencies:
489
446
  """
490
447
  fetches all available currencies on an exchange
491
448
  :param dict [params]: extra parameters specific to the exchange API endpoint
492
449
  :returns dict: an associative dictionary of currencies
493
450
  """
494
- response = await self.fetch_currencies_from_cache(params)
451
+ response = await self.publicGetCurrency(params)
495
452
  #
496
453
  # [
497
454
  # {
@@ -530,27 +487,18 @@ class latoken(Exchange, ImplicitAPI):
530
487
  id = self.safe_string(currency, 'id')
531
488
  tag = self.safe_string(currency, 'tag')
532
489
  code = self.safe_currency_code(tag)
533
- fee = self.safe_number(currency, 'fee')
534
490
  currencyType = self.safe_string(currency, 'type')
535
- type = None
536
- if currencyType == 'CURRENCY_TYPE_ALTERNATIVE':
537
- type = 'other'
538
- else:
539
- # CURRENCY_TYPE_CRYPTO and CURRENCY_TYPE_IEO are all cryptos
540
- type = 'crypto'
541
- status = self.safe_string(currency, 'status')
542
- active = (status == 'CURRENCY_STATUS_ACTIVE')
543
- name = self.safe_string(currency, 'name')
544
- result[code] = {
491
+ isCrypto = (currencyType == 'CURRENCY_TYPE_CRYPTO' or currencyType == 'CURRENCY_TYPE_IEO')
492
+ result[code] = self.safe_currency_structure({
545
493
  'id': id,
546
494
  'code': code,
547
495
  'info': currency,
548
- 'name': name,
549
- 'type': type,
550
- 'active': active,
496
+ 'name': self.safe_string(currency, 'name'),
497
+ 'type': 'crypto' if isCrypto else 'other',
498
+ 'active': self.safe_string(currency, 'status') == 'CURRENCY_STATUS_ACTIVE',
551
499
  'deposit': None,
552
500
  'withdraw': None,
553
- 'fee': fee,
501
+ 'fee': self.safe_number(currency, 'fee'),
554
502
  'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals'))),
555
503
  'limits': {
556
504
  'amount': {
@@ -563,7 +511,7 @@ class latoken(Exchange, ImplicitAPI):
563
511
  },
564
512
  },
565
513
  'networks': {},
566
- }
514
+ })
567
515
  return result
568
516
 
569
517
  async def fetch_balance(self, params={}) -> Balances:
@@ -138,7 +138,7 @@ class lbank(Exchange, ImplicitAPI):
138
138
  'accuracy': 2.5,
139
139
  'usdToCny': 2.5,
140
140
  'assetConfigs': 2.5,
141
- 'withdrawConfigs': 2.5,
141
+ 'withdrawConfigs': 2.5 * 1.5, # frequently rate-limits, so increase self endpoint RL
142
142
  'timestamp': 2.5,
143
143
  'ticker/24hr': 2.5,
144
144
  'ticker': 2.5,
@@ -675,7 +675,7 @@ class lbank(Exchange, ImplicitAPI):
675
675
  'active': True,
676
676
  'contract': True,
677
677
  'linear': True,
678
- 'inverse': None,
678
+ 'inverse': False,
679
679
  'contractSize': self.safe_number(market, 'volumeMultiple'),
680
680
  'expiry': None,
681
681
  'expiryDatetime': None,