ccxt 4.4.85__py2.py3-none-any.whl → 4.4.86__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 (54) hide show
  1. ccxt/__init__.py +3 -5
  2. ccxt/abstract/myokx.py +2 -0
  3. ccxt/abstract/okx.py +2 -0
  4. ccxt/ascendex.py +187 -151
  5. ccxt/async_support/__init__.py +3 -5
  6. ccxt/async_support/ascendex.py +187 -151
  7. ccxt/async_support/base/exchange.py +26 -22
  8. ccxt/async_support/bequant.py +1 -1
  9. ccxt/async_support/bitget.py +4 -4
  10. ccxt/async_support/bitmart.py +1 -1
  11. ccxt/async_support/{huobijp.py → bittrade.py} +11 -11
  12. ccxt/async_support/coinbase.py +2 -5
  13. ccxt/async_support/deribit.py +4 -5
  14. ccxt/async_support/hollaex.py +106 -49
  15. ccxt/async_support/htx.py +20 -43
  16. ccxt/async_support/hyperliquid.py +4 -4
  17. ccxt/async_support/mexc.py +2 -2
  18. ccxt/async_support/ndax.py +25 -24
  19. ccxt/async_support/okcoin.py +12 -29
  20. ccxt/async_support/okx.py +9 -0
  21. ccxt/async_support/onetrading.py +10 -7
  22. ccxt/async_support/oxfun.py +40 -110
  23. ccxt/async_support/paradex.py +3 -0
  24. ccxt/base/exchange.py +1 -1
  25. ccxt/bequant.py +1 -1
  26. ccxt/bitget.py +4 -4
  27. ccxt/bitmart.py +1 -1
  28. ccxt/{huobijp.py → bittrade.py} +11 -11
  29. ccxt/coinbase.py +2 -5
  30. ccxt/deribit.py +4 -5
  31. ccxt/hollaex.py +106 -49
  32. ccxt/htx.py +20 -43
  33. ccxt/hyperliquid.py +4 -4
  34. ccxt/mexc.py +2 -2
  35. ccxt/ndax.py +25 -24
  36. ccxt/okcoin.py +12 -29
  37. ccxt/okx.py +9 -0
  38. ccxt/onetrading.py +10 -7
  39. ccxt/oxfun.py +40 -110
  40. ccxt/paradex.py +3 -0
  41. ccxt/pro/__init__.py +41 -3
  42. ccxt/pro/binance.py +1 -0
  43. ccxt/pro/{huobijp.py → bittrade.py} +3 -3
  44. ccxt/pro/luno.py +6 -5
  45. ccxt/pro/mexc.py +2 -0
  46. {ccxt-4.4.85.dist-info → ccxt-4.4.86.dist-info}/METADATA +7 -8
  47. {ccxt-4.4.85.dist-info → ccxt-4.4.86.dist-info}/RECORD +51 -54
  48. ccxt/abstract/kuna.py +0 -182
  49. ccxt/async_support/kuna.py +0 -1935
  50. ccxt/kuna.py +0 -1935
  51. /ccxt/abstract/{huobijp.py → bittrade.py} +0 -0
  52. {ccxt-4.4.85.dist-info → ccxt-4.4.86.dist-info}/LICENSE.txt +0 -0
  53. {ccxt-4.4.85.dist-info → ccxt-4.4.86.dist-info}/WHEEL +0 -0
  54. {ccxt-4.4.85.dist-info → ccxt-4.4.86.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.ascendex import ImplicitAPI
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Account, Any, Balances, Bool, Currencies, Currency, DepositAddress, Int, Leverage, Leverages, LeverageTier, LeverageTiers, MarginMode, MarginModes, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFees, Transaction, TransferEntry
10
+ from ccxt.base.types import Account, Any, Balances, Currencies, Currency, DepositAddress, Int, Leverage, Leverages, LeverageTier, LeverageTiers, MarginMode, MarginModes, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFees, Transaction, TransferEntry
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
@@ -478,6 +478,7 @@ class ascendex(Exchange, ImplicitAPI):
478
478
  'broad': {},
479
479
  },
480
480
  'commonCurrencies': {
481
+ 'XBT': 'XBT', # self is not BTC ! just another token
481
482
  'BOND': 'BONDED',
482
483
  'BTCBEAR': 'BEAR',
483
484
  'BTCBULL': 'BULL',
@@ -498,112 +499,82 @@ class ascendex(Exchange, ImplicitAPI):
498
499
  :param dict [params]: extra parameters specific to the exchange API endpoint
499
500
  :returns dict: an associative dictionary of currencies
500
501
  """
501
- assetsPromise = self.v1PublicGetAssets(params)
502
- #
503
- # {
504
- # "code":0,
505
- # "data":[
506
- # {
507
- # "assetCode" : "LTCBULL",
508
- # "assetName" : "3X Long LTC Token",
509
- # "precisionScale" : 9,
510
- # "nativeScale" : 4,
511
- # "withdrawalFee" : "0.2",
512
- # "minWithdrawalAmt" : "1.0",
513
- # "status" : "Normal"
514
- # },
515
- # ]
516
- # }
517
- #
518
- marginPromise = self.v1PublicGetMarginAssets(params)
519
- #
520
- # {
521
- # "code":0,
522
- # "data":[
523
- # {
524
- # "assetCode":"BTT",
525
- # "displayName": "BTT",
526
- # "borrowAssetCode":"BTT-B",
527
- # "interestAssetCode":"BTT-I",
528
- # "nativeScale":0,
529
- # "numConfirmations":1,
530
- # "withdrawFee":"100.0",
531
- # "minWithdrawalAmt":"1000.0",
532
- # "statusCode":"Normal",
533
- # "statusMessage":"",
534
- # "interestRate":"0.001"
535
- # }
536
- # ]
537
- # }
538
- #
539
- cashPromise = self.v1PublicGetCashAssets(params)
502
+ response = await self.v2PublicGetAssets(params)
540
503
  #
541
- # {
542
- # "code":0,
543
- # "data":[
544
- # {
545
- # "assetCode":"LTCBULL",
546
- # "displayName": "LTCBULL",
547
- # "nativeScale":4,
548
- # "numConfirmations":20,
549
- # "withdrawFee":"0.2",
550
- # "minWithdrawalAmt":"1.0",
551
- # "statusCode":"Normal",
552
- # "statusMessage":"" # hideFromWalletTx
553
- # }
504
+ # {
505
+ # "code": "0",
506
+ # "data": [
507
+ # {
508
+ # "assetCode": "USDT",
509
+ # "assetName": "Tether",
510
+ # "precisionScale": 9,
511
+ # "nativeScale": 4,
512
+ # "blockChain": [
513
+ # {
514
+ # "chainName": "Solana",
515
+ # "withdrawFee": "2.0",
516
+ # "allowDeposit": True,
517
+ # "allowWithdraw": True,
518
+ # "minDepositAmt": "0.01",
519
+ # "minWithdrawal": "4.0",
520
+ # "numConfirmations": 1
521
+ # },
522
+ # ...
523
+ # ]
524
+ # },
554
525
  # ]
555
- # }
526
+ # }
556
527
  #
557
- assets, margin, cash = await asyncio.gather(*[assetsPromise, marginPromise, cashPromise])
558
- assetsData = self.safe_list(assets, 'data', [])
559
- marginData = self.safe_list(margin, 'data', [])
560
- cashData = self.safe_list(cash, 'data', [])
561
- assetsById = self.index_by(assetsData, 'assetCode')
562
- marginById = self.index_by(marginData, 'assetCode')
563
- cashById = self.index_by(cashData, 'assetCode')
564
- dataById = self.deep_extend(assetsById, marginById, cashById)
565
- ids = list(dataById.keys())
528
+ data = self.safe_list(response, 'data', [])
566
529
  result: dict = {}
567
- for i in range(0, len(ids)):
568
- id = self.safe_string(ids, i)
569
- currency = dataById[id]
530
+ for i in range(0, len(data)):
531
+ currency = data[i]
532
+ id = self.safe_string(currency, 'assetCode')
570
533
  code = self.safe_currency_code(id)
571
- scale = self.safe_string_2(currency, 'precisionScale', 'nativeScale')
572
- precision = self.parse_number(self.parse_precision(scale))
573
- fee = self.safe_number_2(currency, 'withdrawFee', 'withdrawalFee')
574
- status = self.safe_string(currency, 'status')
575
- statusCode = self.safe_string(currency, 'statusCode')
576
- active = (status == 'Normal')
577
- depositEnabled: Bool = None
578
- withdrawEnabled: Bool = None
579
- if status == 'Delisted' or statusCode == 'hideFromWalletTx':
580
- depositEnabled = False
581
- withdrawEnabled = False
582
- elif status == 'Normal':
583
- depositEnabled = True
584
- withdrawEnabled = True
585
- elif status == 'NoTransaction' or statusCode == 'NoTransaction':
586
- depositEnabled = True
587
- withdrawEnabled = False
588
- elif status == 'NoDeposit':
589
- depositEnabled = False
590
- withdrawEnabled = True
591
- marginInside = ('borrowAssetCode' in currency)
592
- result[code] = {
534
+ chains = self.safe_list(currency, 'blockChain', [])
535
+ precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'nativeScale')))
536
+ networks = {}
537
+ for j in range(0, len(chains)):
538
+ networkEtnry = chains[j]
539
+ networkId = self.safe_string(networkEtnry, 'chainName')
540
+ networkCode = self.network_code_to_id(networkId)
541
+ networks[networkCode] = {
542
+ 'fee': self.safe_number(networkEtnry, 'withdrawFee'),
543
+ 'active': None,
544
+ 'withdraw': self.safe_bool(networkEtnry, 'allowWithdraw'),
545
+ 'deposit': self.safe_bool(networkEtnry, 'allowDeposit'),
546
+ 'precision': precision,
547
+ 'limits': {
548
+ 'amount': {
549
+ 'min': None,
550
+ 'max': None,
551
+ },
552
+ 'withdraw': {
553
+ 'min': self.safe_number(networkEtnry, 'minWithdrawal'),
554
+ 'max': None,
555
+ },
556
+ 'deposit': {
557
+ 'min': self.safe_number(networkEtnry, 'minDepositAmt'),
558
+ 'max': None,
559
+ },
560
+ },
561
+ }
562
+ # todo type: if chainsLength == 0 and (assetName.endswith(' Staking') or assetName.find(' Reward ') >= 0 or assetName.find('Slot Auction') >= 0 or assetName.find(' Freeze Asset') >= 0):
563
+ result[code] = self.safe_currency_structure({
593
564
  'id': id,
594
565
  'code': code,
595
566
  'info': currency,
596
567
  'type': None,
597
- 'margin': marginInside,
568
+ 'margin': None,
598
569
  'name': self.safe_string(currency, 'assetName'),
599
- 'active': active,
600
- 'deposit': depositEnabled,
601
- 'withdraw': withdrawEnabled,
602
- 'fee': fee,
570
+ 'active': None,
571
+ 'deposit': None,
572
+ 'withdraw': None,
573
+ 'fee': None,
603
574
  'precision': precision,
604
575
  'limits': {
605
576
  'amount': {
606
- 'min': precision,
577
+ 'min': None,
607
578
  'max': None,
608
579
  },
609
580
  'withdraw': {
@@ -611,8 +582,8 @@ class ascendex(Exchange, ImplicitAPI):
611
582
  'max': None,
612
583
  },
613
584
  },
614
- 'networks': {}, # todo
615
- }
585
+ 'networks': networks,
586
+ })
616
587
  return result
617
588
 
618
589
  async def fetch_markets(self, params={}) -> List[Market]:
@@ -621,6 +592,12 @@ class ascendex(Exchange, ImplicitAPI):
621
592
  :param dict [params]: extra parameters specific to the exchange API endpoint
622
593
  :returns dict[]: an array of objects representing market data
623
594
  """
595
+ spotPromise = self.fetch_spot_markets(params)
596
+ contractPromise = self.fetch_contract_markets(params)
597
+ spotMarkets, contractMarkets = await asyncio.gather(*[spotPromise, contractPromise])
598
+ return self.array_concat(spotMarkets, contractMarkets)
599
+
600
+ async def fetch_spot_markets(self, params={}) -> List[Market]:
624
601
  productsPromise = self.v1PublicGetProducts(params)
625
602
  #
626
603
  # {
@@ -672,7 +649,91 @@ class ascendex(Exchange, ImplicitAPI):
672
649
  # ]
673
650
  # }
674
651
  #
675
- perpetualsPromise = self.v2PublicGetFuturesContract(params)
652
+ products, cash = await asyncio.gather(*[productsPromise, cashPromise])
653
+ productsData = self.safe_list(products, 'data', [])
654
+ productsById = self.index_by(productsData, 'symbol')
655
+ cashData = self.safe_list(cash, 'data', [])
656
+ cashAndPerpetualsById = self.index_by(cashData, 'symbol')
657
+ dataById = self.deep_extend(productsById, cashAndPerpetualsById)
658
+ ids = list(dataById.keys())
659
+ result = []
660
+ for i in range(0, len(ids)):
661
+ id = ids[i]
662
+ if id.find('-PERP') >= 0:
663
+ continue # skip perpetuals, endpoint returns them
664
+ market = dataById[id]
665
+ status = self.safe_string(market, 'status')
666
+ domain = self.safe_string(market, 'domain')
667
+ active = False
668
+ if ((status == 'Normal') or (status == 'InternalTrading')) and (domain != 'LeveragedETF'):
669
+ active = True
670
+ minQty = self.safe_number(market, 'minQty')
671
+ maxQty = self.safe_number(market, 'maxQty')
672
+ minPrice = self.safe_number(market, 'tickSize')
673
+ maxPrice: Num = None
674
+ underlying = self.safe_string_2(market, 'underlying', 'symbol')
675
+ parts = underlying.split('/')
676
+ baseId = self.safe_string(parts, 0)
677
+ quoteId = self.safe_string(parts, 1)
678
+ base = self.safe_currency_code(baseId)
679
+ quote = self.safe_currency_code(quoteId)
680
+ fee = self.safe_number(market, 'commissionReserveRate')
681
+ marginTradable = self.safe_bool(market, 'marginTradable', False)
682
+ result.append({
683
+ 'id': id,
684
+ 'symbol': base + '/' + quote,
685
+ 'base': base,
686
+ 'baseId': baseId,
687
+ 'quote': quote,
688
+ 'quoteId': quoteId,
689
+ 'settle': None,
690
+ 'settleId': None,
691
+ 'type': 'spot',
692
+ 'spot': True,
693
+ 'margin': marginTradable,
694
+ 'swap': False,
695
+ 'future': False,
696
+ 'option': False,
697
+ 'active': active,
698
+ 'contract': False,
699
+ 'linear': None,
700
+ 'inverse': None,
701
+ 'taker': fee,
702
+ 'maker': fee,
703
+ 'contractSize': None,
704
+ 'expiry': None,
705
+ 'expiryDatetime': None,
706
+ 'strike': None,
707
+ 'optionType': None,
708
+ 'precision': {
709
+ 'amount': self.safe_number(market, 'lotSize'),
710
+ 'price': self.safe_number(market, 'tickSize'),
711
+ },
712
+ 'limits': {
713
+ 'leverage': {
714
+ 'min': None,
715
+ 'max': None,
716
+ },
717
+ 'amount': {
718
+ 'min': minQty,
719
+ 'max': maxQty,
720
+ },
721
+ 'price': {
722
+ 'min': minPrice,
723
+ 'max': maxPrice,
724
+ },
725
+ 'cost': {
726
+ 'min': self.safe_number(market, 'minNotional'),
727
+ 'max': self.safe_number(market, 'maxNotional'),
728
+ },
729
+ },
730
+ 'created': self.safe_integer(market, 'tradingStartTime'),
731
+ 'info': market,
732
+ })
733
+ return result
734
+
735
+ async def fetch_contract_markets(self, params={}) -> List[Market]:
736
+ contracts = await self.v2PublicGetFuturesContract(params)
676
737
  #
677
738
  # {
678
739
  # "code": 0,
@@ -685,9 +746,9 @@ class ascendex(Exchange, ImplicitAPI):
685
746
  # "underlying": "BTC/USDT",
686
747
  # "tradingStartTime": 1579701600000,
687
748
  # "priceFilter": {
688
- # "minPrice": "1",
749
+ # "minPrice": "0.1",
689
750
  # "maxPrice": "1000000",
690
- # "tickSize": "1"
751
+ # "tickSize": "0.1"
691
752
  # },
692
753
  # "lotSizeFilter": {
693
754
  # "minQty": "0.0001",
@@ -710,50 +771,25 @@ class ascendex(Exchange, ImplicitAPI):
710
771
  # ]
711
772
  # }
712
773
  #
713
- products, cash, perpetuals = await asyncio.gather(*[productsPromise, cashPromise, perpetualsPromise])
714
- productsData = self.safe_list(products, 'data', [])
715
- productsById = self.index_by(productsData, 'symbol')
716
- cashData = self.safe_list(cash, 'data', [])
717
- perpetualsData = self.safe_list(perpetuals, 'data', [])
718
- cashAndPerpetualsData = self.array_concat(cashData, perpetualsData)
719
- cashAndPerpetualsById = self.index_by(cashAndPerpetualsData, 'symbol')
720
- dataById = self.deep_extend(productsById, cashAndPerpetualsById)
721
- ids = list(dataById.keys())
774
+ data = self.safe_list(contracts, 'data', [])
722
775
  result = []
723
- for i in range(0, len(ids)):
724
- id = ids[i]
725
- market = dataById[id]
726
- settleId = self.safe_string(market, 'settlementAsset')
727
- settle = self.safe_currency_code(settleId)
728
- status = self.safe_string(market, 'status')
729
- domain = self.safe_string(market, 'domain')
730
- active = False
731
- if ((status == 'Normal') or (status == 'InternalTrading')) and (domain != 'LeveragedETF'):
732
- active = True
733
- spot = settle is None
734
- swap = not spot
735
- linear = True if swap else None
736
- minQty = self.safe_number(market, 'minQty')
737
- maxQty = self.safe_number(market, 'maxQty')
738
- minPrice = self.safe_number(market, 'tickSize')
739
- maxPrice: Num = None
740
- underlying = self.safe_string_2(market, 'underlying', 'symbol')
776
+ for i in range(0, len(data)):
777
+ market = data[i]
778
+ id = self.safe_string(market, 'symbol')
779
+ underlying = self.safe_string(market, 'underlying')
741
780
  parts = underlying.split('/')
742
781
  baseId = self.safe_string(parts, 0)
743
- quoteId = self.safe_string(parts, 1)
744
782
  base = self.safe_currency_code(baseId)
783
+ quoteId = self.safe_string(parts, 1)
745
784
  quote = self.safe_currency_code(quoteId)
746
- symbol = base + '/' + quote
747
- if swap:
748
- lotSizeFilter = self.safe_dict(market, 'lotSizeFilter')
749
- minQty = self.safe_number(lotSizeFilter, 'minQty')
750
- maxQty = self.safe_number(lotSizeFilter, 'maxQty')
751
- priceFilter = self.safe_dict(market, 'priceFilter')
752
- minPrice = self.safe_number(priceFilter, 'minPrice')
753
- maxPrice = self.safe_number(priceFilter, 'maxPrice')
754
- symbol = base + '/' + quote + ':' + settle
785
+ settleId = self.safe_string(market, 'settlementAsset')
786
+ settle = self.safe_currency_code(settleId)
787
+ linear = settle == quote
788
+ inverse = settle == base
789
+ symbol = base + '/' + quote + ':' + settle
790
+ priceFilter = self.safe_dict(market, 'priceFilter')
791
+ lotSizeFilter = self.safe_dict(market, 'lotSizeFilter')
755
792
  fee = self.safe_number(market, 'commissionReserveRate')
756
- marginTradable = self.safe_bool(market, 'marginTradable', False)
757
793
  result.append({
758
794
  'id': id,
759
795
  'symbol': symbol,
@@ -763,26 +799,26 @@ class ascendex(Exchange, ImplicitAPI):
763
799
  'baseId': baseId,
764
800
  'quoteId': quoteId,
765
801
  'settleId': settleId,
766
- 'type': 'swap' if swap else 'spot',
767
- 'spot': spot,
768
- 'margin': marginTradable if spot else None,
769
- 'swap': swap,
802
+ 'type': 'swap',
803
+ 'spot': False,
804
+ 'margin': None,
805
+ 'swap': True,
770
806
  'future': False,
771
807
  'option': False,
772
- 'active': active,
773
- 'contract': swap,
808
+ 'active': self.safe_string(market, 'status') == 'Normal',
809
+ 'contract': True,
774
810
  'linear': linear,
775
- 'inverse': not linear if swap else None,
811
+ 'inverse': inverse,
776
812
  'taker': fee,
777
813
  'maker': fee,
778
- 'contractSize': self.parse_number('1') if swap else None,
814
+ 'contractSize': self.parse_number('1'),
779
815
  'expiry': None,
780
816
  'expiryDatetime': None,
781
817
  'strike': None,
782
818
  'optionType': None,
783
819
  'precision': {
784
- 'amount': self.safe_number(market, 'lotSize'),
785
- 'price': self.safe_number(market, 'tickSize'),
820
+ 'amount': self.safe_number(lotSizeFilter, 'lotSize'),
821
+ 'price': self.safe_number(priceFilter, 'tickSize'),
786
822
  },
787
823
  'limits': {
788
824
  'leverage': {
@@ -790,12 +826,12 @@ class ascendex(Exchange, ImplicitAPI):
790
826
  'max': None,
791
827
  },
792
828
  'amount': {
793
- 'min': minQty,
794
- 'max': maxQty,
829
+ 'min': self.safe_number(lotSizeFilter, 'minQty'),
830
+ 'max': self.safe_number(lotSizeFilter, 'maxQty'),
795
831
  },
796
832
  'price': {
797
- 'min': minPrice,
798
- 'max': maxPrice,
833
+ 'min': self.safe_number(priceFilter, 'minPrice'),
834
+ 'max': self.safe_number(priceFilter, 'maxPrice'),
799
835
  },
800
836
  'cost': {
801
837
  'min': self.safe_number(market, 'minNotional'),
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.4.85'
5
+ __version__ = '4.4.86'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -176,15 +176,7 @@ class Exchange(BaseExchange):
176
176
  if (socksProxy not in self.socks_proxy_sessions):
177
177
  # Create our SSL context object with our CA cert file
178
178
  self.open() # ensure `asyncio_loop` is set
179
- self.aiohttp_socks_connector = ProxyConnector.from_url(
180
- socksProxy,
181
- # extra args copied from self.open()
182
- ssl=self.ssl_context,
183
- loop=self.asyncio_loop,
184
- enable_cleanup_closed=True
185
- )
186
- self.socks_proxy_sessions[socksProxy] = aiohttp.ClientSession(loop=self.asyncio_loop, connector=self.aiohttp_socks_connector, trust_env=self.aiohttp_trust_env)
187
- proxy_session = self.socks_proxy_sessions[socksProxy]
179
+ proxy_session = self.get_socks_proxy_session(socksProxy)
188
180
  # add aiohttp_proxy for python as exclusion
189
181
  elif self.aiohttp_proxy:
190
182
  final_proxy = self.aiohttp_proxy
@@ -267,6 +259,20 @@ class Exchange(BaseExchange):
267
259
  return http_response
268
260
  return response.content
269
261
 
262
+ def get_socks_proxy_session(self, socksProxy):
263
+ if (self.socks_proxy_sessions is None):
264
+ self.socks_proxy_sessions = {}
265
+ if (socksProxy not in self.socks_proxy_sessions):
266
+ self.aiohttp_socks_connector = ProxyConnector.from_url(
267
+ socksProxy,
268
+ # extra args copied from self.open()
269
+ ssl=self.ssl_context,
270
+ loop=self.asyncio_loop,
271
+ enable_cleanup_closed=True
272
+ )
273
+ self.socks_proxy_sessions[socksProxy] = aiohttp.ClientSession(loop=self.asyncio_loop, connector=self.aiohttp_socks_connector, trust_env=self.aiohttp_trust_env)
274
+ return self.socks_proxy_sessions[socksProxy]
275
+
270
276
  async def load_markets_helper(self, reload=False, params={}):
271
277
  if not reload:
272
278
  if self.markets:
@@ -411,19 +417,12 @@ class Exchange(BaseExchange):
411
417
  # we use aiohttp instead of fastClient now because of this
412
418
  # https://github.com/ccxt/ccxt/pull/25995
413
419
  self.clients[url] = AiohttpClient(url, on_message, on_error, on_close, on_connected, options)
414
- self.clients[url].proxy = self.get_ws_proxy()
420
+ # set http/s proxy (socks proxy should be set in other place)
421
+ httpProxy, httpsProxy, socksProxy = self.check_ws_proxy_settings()
422
+ if (httpProxy or httpsProxy):
423
+ self.clients[url].proxy = httpProxy if httpProxy else httpsProxy
415
424
  return self.clients[url]
416
425
 
417
- def get_ws_proxy(self):
418
- httpProxy, httpsProxy, socksProxy = self.check_ws_proxy_settings()
419
- if httpProxy:
420
- return httpProxy
421
- elif httpsProxy:
422
- return httpsProxy
423
- elif socksProxy:
424
- return socksProxy
425
- return None
426
-
427
426
  def delay(self, timeout, method, *args):
428
427
  return self.asyncio_loop.call_later(timeout / 1000, self.spawn, method, *args)
429
428
 
@@ -486,8 +485,13 @@ class Exchange(BaseExchange):
486
485
  if not subscribed:
487
486
  client.subscriptions[subscribe_hash] = subscription or True
488
487
 
488
+ selected_session = self.session
489
+ # http/s proxy is being set in other places
490
+ httpProxy, httpsProxy, socksProxy = self.check_ws_proxy_settings()
491
+ if (socksProxy):
492
+ selected_session = self.get_socks_proxy_session(socksProxy)
489
493
  connected = client.connected if client.connected.done() \
490
- else asyncio.ensure_future(client.connect(self.session, backoff_delay))
494
+ else asyncio.ensure_future(client.connect(selected_session, backoff_delay))
491
495
 
492
496
  def after(fut):
493
497
  # todo: decouple signing from subscriptions
@@ -14,8 +14,8 @@ class bequant(hitbtc, ImplicitAPI):
14
14
  return self.deep_extend(super(bequant, self).describe(), {
15
15
  'id': 'bequant',
16
16
  'name': 'Bequant',
17
- 'countries': ['MT'], # Malta
18
17
  'pro': True,
18
+ 'countries': ['MT'], # Malta
19
19
  'urls': {
20
20
  'logo': 'https://github.com/user-attachments/assets/0583ef1f-29fe-4b7c-8189-63565a0e2867',
21
21
  'api': {
@@ -2371,7 +2371,7 @@ class bitget(Exchange, ImplicitAPI):
2371
2371
  'coin': currency['id'],
2372
2372
  'address': address,
2373
2373
  'chain': networkId,
2374
- 'size': amount,
2374
+ 'size': self.currency_to_precision(code, amount, networkCode),
2375
2375
  'transferType': 'on_chain',
2376
2376
  }
2377
2377
  if tag is not None:
@@ -2395,8 +2395,6 @@ class bitget(Exchange, ImplicitAPI):
2395
2395
  fillResponseFromRequest = self.safe_bool(withdrawOptions, 'fillResponseFromRequest', True)
2396
2396
  if fillResponseFromRequest:
2397
2397
  result['currency'] = code
2398
- result['timestamp'] = self.milliseconds()
2399
- result['datetime'] = self.iso8601(self.milliseconds())
2400
2398
  result['amount'] = amount
2401
2399
  result['tag'] = tag
2402
2400
  result['address'] = address
@@ -2514,7 +2512,9 @@ class bitget(Exchange, ImplicitAPI):
2514
2512
  status = self.safe_string(transaction, 'status')
2515
2513
  tag = self.safe_string(transaction, 'tag')
2516
2514
  feeCostString = self.safe_string(transaction, 'fee')
2517
- feeCostAbsString = Precise.string_abs(feeCostString)
2515
+ feeCostAbsString = None
2516
+ if feeCostString is not None:
2517
+ feeCostAbsString = Precise.string_abs(feeCostString)
2518
2518
  fee = None
2519
2519
  amountString = self.safe_string(transaction, 'size')
2520
2520
  if feeCostAbsString is not None:
@@ -2306,7 +2306,7 @@ class bitmart(Exchange, ImplicitAPI):
2306
2306
  code = self.safe_currency_code(currencyId)
2307
2307
  account = self.account()
2308
2308
  account['free'] = self.safe_string_2(balance, 'available', 'available_balance')
2309
- account['used'] = self.safe_string_2(balance, 'frozen', 'frozen_balance')
2309
+ account['used'] = self.safe_string_n(balance, ['unAvailable', 'frozen', 'frozen_balance'])
2310
2310
  result[code] = account
2311
2311
  return self.safe_balance(result)
2312
2312
 
@@ -4,7 +4,7 @@
4
4
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
- from ccxt.abstract.huobijp import ImplicitAPI
7
+ from ccxt.abstract.bittrade import ImplicitAPI
8
8
  import hashlib
9
9
  from ccxt.base.types import Account, Any, Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
10
10
  from typing import List
@@ -27,12 +27,12 @@ from ccxt.base.decimal_to_precision import TICK_SIZE
27
27
  from ccxt.base.precise import Precise
28
28
 
29
29
 
30
- class huobijp(Exchange, ImplicitAPI):
30
+ class bittrade(Exchange, ImplicitAPI):
31
31
 
32
32
  def describe(self) -> Any:
33
- return self.deep_extend(super(huobijp, self).describe(), {
34
- 'id': 'huobijp',
35
- 'name': 'Huobi Japan',
33
+ return self.deep_extend(super(bittrade, self).describe(), {
34
+ 'id': 'bittrade',
35
+ 'name': 'BitTrade',
36
36
  'countries': ['JP'],
37
37
  'rateLimit': 100,
38
38
  'userAgent': self.userAgents['chrome39'],
@@ -108,10 +108,10 @@ class huobijp(Exchange, ImplicitAPI):
108
108
  'v2Public': 'https://{hostname}',
109
109
  'v2Private': 'https://{hostname}',
110
110
  },
111
- 'www': 'https://www.huobi.co.jp',
112
- 'referral': 'https://www.huobi.co.jp/register/?invite_code=znnq3',
113
- 'doc': 'https://api-doc.huobi.co.jp',
114
- 'fees': 'https://www.huobi.co.jp/support/fee',
111
+ 'www': 'https://www.bittrade.co.jp',
112
+ 'referral': 'https://www.bittrade.co.jp/register/?invite_code=znnq3',
113
+ 'doc': 'https://api-doc.bittrade.co.jp',
114
+ 'fees': 'https://www.bittrade.co.jp/ja-jp/support/fee',
115
115
  },
116
116
  'api': {
117
117
  'v2Public': {
@@ -1483,7 +1483,7 @@ class huobijp(Exchange, ImplicitAPI):
1483
1483
  """
1484
1484
  cancels an open order
1485
1485
  :param str id: order id
1486
- :param str symbol: not used by huobijp cancelOrder()
1486
+ :param str symbol: not used by bittrade cancelOrder()
1487
1487
  :param dict [params]: extra parameters specific to the exchange API endpoint
1488
1488
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1489
1489
  """
@@ -1503,7 +1503,7 @@ class huobijp(Exchange, ImplicitAPI):
1503
1503
  """
1504
1504
  cancel multiple orders
1505
1505
  :param str[] ids: order ids
1506
- :param str symbol: not used by huobijp cancelOrders()
1506
+ :param str symbol: not used by bittrade cancelOrders()
1507
1507
  :param dict [params]: extra parameters specific to the exchange API endpoint
1508
1508
  :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1509
1509
  """
@@ -1425,9 +1425,6 @@ class coinbase(Exchange, ImplicitAPI):
1425
1425
  self.v3PublicGetBrokerageMarketProducts(self.extend(params, {'product_type': 'FUTURE'})),
1426
1426
  self.v3PublicGetBrokerageMarketProducts(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1427
1427
  ]
1428
- if self.check_required_credentials(False):
1429
- unresolvedContractPromises.append(self.extend(params, {'product_type': 'FUTURE'}))
1430
- unresolvedContractPromises.append(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'}))
1431
1428
  except Exception as e:
1432
1429
  unresolvedContractPromises = [] # the sync version of ccxt won't have the promise.all line so the request is made here. Some users can't access perpetual products
1433
1430
  promises = await asyncio.gather(*spotUnresolvedPromises)
@@ -1440,8 +1437,8 @@ class coinbase(Exchange, ImplicitAPI):
1440
1437
  fees = self.safe_dict(promises, 1, {})
1441
1438
  expiringFutures = self.safe_dict(contractPromises, 0, {})
1442
1439
  perpetualFutures = self.safe_dict(contractPromises, 1, {})
1443
- expiringFees = self.safe_dict(contractPromises, 2, {})
1444
- perpetualFees = self.safe_dict(contractPromises, 3, {})
1440
+ expiringFees = self.safe_dict(contractPromises, 0, {})
1441
+ perpetualFees = self.safe_dict(contractPromises, 1, {})
1445
1442
  #
1446
1443
  # {
1447
1444
  # "total_volume": 0,