ccxt-ir 4.3.46.0.3__py2.py3-none-any.whl → 4.5.0__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 +39 -35
- ccxt/abantether.py +8 -8
- ccxt/abstract/alpaca.py +4 -0
- ccxt/abstract/apex.py +31 -0
- ccxt/abstract/bigone.py +1 -1
- ccxt/abstract/binance.py +106 -48
- ccxt/abstract/binancecoinm.py +106 -48
- ccxt/abstract/binanceus.py +141 -83
- ccxt/abstract/binanceusdm.py +106 -48
- ccxt/abstract/bingx.py +50 -1
- ccxt/abstract/bitbank.py +5 -0
- ccxt/abstract/bitfinex.py +136 -65
- ccxt/abstract/bitflyer.py +1 -0
- ccxt/abstract/bitget.py +67 -0
- ccxt/abstract/bitmart.py +19 -1
- ccxt/abstract/bitopro.py +1 -0
- ccxt/abstract/bitrue.py +68 -68
- ccxt/abstract/bitstamp.py +1 -0
- ccxt/abstract/blofin.py +30 -0
- ccxt/abstract/btcbox.py +2 -0
- ccxt/abstract/bybit.py +28 -13
- ccxt/abstract/cex.py +28 -29
- ccxt/abstract/coinbaseexchange.py +1 -0
- ccxt/abstract/coinbaseinternational.py +1 -1
- ccxt/abstract/cryptocom.py +16 -0
- ccxt/abstract/cryptomus.py +20 -0
- ccxt/abstract/defx.py +69 -0
- ccxt/abstract/deribit.py +1 -0
- ccxt/abstract/derive.py +117 -0
- ccxt/abstract/digifinex.py +1 -0
- ccxt/abstract/ellipx.py +25 -0
- ccxt/abstract/foxbit.py +26 -0
- ccxt/abstract/gate.py +19 -0
- ccxt/abstract/gateio.py +19 -0
- ccxt/abstract/gemini.py +1 -0
- ccxt/abstract/hibachi.py +26 -0
- ccxt/abstract/hyperliquid.py +1 -1
- ccxt/abstract/independentreserve.py +6 -0
- ccxt/abstract/kraken.py +1 -0
- ccxt/abstract/krakenfutures.py +4 -0
- ccxt/abstract/kucoin.py +10 -0
- ccxt/abstract/kucoinfutures.py +18 -0
- ccxt/abstract/lbank.py +2 -1
- ccxt/abstract/luno.py +1 -0
- ccxt/abstract/mexc.py +2 -0
- ccxt/abstract/modetrade.py +119 -0
- ccxt/abstract/myokx.py +349 -0
- ccxt/abstract/oceanex.py +5 -0
- ccxt/abstract/okx.py +25 -0
- ccxt/abstract/okxus.py +349 -0
- ccxt/abstract/onetrading.py +0 -12
- ccxt/abstract/paradex.py +23 -0
- ccxt/abstract/phemex.py +2 -0
- ccxt/abstract/poloniex.py +36 -0
- ccxt/abstract/tradeogre.py +3 -1
- ccxt/abstract/upbit.py +51 -34
- ccxt/abstract/whitebit.py +16 -0
- ccxt/abstract/woo.py +64 -6
- ccxt/abstract/xt.py +10 -5
- ccxt/afratether.py +7 -7
- ccxt/alpaca.py +828 -51
- ccxt/apex.py +1875 -0
- ccxt/arzinja.py +7 -7
- ccxt/arzplus.py +9 -9
- ccxt/ascendex.py +501 -306
- ccxt/async_support/__init__.py +39 -35
- ccxt/async_support/abantether.py +8 -8
- ccxt/async_support/afratether.py +9 -9
- ccxt/async_support/alpaca.py +828 -51
- ccxt/async_support/apex.py +1875 -0
- ccxt/async_support/arzinja.py +10 -10
- ccxt/async_support/arzplus.py +12 -12
- ccxt/async_support/ascendex.py +502 -306
- ccxt/async_support/base/exchange.py +303 -89
- ccxt/async_support/base/ws/cache.py +9 -3
- ccxt/async_support/base/ws/client.py +173 -38
- ccxt/async_support/base/ws/future.py +25 -37
- ccxt/async_support/bequant.py +5 -3
- ccxt/async_support/bigone.py +279 -144
- ccxt/async_support/binance.py +2347 -1158
- ccxt/async_support/binancecoinm.py +9 -3
- ccxt/async_support/binanceus.py +17 -3
- ccxt/async_support/binanceusdm.py +9 -4
- ccxt/async_support/bingx.py +2962 -920
- ccxt/async_support/bit2c.py +147 -27
- ccxt/async_support/bitbank.py +151 -23
- ccxt/async_support/bitbns.py +104 -30
- ccxt/async_support/bitfinex.py +3291 -1113
- ccxt/async_support/bitflyer.py +202 -27
- ccxt/async_support/bitget.py +3683 -1538
- ccxt/async_support/bithumb.py +195 -38
- ccxt/async_support/bitimen.py +12 -12
- ccxt/async_support/bitir.py +38 -38
- ccxt/async_support/bitmart.py +1288 -350
- ccxt/async_support/bitmex.py +260 -75
- ccxt/async_support/bitopro.py +262 -62
- ccxt/async_support/bitpin.py +17 -16
- ccxt/async_support/bitrue.py +459 -290
- ccxt/async_support/bitso.py +199 -54
- ccxt/async_support/bitstamp.py +230 -96
- ccxt/async_support/bitteam.py +167 -25
- ccxt/async_support/{huobijp.py → bittrade.py} +158 -30
- ccxt/async_support/bitvavo.py +213 -49
- ccxt/async_support/blockchaincom.py +160 -46
- ccxt/async_support/blofin.py +502 -120
- ccxt/async_support/btcalpha.py +169 -31
- ccxt/async_support/btcbox.py +292 -23
- ccxt/async_support/btcmarkets.py +211 -58
- ccxt/async_support/btcturk.py +161 -38
- ccxt/async_support/bybit.py +1775 -1030
- ccxt/async_support/cex.py +1440 -1303
- ccxt/async_support/coinbase.py +724 -212
- ccxt/async_support/coinbaseadvanced.py +2 -1
- ccxt/async_support/coinbaseexchange.py +388 -89
- ccxt/async_support/coinbaseinternational.py +412 -57
- ccxt/async_support/coincatch.py +177 -78
- ccxt/async_support/coincheck.py +135 -19
- ccxt/async_support/coinex.py +606 -232
- ccxt/async_support/coinmate.py +189 -63
- ccxt/async_support/coinmetro.py +195 -54
- ccxt/async_support/coinone.py +158 -51
- ccxt/async_support/coinsph.py +336 -61
- ccxt/async_support/coinspot.py +151 -52
- ccxt/async_support/cryptocom.py +661 -111
- ccxt/async_support/cryptomus.py +1137 -0
- ccxt/async_support/defx.py +2071 -0
- ccxt/async_support/delta.py +299 -99
- ccxt/async_support/deribit.py +348 -126
- ccxt/async_support/derive.py +2572 -0
- ccxt/async_support/digifinex.py +430 -214
- ccxt/async_support/ellipx.py +2029 -0
- ccxt/async_support/eterex.py +10 -10
- ccxt/async_support/excoino.py +31 -31
- ccxt/async_support/exir.py +14 -14
- ccxt/async_support/exmo.py +344 -131
- ccxt/async_support/exnovin.py +10 -10
- ccxt/async_support/farhadexchange.py +12 -12
- ccxt/async_support/fmfwio.py +2 -1
- ccxt/async_support/foxbit.py +1935 -0
- ccxt/async_support/gate.py +1351 -529
- ccxt/async_support/gateio.py +2 -1
- ccxt/async_support/gemini.py +144 -39
- ccxt/async_support/hashkey.py +152 -109
- ccxt/async_support/hibachi.py +2080 -0
- ccxt/async_support/hitbtc.py +395 -167
- ccxt/async_support/hitobit.py +12 -12
- ccxt/async_support/hollaex.py +307 -119
- ccxt/async_support/htx.py +851 -383
- ccxt/async_support/huobi.py +2 -1
- ccxt/async_support/hyperliquid.py +1848 -536
- ccxt/async_support/independentreserve.py +288 -15
- ccxt/async_support/indodax.py +190 -33
- ccxt/async_support/jibitex.py +12 -12
- ccxt/async_support/kraken.py +795 -351
- ccxt/async_support/krakenfutures.py +214 -62
- ccxt/async_support/kucoin.py +715 -396
- ccxt/async_support/kucoinfutures.py +652 -89
- ccxt/async_support/latoken.py +217 -113
- ccxt/async_support/lbank.py +425 -97
- ccxt/async_support/luno.py +382 -35
- ccxt/async_support/mercado.py +113 -6
- ccxt/async_support/mexc.py +874 -437
- ccxt/async_support/modetrade.py +2818 -0
- ccxt/async_support/myokx.py +54 -0
- ccxt/async_support/ndax.py +221 -64
- ccxt/async_support/nobitex.py +31 -37
- ccxt/async_support/novadax.py +190 -34
- ccxt/async_support/oceanex.py +217 -28
- ccxt/async_support/okcoin.py +253 -145
- ccxt/async_support/okexchange.py +11 -11
- ccxt/async_support/okx.py +1088 -351
- ccxt/async_support/okxus.py +54 -0
- ccxt/async_support/ompfinex.py +25 -24
- ccxt/async_support/onetrading.py +213 -392
- ccxt/async_support/oxfun.py +245 -166
- ccxt/async_support/p2b.py +151 -29
- ccxt/async_support/paradex.py +562 -49
- ccxt/async_support/paymium.py +82 -19
- ccxt/async_support/phemex.py +713 -172
- ccxt/async_support/poloniex.py +1602 -283
- ccxt/async_support/probit.py +224 -95
- ccxt/async_support/ramzinex.py +30 -27
- ccxt/async_support/sarmayex.py +9 -9
- ccxt/async_support/sarrafex.py +13 -13
- ccxt/async_support/tabdeal.py +14 -13
- ccxt/async_support/tetherland.py +9 -9
- ccxt/async_support/timex.py +210 -51
- ccxt/async_support/tokocrypto.py +167 -47
- ccxt/async_support/tradeogre.py +266 -31
- ccxt/async_support/twox.py +9 -9
- ccxt/async_support/ubitex.py +12 -12
- ccxt/async_support/upbit.py +568 -165
- ccxt/async_support/vertex.py +160 -32
- ccxt/async_support/wallex.py +12 -12
- ccxt/async_support/wavesexchange.py +165 -30
- ccxt/async_support/whitebit.py +975 -127
- ccxt/async_support/woo.py +1918 -1016
- ccxt/async_support/woofipro.py +433 -141
- ccxt/async_support/xt.py +649 -193
- ccxt/async_support/yobit.py +195 -70
- ccxt/async_support/zaif.py +91 -15
- ccxt/async_support/zonda.py +151 -36
- ccxt/base/decimal_to_precision.py +14 -10
- ccxt/base/errors.py +49 -18
- ccxt/base/exchange.py +1556 -450
- ccxt/base/precise.py +10 -0
- ccxt/base/types.py +114 -6
- ccxt/bequant.py +5 -3
- ccxt/bigone.py +279 -144
- ccxt/binance.py +2347 -1158
- ccxt/binancecoinm.py +9 -3
- ccxt/binanceus.py +17 -3
- ccxt/binanceusdm.py +9 -4
- ccxt/bingx.py +2962 -920
- ccxt/bit2c.py +147 -27
- ccxt/bitbank.py +151 -23
- ccxt/bitbns.py +104 -30
- ccxt/bitfinex.py +3290 -1113
- ccxt/bitflyer.py +202 -27
- ccxt/bitget.py +3683 -1538
- ccxt/bithumb.py +194 -38
- ccxt/bitimen.py +9 -9
- ccxt/bitir.py +35 -35
- ccxt/bitmart.py +1288 -350
- ccxt/bitmex.py +260 -75
- ccxt/bitopro.py +262 -62
- ccxt/bitpin.py +15 -14
- ccxt/bitrue.py +459 -290
- ccxt/bitso.py +199 -54
- ccxt/bitstamp.py +230 -96
- ccxt/bitteam.py +167 -25
- ccxt/{huobijp.py → bittrade.py} +158 -30
- ccxt/bitvavo.py +213 -49
- ccxt/blockchaincom.py +160 -46
- ccxt/blofin.py +502 -120
- ccxt/btcalpha.py +169 -31
- ccxt/btcbox.py +291 -23
- ccxt/btcmarkets.py +211 -58
- ccxt/btcturk.py +161 -38
- ccxt/bybit.py +1775 -1030
- ccxt/cex.py +1439 -1303
- ccxt/coinbase.py +724 -212
- ccxt/coinbaseadvanced.py +2 -1
- ccxt/coinbaseexchange.py +388 -89
- ccxt/coinbaseinternational.py +412 -57
- ccxt/coincatch.py +177 -78
- ccxt/coincheck.py +135 -19
- ccxt/coinex.py +606 -232
- ccxt/coinmate.py +189 -63
- ccxt/coinmetro.py +194 -54
- ccxt/coinone.py +158 -51
- ccxt/coinsph.py +336 -61
- ccxt/coinspot.py +151 -52
- ccxt/cryptocom.py +661 -111
- ccxt/cryptomus.py +1137 -0
- ccxt/defx.py +2070 -0
- ccxt/delta.py +299 -99
- ccxt/deribit.py +348 -126
- ccxt/derive.py +2571 -0
- ccxt/digifinex.py +430 -214
- ccxt/ellipx.py +2029 -0
- ccxt/eterex.py +7 -7
- ccxt/excoino.py +29 -29
- ccxt/exir.py +11 -11
- ccxt/exmo.py +343 -131
- ccxt/exnovin.py +8 -8
- ccxt/farhadexchange.py +10 -10
- ccxt/fmfwio.py +2 -1
- ccxt/foxbit.py +1935 -0
- ccxt/gate.py +1351 -529
- ccxt/gateio.py +2 -1
- ccxt/gemini.py +144 -39
- ccxt/hashkey.py +152 -109
- ccxt/hibachi.py +2079 -0
- ccxt/hitbtc.py +395 -167
- ccxt/hitobit.py +9 -9
- ccxt/hollaex.py +307 -119
- ccxt/htx.py +851 -383
- ccxt/huobi.py +2 -1
- ccxt/hyperliquid.py +1848 -536
- ccxt/independentreserve.py +287 -15
- ccxt/indodax.py +190 -33
- ccxt/jibitex.py +9 -9
- ccxt/kraken.py +794 -351
- ccxt/krakenfutures.py +214 -62
- ccxt/kucoin.py +715 -396
- ccxt/kucoinfutures.py +652 -89
- ccxt/latoken.py +217 -113
- ccxt/lbank.py +425 -97
- ccxt/luno.py +382 -35
- ccxt/mercado.py +113 -6
- ccxt/mexc.py +873 -437
- ccxt/modetrade.py +2818 -0
- ccxt/myokx.py +54 -0
- ccxt/ndax.py +221 -64
- ccxt/nobitex.py +29 -35
- ccxt/novadax.py +190 -34
- ccxt/oceanex.py +217 -28
- ccxt/okcoin.py +253 -145
- ccxt/okexchange.py +9 -9
- ccxt/okx.py +1088 -351
- ccxt/okxus.py +54 -0
- ccxt/ompfinex.py +22 -21
- ccxt/onetrading.py +213 -392
- ccxt/oxfun.py +245 -166
- ccxt/p2b.py +151 -29
- ccxt/paradex.py +562 -49
- ccxt/paymium.py +82 -19
- ccxt/phemex.py +712 -172
- ccxt/poloniex.py +1601 -283
- ccxt/pro/__init__.py +76 -17
- ccxt/pro/alpaca.py +21 -6
- ccxt/pro/apex.py +984 -0
- ccxt/pro/ascendex.py +58 -10
- ccxt/pro/bequant.py +6 -1
- ccxt/pro/binance.py +728 -156
- ccxt/pro/binancecoinm.py +6 -2
- ccxt/pro/binanceus.py +8 -4
- ccxt/pro/binanceusdm.py +7 -2
- ccxt/pro/bingx.py +333 -142
- ccxt/pro/bitfinex.py +727 -262
- ccxt/pro/bitget.py +570 -79
- ccxt/pro/bithumb.py +20 -6
- ccxt/pro/bitmart.py +216 -87
- ccxt/pro/bitmex.py +47 -9
- ccxt/pro/bitopro.py +26 -14
- ccxt/pro/bitrue.py +22 -22
- ccxt/pro/bitstamp.py +54 -21
- ccxt/pro/{huobijp.py → bittrade.py} +7 -6
- ccxt/pro/bitvavo.py +191 -67
- ccxt/pro/blockchaincom.py +21 -8
- ccxt/pro/blofin.py +9 -1
- ccxt/pro/bybit.py +632 -245
- ccxt/pro/cex.py +59 -24
- ccxt/pro/coinbase.py +102 -73
- ccxt/pro/coinbaseadvanced.py +2 -1
- ccxt/pro/coinbaseexchange.py +8 -8
- ccxt/pro/coinbaseinternational.py +181 -25
- ccxt/pro/coincatch.py +6 -7
- ccxt/pro/coincheck.py +11 -6
- ccxt/pro/coinex.py +967 -665
- ccxt/pro/coinone.py +16 -9
- ccxt/pro/cryptocom.py +448 -45
- ccxt/pro/defx.py +831 -0
- ccxt/pro/deribit.py +150 -14
- ccxt/pro/derive.py +704 -0
- ccxt/pro/exmo.py +239 -6
- ccxt/pro/gate.py +623 -65
- ccxt/pro/gateio.py +2 -1
- ccxt/pro/gemini.py +27 -11
- ccxt/pro/hashkey.py +2 -2
- ccxt/pro/hitbtc.py +196 -91
- ccxt/pro/hollaex.py +23 -7
- ccxt/pro/htx.py +51 -14
- ccxt/pro/huobi.py +2 -1
- ccxt/pro/hyperliquid.py +591 -27
- ccxt/pro/independentreserve.py +9 -6
- ccxt/pro/kraken.py +640 -320
- ccxt/pro/krakenfutures.py +62 -35
- ccxt/pro/kucoin.py +267 -46
- ccxt/pro/kucoinfutures.py +165 -21
- ccxt/pro/lbank.py +102 -21
- ccxt/pro/luno.py +12 -8
- ccxt/pro/mexc.py +877 -111
- ccxt/pro/modetrade.py +1271 -0
- ccxt/pro/myokx.py +38 -0
- ccxt/pro/ndax.py +15 -2
- ccxt/pro/okcoin.py +23 -4
- ccxt/pro/okx.py +573 -98
- ccxt/pro/okxus.py +38 -0
- ccxt/pro/onetrading.py +30 -13
- ccxt/pro/oxfun.py +131 -27
- ccxt/pro/p2b.py +88 -22
- ccxt/pro/paradex.py +3 -3
- ccxt/pro/phemex.py +75 -21
- ccxt/pro/poloniex.py +124 -41
- ccxt/pro/probit.py +87 -80
- ccxt/pro/tradeogre.py +272 -0
- ccxt/pro/upbit.py +152 -12
- ccxt/pro/vertex.py +8 -3
- ccxt/pro/whitebit.py +58 -5
- ccxt/pro/woo.py +228 -37
- ccxt/pro/woofipro.py +106 -18
- ccxt/pro/xt.py +111 -5
- ccxt/probit.py +224 -95
- ccxt/protobuf/__init__.py +0 -0
- ccxt/protobuf/mexc/PrivateAccountV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PrivateDealsV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PrivateOrdersV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PublicAggreBookTickerV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PublicAggreDealsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicAggreDepthsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicBookTickerBatchV3Api_pb2.py +38 -0
- ccxt/protobuf/mexc/PublicBookTickerV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PublicDealsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicIncreaseDepthsBatchV3Api_pb2.py +38 -0
- ccxt/protobuf/mexc/PublicIncreaseDepthsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicLimitDepthsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicMiniTickerV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PublicMiniTickersV3Api_pb2.py +38 -0
- ccxt/protobuf/mexc/PublicSpotKlineV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PushDataV3ApiWrapper_pb2.py +52 -0
- ccxt/protobuf/mexc/__init__.py +0 -0
- ccxt/ramzinex.py +28 -25
- ccxt/sarmayex.py +7 -7
- ccxt/sarrafex.py +10 -10
- ccxt/static_dependencies/__init__.py +1 -1
- ccxt/static_dependencies/lark/py.typed +0 -0
- ccxt/static_dependencies/marshmallow/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- ccxt/tabdeal.py +12 -11
- ccxt/test/tests_async.py +261 -57
- ccxt/test/tests_helpers.py +1 -3
- ccxt/test/tests_init.py +4 -3
- ccxt/test/tests_sync.py +261 -57
- ccxt/tetherland.py +7 -7
- ccxt/timex.py +210 -51
- ccxt/tokocrypto.py +167 -47
- ccxt/tradeogre.py +266 -31
- ccxt/twox.py +7 -7
- ccxt/ubitex.py +9 -9
- ccxt/upbit.py +568 -165
- ccxt/vertex.py +160 -32
- ccxt/wallex.py +9 -9
- ccxt/wavesexchange.py +165 -30
- ccxt/whitebit.py +975 -127
- ccxt/woo.py +1917 -1016
- ccxt/woofipro.py +432 -141
- ccxt/xt.py +649 -193
- ccxt/yobit.py +194 -70
- ccxt/zaif.py +91 -15
- ccxt/zonda.py +151 -36
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.0.dist-info}/METADATA +225 -73
- ccxt_ir-4.5.0.dist-info/RECORD +743 -0
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.0.dist-info}/WHEEL +1 -1
- ccxt/__test__.py +0 -7
- ccxt/abstract/ace.py +0 -15
- ccxt/abstract/bitbay.py +0 -53
- ccxt/abstract/bitcoincom.py +0 -115
- ccxt/abstract/bitfinex2.py +0 -139
- ccxt/abstract/bitpanda.py +0 -35
- ccxt/abstract/bl3p.py +0 -19
- ccxt/abstract/coinlist.py +0 -54
- ccxt/abstract/currencycom.py +0 -68
- ccxt/abstract/hitbtc3.py +0 -115
- ccxt/abstract/idex.py +0 -26
- ccxt/abstract/kuna.py +0 -182
- ccxt/abstract/lykke.py +0 -29
- ccxt/abstract/poloniexfutures.py +0 -48
- ccxt/abstract/wazirx.py +0 -30
- ccxt/ace.py +0 -1012
- ccxt/async_support/ace.py +0 -1012
- ccxt/async_support/base/ws/aiohttp_client.py +0 -125
- ccxt/async_support/base/ws/fast_client.py +0 -96
- ccxt/async_support/bitbay.py +0 -17
- ccxt/async_support/bitcoincom.py +0 -17
- ccxt/async_support/bitfinex2.py +0 -3552
- ccxt/async_support/bitpanda.py +0 -16
- ccxt/async_support/bl3p.py +0 -485
- ccxt/async_support/coinlist.py +0 -2243
- ccxt/async_support/currencycom.py +0 -1950
- ccxt/async_support/hitbtc3.py +0 -16
- ccxt/async_support/idex.py +0 -1766
- ccxt/async_support/kuna.py +0 -1841
- ccxt/async_support/lykke.py +0 -1270
- ccxt/async_support/poloniexfutures.py +0 -1717
- ccxt/async_support/wazirx.py +0 -1224
- ccxt/bitbay.py +0 -17
- ccxt/bitcoincom.py +0 -17
- ccxt/bitfinex2.py +0 -3552
- ccxt/bitpanda.py +0 -16
- ccxt/bl3p.py +0 -485
- ccxt/coinlist.py +0 -2243
- ccxt/currencycom.py +0 -1950
- ccxt/hitbtc3.py +0 -16
- ccxt/idex.py +0 -1766
- ccxt/kuna.py +0 -1841
- ccxt/lykke.py +0 -1270
- ccxt/poloniexfutures.py +0 -1717
- ccxt/pro/bitcoincom.py +0 -34
- ccxt/pro/bitfinex2.py +0 -1083
- ccxt/pro/bitpanda.py +0 -15
- ccxt/pro/currencycom.py +0 -536
- ccxt/pro/idex.py +0 -672
- ccxt/pro/poloniexfutures.py +0 -990
- ccxt/pro/wazirx.py +0 -749
- ccxt/test/base/__init__.py +0 -29
- ccxt/test/base/test_account.py +0 -26
- ccxt/test/base/test_balance.py +0 -56
- ccxt/test/base/test_borrow_interest.py +0 -35
- ccxt/test/base/test_borrow_rate.py +0 -32
- ccxt/test/base/test_calculate_fee.py +0 -51
- ccxt/test/base/test_crypto.py +0 -127
- ccxt/test/base/test_currency.py +0 -76
- ccxt/test/base/test_datetime.py +0 -109
- ccxt/test/base/test_decimal_to_precision.py +0 -392
- ccxt/test/base/test_deep_extend.py +0 -68
- ccxt/test/base/test_deposit_withdrawal.py +0 -50
- ccxt/test/base/test_exchange_datetime_functions.py +0 -76
- ccxt/test/base/test_funding_rate_history.py +0 -29
- ccxt/test/base/test_last_price.py +0 -31
- ccxt/test/base/test_ledger_entry.py +0 -45
- ccxt/test/base/test_ledger_item.py +0 -48
- ccxt/test/base/test_leverage_tier.py +0 -33
- ccxt/test/base/test_liquidation.py +0 -50
- ccxt/test/base/test_margin_mode.py +0 -24
- ccxt/test/base/test_margin_modification.py +0 -35
- ccxt/test/base/test_market.py +0 -193
- ccxt/test/base/test_number.py +0 -411
- ccxt/test/base/test_ohlcv.py +0 -33
- ccxt/test/base/test_open_interest.py +0 -32
- ccxt/test/base/test_order.py +0 -64
- ccxt/test/base/test_order_book.py +0 -69
- ccxt/test/base/test_position.py +0 -60
- ccxt/test/base/test_shared_methods.py +0 -353
- ccxt/test/base/test_status.py +0 -24
- ccxt/test/base/test_throttle.py +0 -126
- ccxt/test/base/test_ticker.py +0 -92
- ccxt/test/base/test_trade.py +0 -47
- ccxt/test/base/test_trading_fee.py +0 -26
- ccxt/test/base/test_transaction.py +0 -39
- ccxt/test/test_async.py +0 -1649
- ccxt/test/test_sync.py +0 -1648
- ccxt/wazirx.py +0 -1224
- ccxt_ir-4.3.46.0.3.dist-info/RECORD +0 -773
- /ccxt/abstract/{huobijp.py → bittrade.py} +0 -0
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.0.dist-info/licenses}/LICENSE.txt +0 -0
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.0.dist-info}/top_level.txt +0 -0
|
@@ -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):
|
|
@@ -23,6 +25,7 @@ class BaseCache(list):
|
|
|
23
25
|
__contains__ = Delegate('__contains__', '_deque')
|
|
24
26
|
__reversed__ = Delegate('__reversed__', '_deque')
|
|
25
27
|
clear = Delegate('clear', '_deque')
|
|
28
|
+
pop = Delegate('pop', '_deque')
|
|
26
29
|
|
|
27
30
|
def __init__(self, max_size=None):
|
|
28
31
|
super(BaseCache, self).__init__()
|
|
@@ -150,7 +153,10 @@ class ArrayCacheBySymbolById(ArrayCache):
|
|
|
150
153
|
if len(self._deque) == self._deque.maxlen:
|
|
151
154
|
delete_item = self._deque.popleft()
|
|
152
155
|
self._index.popleft()
|
|
153
|
-
|
|
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}")
|
|
154
160
|
self._deque.append(item)
|
|
155
161
|
self._index.append(item['id'])
|
|
156
162
|
if self._clear_all_updates:
|
|
@@ -184,7 +190,7 @@ class ArrayCacheBySymbolBySide(ArrayCache):
|
|
|
184
190
|
if reference != item:
|
|
185
191
|
reference.update(item)
|
|
186
192
|
item = reference
|
|
187
|
-
index = self._index.index(item['side'])
|
|
193
|
+
index = self._index.index(item['symbol'] + item['side'])
|
|
188
194
|
del self._deque[index]
|
|
189
195
|
del self._index[index]
|
|
190
196
|
else:
|
|
@@ -194,7 +200,7 @@ class ArrayCacheBySymbolBySide(ArrayCache):
|
|
|
194
200
|
self._index.popleft()
|
|
195
201
|
del self.hashmap[delete_item['symbol']][delete_item['side']]
|
|
196
202
|
self._deque.append(item)
|
|
197
|
-
self._index.append(item['side'])
|
|
203
|
+
self._index.append(item['symbol'] + item['side'])
|
|
198
204
|
if self._clear_all_updates:
|
|
199
205
|
self._clear_all_updates = False
|
|
200
206
|
self._clear_updates_by_symbol.clear()
|
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
orjson = None
|
|
4
|
+
try:
|
|
5
|
+
import orjson as orjson
|
|
6
|
+
except ImportError:
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
from asyncio import sleep, ensure_future, wait_for, TimeoutError, BaseEventLoop, Future as asyncioFuture
|
|
12
|
+
from .functions import milliseconds, iso8601, deep_extend, is_json_encoded_object
|
|
13
|
+
from ccxt import NetworkError, RequestTimeout
|
|
6
14
|
from ccxt.async_support.base.ws.future import Future
|
|
15
|
+
from ccxt.async_support.base.ws.functions import gunzip, inflate
|
|
16
|
+
from typing import Dict
|
|
17
|
+
|
|
18
|
+
from aiohttp import WSMsgType
|
|
7
19
|
|
|
8
20
|
|
|
9
21
|
class Client(object):
|
|
10
22
|
|
|
11
23
|
url = None
|
|
12
24
|
ws = None
|
|
13
|
-
futures = {}
|
|
25
|
+
futures: Dict[str, Future] = {}
|
|
14
26
|
options = {} # ws-specific options
|
|
15
27
|
subscriptions = {}
|
|
16
28
|
rejections = {}
|
|
@@ -30,14 +42,15 @@ class Client(object):
|
|
|
30
42
|
maxPingPongMisses = 2.0 # how many missed pongs to raise a timeout
|
|
31
43
|
lastPong = None
|
|
32
44
|
ping = None # ping-function if defined
|
|
45
|
+
proxy = None
|
|
33
46
|
verbose = False # verbose output
|
|
34
47
|
gunzip = False
|
|
35
48
|
inflate = False
|
|
36
49
|
throttle = None
|
|
37
50
|
connecting = False
|
|
38
|
-
asyncio_loop = None
|
|
51
|
+
asyncio_loop: BaseEventLoop = None
|
|
39
52
|
ping_looper = None
|
|
40
|
-
|
|
53
|
+
decompressBinary = True # decompress binary messages by default
|
|
41
54
|
|
|
42
55
|
def __init__(self, url, on_message_callback, on_error_callback, on_close_callback, on_connected_callback, config={}):
|
|
43
56
|
defaults = {
|
|
@@ -80,7 +93,7 @@ class Client(object):
|
|
|
80
93
|
return result
|
|
81
94
|
|
|
82
95
|
def reject(self, result, message_hash=None):
|
|
83
|
-
if message_hash:
|
|
96
|
+
if message_hash is not None:
|
|
84
97
|
if message_hash in self.futures:
|
|
85
98
|
future = self.futures[message_hash]
|
|
86
99
|
future.reject(result)
|
|
@@ -93,19 +106,41 @@ class Client(object):
|
|
|
93
106
|
self.reject(result, message_hash)
|
|
94
107
|
return result
|
|
95
108
|
|
|
96
|
-
|
|
109
|
+
def receive_loop(self):
|
|
97
110
|
if self.verbose:
|
|
98
111
|
self.log(iso8601(milliseconds()), 'receive loop')
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
self.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
self.
|
|
112
|
+
if not self.closed():
|
|
113
|
+
# let's drain the aiohttp buffer to avoid latency
|
|
114
|
+
if len(self.buffer) > 1:
|
|
115
|
+
size_delta = 0
|
|
116
|
+
while len(self.buffer) > 1:
|
|
117
|
+
message, size = self.buffer.popleft()
|
|
118
|
+
size_delta += size
|
|
119
|
+
self.handle_message(message)
|
|
120
|
+
# we must update the size of the last message inside WebSocketDataQueue
|
|
121
|
+
# self.receive() calls WebSocketDataQueue.read() that calls WebSocketDataQueue._read_from_buffer()
|
|
122
|
+
# which updates the size of the buffer, the _size will overflow and pause the transport
|
|
123
|
+
# make sure to set the enviroment variable AIOHTTP_NO_EXTENSIONS=Y to check
|
|
124
|
+
# print(self.connection._conn.protocol._payload._size)
|
|
125
|
+
self.buffer[0] = (self.buffer[0][0], self.buffer[0][1] + size_delta)
|
|
126
|
+
|
|
127
|
+
task = self.asyncio_loop.create_task(self.receive())
|
|
128
|
+
|
|
129
|
+
def after_interrupt(resolved: asyncioFuture):
|
|
130
|
+
exception = resolved.exception()
|
|
131
|
+
if exception is None:
|
|
132
|
+
self.handle_message(resolved.result())
|
|
133
|
+
self.asyncio_loop.call_soon(self.receive_loop)
|
|
134
|
+
else:
|
|
135
|
+
error = NetworkError(str(exception))
|
|
136
|
+
if self.verbose:
|
|
137
|
+
self.log(iso8601(milliseconds()), 'receive_loop', 'Exception', error)
|
|
138
|
+
self.reject(error)
|
|
139
|
+
|
|
140
|
+
task.add_done_callback(after_interrupt)
|
|
141
|
+
else:
|
|
142
|
+
# connection got terminated after the connection was made and before the receive loop ran
|
|
143
|
+
self.on_close(1006)
|
|
109
144
|
|
|
110
145
|
async def open(self, session, backoff_delay=0):
|
|
111
146
|
# exponential backoff for consequent connections if necessary
|
|
@@ -126,7 +161,7 @@ class Client(object):
|
|
|
126
161
|
self.on_connected_callback(self)
|
|
127
162
|
# run both loops forever
|
|
128
163
|
self.ping_looper = ensure_future(self.ping_loop(), loop=self.asyncio_loop)
|
|
129
|
-
self.
|
|
164
|
+
self.asyncio_loop.call_soon(self.receive_loop)
|
|
130
165
|
except TimeoutError:
|
|
131
166
|
# connection timeout
|
|
132
167
|
error = RequestTimeout('Connection timeout')
|
|
@@ -140,6 +175,13 @@ class Client(object):
|
|
|
140
175
|
self.log(iso8601(milliseconds()), 'NetworkError', error)
|
|
141
176
|
self.on_error(error)
|
|
142
177
|
|
|
178
|
+
@property
|
|
179
|
+
def buffer(self):
|
|
180
|
+
# looks like they exposed it in C
|
|
181
|
+
# this means we can bypass it
|
|
182
|
+
# https://github.com/aio-libs/aiohttp/blob/master/aiohttp/_websocket/reader_c.pxd#L53C24-L53C31
|
|
183
|
+
return self.connection._conn.protocol._payload._buffer
|
|
184
|
+
|
|
143
185
|
def connect(self, session, backoff_delay=0):
|
|
144
186
|
if not self.connection and not self.connecting:
|
|
145
187
|
self.connecting = True
|
|
@@ -150,7 +192,7 @@ class Client(object):
|
|
|
150
192
|
if self.verbose:
|
|
151
193
|
self.log(iso8601(milliseconds()), 'on_error', error)
|
|
152
194
|
self.error = error
|
|
153
|
-
self.
|
|
195
|
+
self.reject(error)
|
|
154
196
|
self.on_error_callback(self, error)
|
|
155
197
|
if not self.closed():
|
|
156
198
|
ensure_future(self.close(1006), loop=self.asyncio_loop)
|
|
@@ -159,35 +201,128 @@ class Client(object):
|
|
|
159
201
|
if self.verbose:
|
|
160
202
|
self.log(iso8601(milliseconds()), 'on_close', code)
|
|
161
203
|
if not self.error:
|
|
162
|
-
self.
|
|
204
|
+
self.reject(NetworkError('Connection closed by remote server, closing code ' + str(code)))
|
|
163
205
|
self.on_close_callback(self, code)
|
|
164
|
-
|
|
165
|
-
ensure_future(self.close(code), loop=self.asyncio_loop)
|
|
206
|
+
ensure_future(self.aiohttp_close(), loop=self.asyncio_loop)
|
|
166
207
|
|
|
167
|
-
def
|
|
168
|
-
|
|
208
|
+
def log(self, *args):
|
|
209
|
+
print(*args)
|
|
169
210
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
self.log(iso8601(milliseconds()), 'ping loop')
|
|
211
|
+
def closed(self):
|
|
212
|
+
return (self.connection is None) or self.connection.closed
|
|
173
213
|
|
|
174
214
|
def receive(self):
|
|
175
|
-
|
|
215
|
+
return self.connection.receive()
|
|
216
|
+
|
|
217
|
+
# helper method for binary and text messages
|
|
218
|
+
def handle_text_or_binary_message(self, data):
|
|
219
|
+
if self.verbose:
|
|
220
|
+
self.log(iso8601(milliseconds()), 'message', data)
|
|
221
|
+
if isinstance(data, bytes):
|
|
222
|
+
if self.decompressBinary:
|
|
223
|
+
data = data.decode()
|
|
224
|
+
# decoded = json.loads(data) if is_json_encoded_object(data) else data
|
|
225
|
+
decode = None
|
|
226
|
+
if is_json_encoded_object(data):
|
|
227
|
+
if orjson is None:
|
|
228
|
+
decode = json.loads(data)
|
|
229
|
+
else:
|
|
230
|
+
decode = orjson.loads(data)
|
|
231
|
+
else:
|
|
232
|
+
decode = data
|
|
233
|
+
self.on_message_callback(self, decode)
|
|
176
234
|
|
|
177
235
|
def handle_message(self, message):
|
|
178
|
-
|
|
236
|
+
# self.log(iso8601(milliseconds()), message)
|
|
237
|
+
if message.type == WSMsgType.TEXT:
|
|
238
|
+
self.handle_text_or_binary_message(message.data)
|
|
239
|
+
elif message.type == WSMsgType.BINARY:
|
|
240
|
+
data = message.data
|
|
241
|
+
if self.gunzip:
|
|
242
|
+
data = gunzip(data)
|
|
243
|
+
elif self.inflate:
|
|
244
|
+
data = inflate(data)
|
|
245
|
+
self.handle_text_or_binary_message(data)
|
|
246
|
+
# autoping is responsible for automatically replying with pong
|
|
247
|
+
# to a ping incoming from a server, we have to disable autoping
|
|
248
|
+
# with aiohttp's websockets and respond with pong manually
|
|
249
|
+
# otherwise aiohttp's websockets client won't trigger WSMsgType.PONG
|
|
250
|
+
elif message.type == WSMsgType.PING:
|
|
251
|
+
if self.verbose:
|
|
252
|
+
self.log(iso8601(milliseconds()), 'ping', message)
|
|
253
|
+
ensure_future(self.connection.pong(message.data), loop=self.asyncio_loop)
|
|
254
|
+
elif message.type == WSMsgType.PONG:
|
|
255
|
+
self.lastPong = milliseconds()
|
|
256
|
+
if self.verbose:
|
|
257
|
+
self.log(iso8601(milliseconds()), 'pong', message)
|
|
258
|
+
pass
|
|
259
|
+
elif message.type == WSMsgType.CLOSE:
|
|
260
|
+
if self.verbose:
|
|
261
|
+
self.log(iso8601(milliseconds()), 'close', self.closed(), message)
|
|
262
|
+
self.on_close(message.data)
|
|
263
|
+
elif message.type == WSMsgType.ERROR:
|
|
264
|
+
if self.verbose:
|
|
265
|
+
self.log(iso8601(milliseconds()), 'error', message)
|
|
266
|
+
error = NetworkError(str(message))
|
|
267
|
+
self.on_error(error)
|
|
179
268
|
|
|
180
|
-
def
|
|
181
|
-
|
|
269
|
+
def create_connection(self, session):
|
|
270
|
+
# autoping is responsible for automatically replying with pong
|
|
271
|
+
# to a ping incoming from a server, we have to disable autoping
|
|
272
|
+
# with aiohttp's websockets and respond with pong manually
|
|
273
|
+
# otherwise aiohttp's websockets client won't trigger WSMsgType.PONG
|
|
274
|
+
# call aenter here to simulate async with otherwise we get the error "await not called with future"
|
|
275
|
+
# if connecting to a non-existent endpoint
|
|
276
|
+
if (self.proxy):
|
|
277
|
+
return session.ws_connect(self.url, autoping=False, autoclose=False, headers=self.options.get('headers'), proxy=self.proxy, max_msg_size=10485760).__aenter__()
|
|
278
|
+
return session.ws_connect(self.url, autoping=False, autoclose=False, headers=self.options.get('headers'), max_msg_size=10485760).__aenter__()
|
|
182
279
|
|
|
183
280
|
async def send(self, message):
|
|
184
|
-
|
|
281
|
+
if self.verbose:
|
|
282
|
+
self.log(iso8601(milliseconds()), 'sending', message)
|
|
283
|
+
send_msg = None
|
|
284
|
+
if isinstance(message, str):
|
|
285
|
+
send_msg = message
|
|
286
|
+
else:
|
|
287
|
+
if orjson is None:
|
|
288
|
+
send_msg = json.dumps(message, separators=(',', ':'))
|
|
289
|
+
else:
|
|
290
|
+
send_msg = orjson.dumps(message).decode('utf-8')
|
|
291
|
+
return await self.connection.send_str(send_msg)
|
|
185
292
|
|
|
186
293
|
async def close(self, code=1000):
|
|
187
|
-
|
|
294
|
+
if self.verbose:
|
|
295
|
+
self.log(iso8601(milliseconds()), 'closing', code)
|
|
296
|
+
for future in self.futures.values():
|
|
297
|
+
future.cancel()
|
|
298
|
+
await self.aiohttp_close()
|
|
188
299
|
|
|
189
|
-
def
|
|
190
|
-
|
|
300
|
+
async def aiohttp_close(self):
|
|
301
|
+
if not self.closed():
|
|
302
|
+
await self.connection.close()
|
|
303
|
+
# these will end automatically once self.closed() = True
|
|
304
|
+
# so we don't need to cancel them
|
|
305
|
+
if self.ping_looper:
|
|
306
|
+
self.ping_looper.cancel()
|
|
191
307
|
|
|
192
|
-
def
|
|
193
|
-
|
|
308
|
+
async def ping_loop(self):
|
|
309
|
+
if self.verbose:
|
|
310
|
+
self.log(iso8601(milliseconds()), 'ping loop')
|
|
311
|
+
while self.keepAlive and not self.closed():
|
|
312
|
+
now = milliseconds()
|
|
313
|
+
self.lastPong = now if self.lastPong is None else self.lastPong
|
|
314
|
+
if (self.lastPong + self.keepAlive * self.maxPingPongMisses) < now:
|
|
315
|
+
self.on_error(RequestTimeout('Connection to ' + self.url + ' timed out due to a ping-pong keepalive missing on time'))
|
|
316
|
+
# the following ping-clause is not necessary with aiohttp's built-in ws
|
|
317
|
+
# since it has a heartbeat option (see create_connection above)
|
|
318
|
+
# however some exchanges require a text-type ping message
|
|
319
|
+
# therefore we need this clause anyway
|
|
320
|
+
else:
|
|
321
|
+
if self.ping:
|
|
322
|
+
try:
|
|
323
|
+
await self.send(self.ping(self))
|
|
324
|
+
except Exception as e:
|
|
325
|
+
self.on_error(e)
|
|
326
|
+
else:
|
|
327
|
+
await self.connection.ping()
|
|
328
|
+
await sleep(self.keepAlive / 1000)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from ccxt import ExchangeClosedByUser
|
|
3
2
|
|
|
3
|
+
# Test by running:
|
|
4
|
+
# - python python/ccxt/pro/test/base/test_close.py
|
|
5
|
+
# - python python/ccxt/pro/test/base/test_future.py
|
|
4
6
|
class Future(asyncio.Future):
|
|
5
7
|
|
|
6
|
-
is_race_future = False
|
|
7
|
-
|
|
8
8
|
def resolve(self, result=None):
|
|
9
9
|
if not self.done():
|
|
10
10
|
self.set_result(result)
|
|
@@ -16,43 +16,31 @@ class Future(asyncio.Future):
|
|
|
16
16
|
@classmethod
|
|
17
17
|
def race(cls, futures):
|
|
18
18
|
future = Future()
|
|
19
|
-
for f in futures:
|
|
20
|
-
f.is_race_future = True
|
|
21
19
|
coro = asyncio.wait(futures, return_when=asyncio.FIRST_COMPLETED)
|
|
22
20
|
task = asyncio.create_task(coro)
|
|
23
21
|
|
|
24
22
|
def callback(done):
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
first = futures_list[0]
|
|
50
|
-
|
|
51
|
-
first_result = first.result()
|
|
52
|
-
future.resolve(first_result)
|
|
53
|
-
except asyncio.CancelledError as e:
|
|
54
|
-
future.reject(e)
|
|
55
|
-
except Exception as e:
|
|
56
|
-
future.reject(e)
|
|
23
|
+
complete, _ = done.result()
|
|
24
|
+
# check for exceptions
|
|
25
|
+
exceptions = []
|
|
26
|
+
cancelled = False
|
|
27
|
+
for f in complete:
|
|
28
|
+
if f.cancelled():
|
|
29
|
+
cancelled = True
|
|
30
|
+
else:
|
|
31
|
+
err = f.exception()
|
|
32
|
+
if err:
|
|
33
|
+
exceptions.append(err)
|
|
34
|
+
# if any exceptions return with first exception
|
|
35
|
+
if future.cancelled():
|
|
36
|
+
return
|
|
37
|
+
if len(exceptions) > 0:
|
|
38
|
+
future.set_exception(exceptions[0])
|
|
39
|
+
# else return first result
|
|
40
|
+
elif cancelled:
|
|
41
|
+
future.cancel()
|
|
42
|
+
else:
|
|
43
|
+
first_result = list(complete)[0].result()
|
|
44
|
+
future.set_result(first_result)
|
|
57
45
|
task.add_done_callback(callback)
|
|
58
46
|
return future
|
ccxt/async_support/bequant.py
CHANGED
|
@@ -5,19 +5,21 @@
|
|
|
5
5
|
|
|
6
6
|
from ccxt.async_support.hitbtc import hitbtc
|
|
7
7
|
from ccxt.abstract.bequant import ImplicitAPI
|
|
8
|
+
from ccxt.base.types import Any
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class bequant(hitbtc, ImplicitAPI):
|
|
11
12
|
|
|
12
|
-
def describe(self):
|
|
13
|
+
def describe(self) -> Any:
|
|
13
14
|
return self.deep_extend(super(bequant, self).describe(), {
|
|
14
15
|
'id': 'bequant',
|
|
15
16
|
'name': 'Bequant',
|
|
16
|
-
'countries': ['MT'], # Malta
|
|
17
17
|
'pro': True,
|
|
18
|
+
'countries': ['MT'], # Malta
|
|
18
19
|
'urls': {
|
|
19
|
-
'logo': 'https://
|
|
20
|
+
'logo': 'https://github.com/user-attachments/assets/0583ef1f-29fe-4b7c-8189-63565a0e2867',
|
|
20
21
|
'api': {
|
|
22
|
+
# v3
|
|
21
23
|
'public': 'https://api.bequant.io/api/3',
|
|
22
24
|
'private': 'https://api.bequant.io/api/3',
|
|
23
25
|
},
|