ccxt 4.4.82__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.
- ccxt/__init__.py +3 -9
- ccxt/abstract/blofin.py +8 -0
- ccxt/abstract/btcbox.py +1 -0
- ccxt/abstract/myokx.py +2 -0
- ccxt/abstract/okx.py +2 -0
- ccxt/apex.py +2 -1
- ccxt/ascendex.py +187 -151
- ccxt/async_support/__init__.py +3 -9
- ccxt/async_support/apex.py +2 -1
- ccxt/async_support/ascendex.py +187 -151
- ccxt/async_support/base/exchange.py +51 -24
- ccxt/async_support/base/ws/cache.py +6 -1
- ccxt/async_support/bequant.py +1 -1
- ccxt/async_support/bitget.py +5 -6
- ccxt/async_support/bitmart.py +1 -1
- ccxt/async_support/bitrue.py +14 -32
- ccxt/async_support/bitso.py +33 -0
- ccxt/async_support/bitstamp.py +33 -0
- ccxt/async_support/{huobijp.py → bittrade.py} +11 -11
- ccxt/async_support/blofin.py +145 -14
- ccxt/async_support/btcbox.py +25 -5
- ccxt/async_support/bybit.py +16 -37
- ccxt/async_support/cex.py +2 -4
- ccxt/async_support/coinbase.py +58 -47
- ccxt/async_support/coinbaseexchange.py +141 -32
- ccxt/async_support/coincatch.py +14 -67
- ccxt/async_support/coinex.py +28 -29
- ccxt/async_support/coinlist.py +17 -16
- ccxt/async_support/coinmetro.py +20 -11
- ccxt/async_support/coinone.py +8 -10
- ccxt/async_support/coinsph.py +124 -2
- ccxt/async_support/cryptocom.py +109 -2
- ccxt/async_support/cryptomus.py +42 -80
- ccxt/async_support/delta.py +75 -36
- ccxt/async_support/deribit.py +4 -5
- ccxt/async_support/derive.py +46 -10
- ccxt/async_support/ellipx.py +175 -77
- ccxt/async_support/gate.py +1 -1
- ccxt/async_support/gemini.py +3 -4
- ccxt/async_support/hitbtc.py +56 -65
- ccxt/async_support/hollaex.py +106 -49
- ccxt/async_support/htx.py +20 -43
- ccxt/async_support/hyperliquid.py +6 -6
- ccxt/async_support/kraken.py +27 -23
- ccxt/async_support/kucoinfutures.py +5 -0
- ccxt/async_support/lbank.py +1 -1
- ccxt/async_support/mexc.py +2 -2
- ccxt/async_support/ndax.py +25 -24
- ccxt/async_support/okcoin.py +12 -29
- ccxt/async_support/okx.py +9 -0
- ccxt/async_support/onetrading.py +10 -7
- ccxt/async_support/oxfun.py +40 -110
- ccxt/async_support/paradex.py +123 -4
- ccxt/base/exchange.py +21 -2
- ccxt/base/types.py +3 -0
- ccxt/bequant.py +1 -1
- ccxt/bitget.py +5 -6
- ccxt/bitmart.py +1 -1
- ccxt/bitrue.py +14 -32
- ccxt/bitso.py +33 -0
- ccxt/bitstamp.py +33 -0
- ccxt/{huobijp.py → bittrade.py} +11 -11
- ccxt/blofin.py +145 -14
- ccxt/btcbox.py +24 -5
- ccxt/bybit.py +16 -37
- ccxt/cex.py +2 -4
- ccxt/coinbase.py +58 -47
- ccxt/coinbaseexchange.py +141 -32
- ccxt/coincatch.py +14 -67
- ccxt/coinex.py +28 -29
- ccxt/coinlist.py +17 -16
- ccxt/coinmetro.py +20 -11
- ccxt/coinone.py +8 -10
- ccxt/coinsph.py +124 -2
- ccxt/cryptocom.py +109 -2
- ccxt/cryptomus.py +42 -80
- ccxt/delta.py +75 -36
- ccxt/deribit.py +4 -5
- ccxt/derive.py +46 -10
- ccxt/ellipx.py +175 -77
- ccxt/gate.py +1 -1
- ccxt/gemini.py +3 -4
- ccxt/hitbtc.py +56 -65
- ccxt/hollaex.py +106 -49
- ccxt/htx.py +20 -43
- ccxt/hyperliquid.py +6 -6
- ccxt/kraken.py +27 -23
- ccxt/kucoinfutures.py +5 -0
- ccxt/lbank.py +1 -1
- ccxt/mexc.py +2 -2
- ccxt/ndax.py +25 -24
- ccxt/okcoin.py +12 -29
- ccxt/okx.py +9 -0
- ccxt/onetrading.py +10 -7
- ccxt/oxfun.py +40 -110
- ccxt/paradex.py +123 -4
- ccxt/pro/__init__.py +109 -5
- ccxt/pro/binance.py +32 -33
- ccxt/pro/bithumb.py +5 -3
- ccxt/pro/{huobijp.py → bittrade.py} +3 -3
- ccxt/pro/kraken.py +249 -79
- ccxt/pro/luno.py +6 -5
- ccxt/pro/mexc.py +254 -7
- ccxt/pro/poloniex.py +6 -2
- {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/METADATA +8 -11
- {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/RECORD +110 -121
- ccxt/abstract/bl3p.py +0 -19
- ccxt/abstract/idex.py +0 -26
- ccxt/abstract/kuna.py +0 -182
- ccxt/async_support/base/ws/fast_client.py +0 -97
- ccxt/async_support/bl3p.py +0 -543
- ccxt/async_support/idex.py +0 -1889
- ccxt/async_support/kuna.py +0 -1935
- ccxt/bl3p.py +0 -543
- ccxt/idex.py +0 -1889
- ccxt/kuna.py +0 -1935
- ccxt/pro/idex.py +0 -687
- /ccxt/abstract/{huobijp.py → bittrade.py} +0 -0
- {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/WHEEL +0 -0
- {ccxt-4.4.82.dist-info → ccxt-4.4.86.dist-info}/top_level.txt +0 -0
ccxt/async_support/__init__.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
|
7
|
-
__version__ = '4.4.
|
7
|
+
__version__ = '4.4.86'
|
8
8
|
|
9
9
|
# -----------------------------------------------------------------------------
|
10
10
|
|
@@ -87,8 +87,8 @@ from ccxt.async_support.bitrue import bitrue
|
|
87
87
|
from ccxt.async_support.bitso import bitso # noqa: F401
|
88
88
|
from ccxt.async_support.bitstamp import bitstamp # noqa: F401
|
89
89
|
from ccxt.async_support.bitteam import bitteam # noqa: F401
|
90
|
+
from ccxt.async_support.bittrade import bittrade # noqa: F401
|
90
91
|
from ccxt.async_support.bitvavo import bitvavo # noqa: F401
|
91
|
-
from ccxt.async_support.bl3p import bl3p # noqa: F401
|
92
92
|
from ccxt.async_support.blockchaincom import blockchaincom # noqa: F401
|
93
93
|
from ccxt.async_support.blofin import blofin # noqa: F401
|
94
94
|
from ccxt.async_support.btcalpha import btcalpha # noqa: F401
|
@@ -128,16 +128,13 @@ from ccxt.async_support.hitbtc import hitbtc
|
|
128
128
|
from ccxt.async_support.hollaex import hollaex # noqa: F401
|
129
129
|
from ccxt.async_support.htx import htx # noqa: F401
|
130
130
|
from ccxt.async_support.huobi import huobi # noqa: F401
|
131
|
-
from ccxt.async_support.huobijp import huobijp # noqa: F401
|
132
131
|
from ccxt.async_support.hyperliquid import hyperliquid # noqa: F401
|
133
|
-
from ccxt.async_support.idex import idex # noqa: F401
|
134
132
|
from ccxt.async_support.independentreserve import independentreserve # noqa: F401
|
135
133
|
from ccxt.async_support.indodax import indodax # noqa: F401
|
136
134
|
from ccxt.async_support.kraken import kraken # noqa: F401
|
137
135
|
from ccxt.async_support.krakenfutures import krakenfutures # noqa: F401
|
138
136
|
from ccxt.async_support.kucoin import kucoin # noqa: F401
|
139
137
|
from ccxt.async_support.kucoinfutures import kucoinfutures # noqa: F401
|
140
|
-
from ccxt.async_support.kuna import kuna # noqa: F401
|
141
138
|
from ccxt.async_support.latoken import latoken # noqa: F401
|
142
139
|
from ccxt.async_support.lbank import lbank # noqa: F401
|
143
140
|
from ccxt.async_support.luno import luno # noqa: F401
|
@@ -196,8 +193,8 @@ exchanges = [
|
|
196
193
|
'bitso',
|
197
194
|
'bitstamp',
|
198
195
|
'bitteam',
|
196
|
+
'bittrade',
|
199
197
|
'bitvavo',
|
200
|
-
'bl3p',
|
201
198
|
'blockchaincom',
|
202
199
|
'blofin',
|
203
200
|
'btcalpha',
|
@@ -237,16 +234,13 @@ exchanges = [
|
|
237
234
|
'hollaex',
|
238
235
|
'htx',
|
239
236
|
'huobi',
|
240
|
-
'huobijp',
|
241
237
|
'hyperliquid',
|
242
|
-
'idex',
|
243
238
|
'independentreserve',
|
244
239
|
'indodax',
|
245
240
|
'kraken',
|
246
241
|
'krakenfutures',
|
247
242
|
'kucoin',
|
248
243
|
'kucoinfutures',
|
249
|
-
'kuna',
|
250
244
|
'latoken',
|
251
245
|
'lbank',
|
252
246
|
'luno',
|
ccxt/async_support/apex.py
CHANGED
@@ -1077,9 +1077,10 @@ class apex(Exchange, ImplicitAPI):
|
|
1077
1077
|
for i in range(0, len(resultList)):
|
1078
1078
|
entry = resultList[i]
|
1079
1079
|
timestamp = self.safe_integer(entry, 'fundingTimestamp')
|
1080
|
+
marketId = self.safe_string(entry, 'symbol')
|
1080
1081
|
rates.append({
|
1081
1082
|
'info': entry,
|
1082
|
-
'symbol': self.
|
1083
|
+
'symbol': self.safe_symbol(marketId, market),
|
1083
1084
|
'fundingRate': self.safe_number(entry, 'rate'),
|
1084
1085
|
'timestamp': timestamp,
|
1085
1086
|
'datetime': self.iso8601(timestamp),
|
ccxt/async_support/ascendex.py
CHANGED
@@ -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,
|
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
|
-
|
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
|
-
#
|
543
|
-
#
|
544
|
-
#
|
545
|
-
#
|
546
|
-
#
|
547
|
-
#
|
548
|
-
#
|
549
|
-
#
|
550
|
-
#
|
551
|
-
#
|
552
|
-
#
|
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
|
-
|
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(
|
568
|
-
|
569
|
-
|
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
|
-
|
572
|
-
precision = self.parse_number(self.parse_precision(
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
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':
|
568
|
+
'margin': None,
|
598
569
|
'name': self.safe_string(currency, 'assetName'),
|
599
|
-
'active':
|
600
|
-
'deposit':
|
601
|
-
'withdraw':
|
602
|
-
'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':
|
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':
|
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
|
-
|
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
|
-
|
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(
|
724
|
-
|
725
|
-
|
726
|
-
|
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
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
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'
|
767
|
-
'spot':
|
768
|
-
'margin':
|
769
|
-
'swap':
|
802
|
+
'type': 'swap',
|
803
|
+
'spot': False,
|
804
|
+
'margin': None,
|
805
|
+
'swap': True,
|
770
806
|
'future': False,
|
771
807
|
'option': False,
|
772
|
-
'active':
|
773
|
-
'contract':
|
808
|
+
'active': self.safe_string(market, 'status') == 'Normal',
|
809
|
+
'contract': True,
|
774
810
|
'linear': linear,
|
775
|
-
'inverse':
|
811
|
+
'inverse': inverse,
|
776
812
|
'taker': fee,
|
777
813
|
'maker': fee,
|
778
|
-
'contractSize': self.parse_number('1')
|
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(
|
785
|
-
'price': self.safe_number(
|
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.
|
5
|
+
__version__ = '4.4.86'
|
6
6
|
|
7
7
|
# -----------------------------------------------------------------------------
|
8
8
|
|
@@ -34,7 +34,7 @@ from ccxt.base.exchange import Exchange as BaseExchange, ArgumentsRequired
|
|
34
34
|
# -----------------------------------------------------------------------------
|
35
35
|
|
36
36
|
from ccxt.async_support.base.ws.functions import inflate, inflate64, gunzip
|
37
|
-
from ccxt.async_support.base.ws.
|
37
|
+
from ccxt.async_support.base.ws.aiohttp_client import AiohttpClient
|
38
38
|
from ccxt.async_support.base.ws.future import Future
|
39
39
|
from ccxt.async_support.base.ws.order_book import OrderBook, IndexedOrderBook, CountedOrderBook
|
40
40
|
|
@@ -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
|
-
|
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:
|
@@ -279,7 +285,28 @@ class Exchange(BaseExchange):
|
|
279
285
|
markets = await self.fetch_markets(params)
|
280
286
|
return self.set_markets(markets, currencies)
|
281
287
|
|
288
|
+
|
282
289
|
async def load_markets(self, reload=False, params={}):
|
290
|
+
"""
|
291
|
+
Loads and prepares the markets for trading.
|
292
|
+
|
293
|
+
Args:
|
294
|
+
reload (bool): If True, the markets will be reloaded from the exchange.
|
295
|
+
params (dict): Additional exchange-specific parameters for the request.
|
296
|
+
|
297
|
+
Returns:
|
298
|
+
dict: A dictionary of markets.
|
299
|
+
|
300
|
+
Raises:
|
301
|
+
Exception: If the markets cannot be loaded or prepared.
|
302
|
+
|
303
|
+
Notes:
|
304
|
+
This method is asynchronous.
|
305
|
+
It ensures that the markets are only loaded once, even if called multiple times.
|
306
|
+
If the markets are already loaded and `reload` is False or not provided, it returns the existing markets.
|
307
|
+
If a reload is in progress, it waits for completion before returning.
|
308
|
+
If an error occurs during loading or preparation, an exception is raised.
|
309
|
+
"""
|
283
310
|
if (reload and not self.reloading_markets) or not self.markets_loading:
|
284
311
|
self.reloading_markets = True
|
285
312
|
coroutine = self.load_markets_helper(reload, params)
|
@@ -387,20 +414,15 @@ class Exchange(BaseExchange):
|
|
387
414
|
'throttle': Throttler(self.tokenBucket, self.asyncio_loop),
|
388
415
|
'asyncio_loop': self.asyncio_loop,
|
389
416
|
}, ws_options)
|
390
|
-
|
391
|
-
|
417
|
+
# we use aiohttp instead of fastClient now because of this
|
418
|
+
# https://github.com/ccxt/ccxt/pull/25995
|
419
|
+
self.clients[url] = AiohttpClient(url, on_message, on_error, on_close, on_connected, options)
|
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
|
392
424
|
return self.clients[url]
|
393
425
|
|
394
|
-
def get_ws_proxy(self):
|
395
|
-
httpProxy, httpsProxy, socksProxy = self.check_ws_proxy_settings()
|
396
|
-
if httpProxy:
|
397
|
-
return httpProxy
|
398
|
-
elif httpsProxy:
|
399
|
-
return httpsProxy
|
400
|
-
elif socksProxy:
|
401
|
-
return socksProxy
|
402
|
-
return None
|
403
|
-
|
404
426
|
def delay(self, timeout, method, *args):
|
405
427
|
return self.asyncio_loop.call_later(timeout / 1000, self.spawn, method, *args)
|
406
428
|
|
@@ -463,8 +485,13 @@ class Exchange(BaseExchange):
|
|
463
485
|
if not subscribed:
|
464
486
|
client.subscriptions[subscribe_hash] = subscription or True
|
465
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)
|
466
493
|
connected = client.connected if client.connected.done() \
|
467
|
-
else asyncio.ensure_future(client.connect(
|
494
|
+
else asyncio.ensure_future(client.connect(selected_session, backoff_delay))
|
468
495
|
|
469
496
|
def after(fut):
|
470
497
|
# todo: decouple signing from subscriptions
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import collections
|
2
|
+
import logging
|
2
3
|
|
4
|
+
logger = logging.getLogger(__name__)
|
3
5
|
|
4
6
|
class Delegate:
|
5
7
|
def __init__(self, name, delegated):
|
@@ -151,7 +153,10 @@ class ArrayCacheBySymbolById(ArrayCache):
|
|
151
153
|
if len(self._deque) == self._deque.maxlen:
|
152
154
|
delete_item = self._deque.popleft()
|
153
155
|
self._index.popleft()
|
154
|
-
|
156
|
+
try:
|
157
|
+
del self.hashmap[delete_item['symbol']][delete_item['id']]
|
158
|
+
except Exception as e:
|
159
|
+
logger.error(f"Error deleting item from hashmap: {delete_item}. Error:{e}")
|
155
160
|
self._deque.append(item)
|
156
161
|
self._index.append(item['id'])
|
157
162
|
if self._clear_all_updates:
|