ccxt-ir 4.3.46.0.3__py2.py3-none-any.whl → 4.5.1__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 +8 -8
- 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 +10 -10
- 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 +32 -38
- 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 +32 -27
- 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 +34 -30
- ccxt/async_support/sarmayex.py +9 -9
- ccxt/async_support/sarrafex.py +13 -13
- ccxt/async_support/tabdeal.py +15 -14
- 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 +30 -36
- 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 +29 -24
- 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 +32 -28
- 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 +13 -12
- 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.1.dist-info}/METADATA +225 -73
- ccxt_ir-4.5.1.dist-info/RECORD +743 -0
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.1.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.1.dist-info/licenses}/LICENSE.txt +0 -0
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.1.dist-info}/top_level.txt +0 -0
ccxt/test/tests_async.py
CHANGED
|
@@ -12,7 +12,6 @@ class testMainClass:
|
|
|
12
12
|
request_tests = False
|
|
13
13
|
ws_tests = False
|
|
14
14
|
response_tests = False
|
|
15
|
-
static_tests = False
|
|
16
15
|
info = False
|
|
17
16
|
verbose = False
|
|
18
17
|
debug = False
|
|
@@ -50,16 +49,16 @@ class testMainClass:
|
|
|
50
49
|
if self.request_tests and self.response_tests:
|
|
51
50
|
await self.run_static_request_tests(exchange_id, symbol_argv)
|
|
52
51
|
await self.run_static_response_tests(exchange_id, symbol_argv)
|
|
53
|
-
return
|
|
52
|
+
return True
|
|
54
53
|
if self.response_tests:
|
|
55
54
|
await self.run_static_response_tests(exchange_id, symbol_argv)
|
|
56
|
-
return
|
|
55
|
+
return True
|
|
57
56
|
if self.request_tests:
|
|
58
57
|
await self.run_static_request_tests(exchange_id, symbol_argv) # symbol here is the testname
|
|
59
|
-
return
|
|
58
|
+
return True
|
|
60
59
|
if self.id_tests:
|
|
61
60
|
await self.run_broker_id_tests()
|
|
62
|
-
return
|
|
61
|
+
return True
|
|
63
62
|
new_line = '\n'
|
|
64
63
|
dump(new_line + '' + new_line + '' + '[INFO] TESTING ', self.ext, {
|
|
65
64
|
'exchange': exchange_id,
|
|
@@ -104,6 +103,7 @@ class testMainClass:
|
|
|
104
103
|
self.test_files = get_test_files_sync(properties, self.ws_tests)
|
|
105
104
|
else:
|
|
106
105
|
self.test_files = await get_test_files(properties, self.ws_tests)
|
|
106
|
+
return True
|
|
107
107
|
|
|
108
108
|
def load_credentials_from_env(self, exchange):
|
|
109
109
|
exchange_id = exchange.id
|
|
@@ -126,8 +126,12 @@ class testMainClass:
|
|
|
126
126
|
keys_local = get_root_dir() + 'keys.local.json'
|
|
127
127
|
keys_global_exists = io_file_exists(keys_global)
|
|
128
128
|
keys_local_exists = io_file_exists(keys_local)
|
|
129
|
-
global_settings =
|
|
130
|
-
|
|
129
|
+
global_settings = {}
|
|
130
|
+
if keys_global_exists:
|
|
131
|
+
global_settings = io_file_read(keys_global)
|
|
132
|
+
local_settings = {}
|
|
133
|
+
if keys_local_exists:
|
|
134
|
+
local_settings = io_file_read(keys_local)
|
|
131
135
|
all_settings = exchange.deep_extend(global_settings, local_settings)
|
|
132
136
|
exchange_settings = exchange.safe_value(all_settings, exchange_id, {})
|
|
133
137
|
if exchange_settings:
|
|
@@ -178,19 +182,20 @@ class testMainClass:
|
|
|
178
182
|
exchange.options['checksum'] = False
|
|
179
183
|
# todo: temporary skip for php
|
|
180
184
|
if 'OrderBook' in method_name and self.ext == 'php':
|
|
181
|
-
return
|
|
185
|
+
return True
|
|
182
186
|
skipped_properties_for_method = self.get_skips(exchange, method_name)
|
|
183
187
|
is_load_markets = (method_name == 'loadMarkets')
|
|
184
188
|
is_fetch_currencies = (method_name == 'fetchCurrencies')
|
|
185
189
|
is_proxy_test = (method_name == self.proxy_test_file_name)
|
|
190
|
+
is_feature_test = (method_name == 'features')
|
|
186
191
|
# if this is a private test, and the implementation was already tested in public, then no need to re-test it in private test (exception is fetchCurrencies, because our approach in base exchange)
|
|
187
192
|
if not is_public and (method_name in self.checked_public_tests) and not is_fetch_currencies:
|
|
188
|
-
return
|
|
193
|
+
return True
|
|
189
194
|
skip_message = None
|
|
190
195
|
supported_by_exchange = (method_name in exchange.has) and exchange.has[method_name]
|
|
191
196
|
if not is_load_markets and (len(self.only_specific_tests) > 0 and not exchange.in_array(method_name, self.only_specific_tests)):
|
|
192
197
|
skip_message = '[INFO] IGNORED_TEST'
|
|
193
|
-
elif not is_load_markets and not supported_by_exchange and not is_proxy_test:
|
|
198
|
+
elif not is_load_markets and not supported_by_exchange and not is_proxy_test and not is_feature_test:
|
|
194
199
|
skip_message = '[INFO] UNSUPPORTED_TEST' # keep it aligned with the longest message
|
|
195
200
|
elif isinstance(skipped_properties_for_method, str):
|
|
196
201
|
skip_message = '[INFO] SKIPPED_TEST'
|
|
@@ -203,7 +208,7 @@ class testMainClass:
|
|
|
203
208
|
if skip_message:
|
|
204
209
|
if self.info:
|
|
205
210
|
dump(self.add_padding(skip_message, 25), name, method_name)
|
|
206
|
-
return
|
|
211
|
+
return True
|
|
207
212
|
if self.info:
|
|
208
213
|
args_stringified = '(' + exchange.json(args) + ')' # args.join() breaks when we provide a list of symbols or multidimensional array; "args.toString()" breaks bcz of "array to string conversion"
|
|
209
214
|
dump(self.add_padding('[INFO] TESTING', 25), name, method_name, args_stringified)
|
|
@@ -216,7 +221,7 @@ class testMainClass:
|
|
|
216
221
|
# add to the list of successed tests
|
|
217
222
|
if is_public:
|
|
218
223
|
self.checked_public_tests[method_name] = True
|
|
219
|
-
return
|
|
224
|
+
return True
|
|
220
225
|
|
|
221
226
|
def get_skips(self, exchange, method_name):
|
|
222
227
|
final_skips = {}
|
|
@@ -285,10 +290,10 @@ class testMainClass:
|
|
|
285
290
|
is_on_maintenance = (isinstance(e, OnMaintenance))
|
|
286
291
|
is_exchange_not_available = (isinstance(e, ExchangeNotAvailable))
|
|
287
292
|
should_fail = None
|
|
288
|
-
|
|
293
|
+
ret_success = None
|
|
289
294
|
if is_load_markets:
|
|
290
295
|
# if "loadMarkets" does not succeed, we must return "false" to caller method, to stop tests continual
|
|
291
|
-
|
|
296
|
+
ret_success = False
|
|
292
297
|
# we might not break exchange tests, if exchange is on maintenance at this moment
|
|
293
298
|
if is_on_maintenance:
|
|
294
299
|
should_fail = False
|
|
@@ -299,20 +304,19 @@ class testMainClass:
|
|
|
299
304
|
if is_exchange_not_available and not is_on_maintenance:
|
|
300
305
|
# break exchange tests if "ExchangeNotAvailable" exception is thrown, but it's not maintenance
|
|
301
306
|
should_fail = True
|
|
302
|
-
|
|
307
|
+
ret_success = False
|
|
303
308
|
else:
|
|
304
309
|
# in all other cases of OperationFailed, show Warning, but don't mark test as failed
|
|
305
310
|
should_fail = False
|
|
306
|
-
|
|
311
|
+
ret_success = True
|
|
307
312
|
# output the message
|
|
308
313
|
fail_type = '[TEST_FAILURE]' if should_fail else '[TEST_WARNING]'
|
|
309
314
|
dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ', exchange.id, method_name, args_stringified, exception_message(e))
|
|
310
|
-
return
|
|
315
|
+
return ret_success
|
|
311
316
|
else:
|
|
312
317
|
# wait and retry again
|
|
313
318
|
# (increase wait time on every retry)
|
|
314
319
|
await exchange.sleep((i + 1) * 1000)
|
|
315
|
-
continue
|
|
316
320
|
else:
|
|
317
321
|
# if it's loadMarkets, then fail test, because it's mandatory for tests
|
|
318
322
|
if is_load_markets:
|
|
@@ -336,6 +340,7 @@ class testMainClass:
|
|
|
336
340
|
|
|
337
341
|
async def run_public_tests(self, exchange, symbol):
|
|
338
342
|
tests = {
|
|
343
|
+
'features': [],
|
|
339
344
|
'fetchCurrencies': [],
|
|
340
345
|
'fetchTicker': [symbol],
|
|
341
346
|
'fetchTickers': [symbol],
|
|
@@ -343,7 +348,6 @@ class testMainClass:
|
|
|
343
348
|
'fetchOHLCV': [symbol],
|
|
344
349
|
'fetchTrades': [symbol],
|
|
345
350
|
'fetchOrderBook': [symbol],
|
|
346
|
-
'fetchL2OrderBook': [symbol],
|
|
347
351
|
'fetchOrderBooks': [],
|
|
348
352
|
'fetchBidsAsks': [],
|
|
349
353
|
'fetchStatus': [],
|
|
@@ -375,6 +379,7 @@ class testMainClass:
|
|
|
375
379
|
tests['fetchPremiumIndexOHLCV'] = [symbol]
|
|
376
380
|
self.public_tests = tests
|
|
377
381
|
await self.run_tests(exchange, tests, True)
|
|
382
|
+
return True
|
|
378
383
|
|
|
379
384
|
async def run_tests(self, exchange, tests, is_public_test):
|
|
380
385
|
test_names = list(tests.keys())
|
|
@@ -399,6 +404,7 @@ class testMainClass:
|
|
|
399
404
|
dump('[TEST_FAILURE]', exchange.id, test_prefix_string, 'Failed methods : ' + errors_string)
|
|
400
405
|
if self.info:
|
|
401
406
|
dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' + exchange.id, 25))
|
|
407
|
+
return True
|
|
402
408
|
|
|
403
409
|
async def load_exchange(self, exchange):
|
|
404
410
|
result = await self.test_safe('loadMarkets', exchange, [], True)
|
|
@@ -519,11 +525,12 @@ class testMainClass:
|
|
|
519
525
|
if exchange.has['swap'] and swap_symbol is not None:
|
|
520
526
|
exchange.options['defaultType'] = 'swap'
|
|
521
527
|
await self.run_private_tests(exchange, swap_symbol)
|
|
528
|
+
return True
|
|
522
529
|
|
|
523
530
|
async def run_private_tests(self, exchange, symbol):
|
|
524
531
|
if not exchange.check_required_credentials(False):
|
|
525
532
|
dump('[INFO] Skipping private tests', 'Keys not found')
|
|
526
|
-
return
|
|
533
|
+
return True
|
|
527
534
|
code = self.get_exchange_code(exchange)
|
|
528
535
|
# if (exchange.deepExtendedTest) {
|
|
529
536
|
# await test ('InvalidNonce', exchange, symbol);
|
|
@@ -560,6 +567,8 @@ class testMainClass:
|
|
|
560
567
|
'fetchBorrowRateHistory': [code],
|
|
561
568
|
'fetchLedgerEntry': [code],
|
|
562
569
|
}
|
|
570
|
+
if get_cli_arg_value('--fundedTests'):
|
|
571
|
+
tests['createOrder'] = [symbol]
|
|
563
572
|
if self.ws_tests:
|
|
564
573
|
tests = {
|
|
565
574
|
'watchBalance': [code],
|
|
@@ -591,14 +600,14 @@ class testMainClass:
|
|
|
591
600
|
proxy_test_name = self.proxy_test_file_name
|
|
592
601
|
# todo: temporary skip for sync py
|
|
593
602
|
if self.ext == 'py' and is_sync():
|
|
594
|
-
return
|
|
603
|
+
return True
|
|
595
604
|
# try proxy several times
|
|
596
605
|
max_retries = 3
|
|
597
606
|
exception = None
|
|
598
607
|
for j in range(0, max_retries):
|
|
599
608
|
try:
|
|
600
609
|
await self.test_method(proxy_test_name, exchange, [], True)
|
|
601
|
-
return # if successfull, then end the test
|
|
610
|
+
return True # if successfull, then end the test
|
|
602
611
|
except Exception as e:
|
|
603
612
|
exception = e
|
|
604
613
|
await exchange.sleep(j * 1000)
|
|
@@ -607,12 +616,39 @@ class testMainClass:
|
|
|
607
616
|
error_message = '[TEST_FAILURE] Failed ' + proxy_test_name + ' : ' + exception_message(exception)
|
|
608
617
|
# temporary comment the below, because c# transpilation failure
|
|
609
618
|
# throw new Exchange Error (errorMessage.toString ());
|
|
610
|
-
dump('[TEST_WARNING]' +
|
|
619
|
+
dump('[TEST_WARNING]' + error_message)
|
|
620
|
+
return True
|
|
621
|
+
|
|
622
|
+
def check_constructor(self, exchange):
|
|
623
|
+
# todo: this might be moved in base tests later
|
|
624
|
+
if exchange.id == 'binance':
|
|
625
|
+
assert exchange.hostname is None or exchange.hostname == '', 'binance.com hostname should be empty'
|
|
626
|
+
assert exchange.urls['api']['public'] == 'https://api.binance.com/api/v3', 'https://api.binance.com/api/v3 does not match: ' + exchange.urls['api']['public']
|
|
627
|
+
assert ('lending/union/account' in exchange.api['sapi']['get']), 'SAPI should contain the endpoint lending/union/account, ' + json_stringify(exchange.api['sapi']['get'])
|
|
628
|
+
elif exchange.id == 'binanceus':
|
|
629
|
+
assert exchange.hostname == 'binance.us', 'binance.us hostname does not match ' + exchange.hostname
|
|
630
|
+
assert exchange.urls['api']['public'] == 'https://api.binance.us/api/v3', 'https://api.binance.us/api/v3 does not match: ' + exchange.urls['api']['public']
|
|
631
|
+
|
|
632
|
+
async def test_return_response_headers(self, exchange):
|
|
633
|
+
if exchange.id != 'binance':
|
|
634
|
+
return False # this test is only for binance exchange for now
|
|
635
|
+
exchange.return_response_headers = True
|
|
636
|
+
ticker = await exchange.fetch_ticker('BTC/USDT')
|
|
637
|
+
info = ticker['info']
|
|
638
|
+
headers = info['responseHeaders']
|
|
639
|
+
headers_keys = list(headers.keys())
|
|
640
|
+
assert len(headers_keys) > 0, 'Response headers should not be empty'
|
|
641
|
+
header_values = list(headers.values())
|
|
642
|
+
assert len(header_values) > 0, 'Response headers values should not be empty'
|
|
643
|
+
exchange.return_response_headers = False
|
|
644
|
+
return True
|
|
611
645
|
|
|
612
646
|
async def start_test(self, exchange, symbol):
|
|
613
647
|
# we do not need to test aliases
|
|
614
648
|
if exchange.alias:
|
|
615
|
-
return
|
|
649
|
+
return True
|
|
650
|
+
self.check_constructor(exchange)
|
|
651
|
+
# await this.testReturnResponseHeaders (exchange);
|
|
616
652
|
if self.sandbox or get_exchange_prop(exchange, 'sandbox'):
|
|
617
653
|
exchange.set_sandbox_mode(True)
|
|
618
654
|
try:
|
|
@@ -620,7 +656,7 @@ class testMainClass:
|
|
|
620
656
|
if not result:
|
|
621
657
|
if not is_sync():
|
|
622
658
|
await close(exchange)
|
|
623
|
-
return
|
|
659
|
+
return True
|
|
624
660
|
# if (exchange.id === 'binance') {
|
|
625
661
|
# # we test proxies functionality just for one random exchange on each build, because proxy functionality is not exchange-specific, instead it's all done from base methods, so just one working sample would mean it works for all ccxt exchanges
|
|
626
662
|
# # await this.testProxies (exchange);
|
|
@@ -712,7 +748,7 @@ class testMainClass:
|
|
|
712
748
|
result[key] = value
|
|
713
749
|
return result
|
|
714
750
|
|
|
715
|
-
def
|
|
751
|
+
def assert_new_and_stored_output_inner(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
|
|
716
752
|
if is_null_value(new_output) and is_null_value(stored_output):
|
|
717
753
|
return True
|
|
718
754
|
if not new_output and not stored_output:
|
|
@@ -743,8 +779,8 @@ class testMainClass:
|
|
|
743
779
|
self.assert_new_and_stored_output(exchange, skip_keys, new_item, stored_item, strict_type_check)
|
|
744
780
|
else:
|
|
745
781
|
# built-in types like strings, numbers, booleans
|
|
746
|
-
sanitized_new_output = None if (
|
|
747
|
-
sanitized_stored_output = None if (
|
|
782
|
+
sanitized_new_output = None if (is_null_value(new_output)) else new_output # we store undefined as nulls in the json file so we need to convert it back
|
|
783
|
+
sanitized_stored_output = None if (is_null_value(stored_output)) else stored_output
|
|
748
784
|
new_output_string = str(sanitized_new_output) if sanitized_new_output else 'undefined'
|
|
749
785
|
stored_output_string = str(sanitized_stored_output) if sanitized_stored_output else 'undefined'
|
|
750
786
|
message_error = 'output value mismatch:' + new_output_string + ' != ' + stored_output_string
|
|
@@ -765,7 +801,7 @@ class testMainClass:
|
|
|
765
801
|
is_string = is_computed_string or is_stored_string
|
|
766
802
|
is_undefined = is_computed_undefined or is_stored_undefined # undefined is a perfetly valid value
|
|
767
803
|
if is_boolean or is_string or is_undefined:
|
|
768
|
-
if self.lang == 'C#':
|
|
804
|
+
if (self.lang == 'C#') or (self.lang == 'GO'):
|
|
769
805
|
# tmp c# number comparsion
|
|
770
806
|
is_number = False
|
|
771
807
|
try:
|
|
@@ -794,6 +830,27 @@ class testMainClass:
|
|
|
794
830
|
self.assert_static_error(numeric_new_output == numeric_stored_output, message_error, stored_output, new_output, asserting_key)
|
|
795
831
|
return True # c# requ
|
|
796
832
|
|
|
833
|
+
def assert_new_and_stored_output(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
|
|
834
|
+
res = True
|
|
835
|
+
try:
|
|
836
|
+
res = self.assert_new_and_stored_output_inner(exchange, skip_keys, new_output, stored_output, strict_type_check, asserting_key)
|
|
837
|
+
except Exception as e:
|
|
838
|
+
if self.info:
|
|
839
|
+
error_message = self.var_to_string(new_output) + '(calculated)' + ' != ' + self.var_to_string(stored_output) + '(stored)'
|
|
840
|
+
dump('[TEST_FAILURE_DETAIL]' + error_message)
|
|
841
|
+
raise e
|
|
842
|
+
return res
|
|
843
|
+
|
|
844
|
+
def var_to_string(self, obj=None):
|
|
845
|
+
new_string = None
|
|
846
|
+
if obj is None:
|
|
847
|
+
new_string = 'undefined'
|
|
848
|
+
elif is_null_value(obj):
|
|
849
|
+
new_string = 'null'
|
|
850
|
+
else:
|
|
851
|
+
new_string = json_stringify(obj)
|
|
852
|
+
return new_string
|
|
853
|
+
|
|
797
854
|
def assert_static_request_output(self, exchange, type, skip_keys, stored_url, request_url, stored_output, new_output):
|
|
798
855
|
if stored_url != request_url:
|
|
799
856
|
# remove the host part from the url
|
|
@@ -811,11 +868,11 @@ class testMainClass:
|
|
|
811
868
|
if (stored_url_query is None) and (new_url_query is None):
|
|
812
869
|
# might be a get request without any query parameters
|
|
813
870
|
# example: https://api.gateio.ws/api/v4/delivery/usdt/positions
|
|
814
|
-
return
|
|
871
|
+
return True
|
|
815
872
|
stored_url_params = self.urlencoded_to_dict(stored_url_query)
|
|
816
873
|
new_url_params = self.urlencoded_to_dict(new_url_query)
|
|
817
874
|
self.assert_new_and_stored_output(exchange, skip_keys, new_url_params, stored_url_params)
|
|
818
|
-
return
|
|
875
|
+
return True
|
|
819
876
|
if type == 'json' and (stored_output is not None) and (new_output is not None):
|
|
820
877
|
if isinstance(stored_output, str):
|
|
821
878
|
stored_output = json_parse(stored_output)
|
|
@@ -832,6 +889,7 @@ class testMainClass:
|
|
|
832
889
|
stored_output = self.urlencoded_to_dict(stored_output)
|
|
833
890
|
new_output = self.urlencoded_to_dict(new_output)
|
|
834
891
|
self.assert_new_and_stored_output(exchange, skip_keys, new_output, stored_output)
|
|
892
|
+
return True
|
|
835
893
|
|
|
836
894
|
def assert_static_response_output(self, exchange, skip_keys, computed_result, stored_result):
|
|
837
895
|
self.assert_new_and_stored_output(exchange, skip_keys, computed_result, stored_result, False)
|
|
@@ -852,6 +910,8 @@ class testMainClass:
|
|
|
852
910
|
async def test_request_statically(self, exchange, method, data, type, skip_keys):
|
|
853
911
|
output = None
|
|
854
912
|
request_url = None
|
|
913
|
+
if self.info:
|
|
914
|
+
dump('[INFO] STATIC REQUEST TEST:', method, ':', data['description'])
|
|
855
915
|
try:
|
|
856
916
|
if not is_sync():
|
|
857
917
|
await call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
|
|
@@ -867,12 +927,15 @@ class testMainClass:
|
|
|
867
927
|
self.assert_static_request_output(exchange, type, skip_keys, data['url'], request_url, call_output, output)
|
|
868
928
|
except Exception as e:
|
|
869
929
|
self.request_tests_failed = True
|
|
870
|
-
error_message = '[' + self.lang + '][STATIC_REQUEST]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' +
|
|
930
|
+
error_message = '[' + self.lang + '][STATIC_REQUEST]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + exception_message(e)
|
|
871
931
|
dump('[TEST_FAILURE]' + error_message)
|
|
932
|
+
return True
|
|
872
933
|
|
|
873
934
|
async def test_response_statically(self, exchange, method, skip_keys, data):
|
|
874
935
|
expected_result = exchange.safe_value(data, 'parsedResponse')
|
|
875
936
|
mocked_exchange = set_fetch_response(exchange, data['httpResponse'])
|
|
937
|
+
if self.info:
|
|
938
|
+
dump('[INFO] STATIC RESPONSE TEST:', method, ':', data['description'])
|
|
876
939
|
try:
|
|
877
940
|
if not is_sync():
|
|
878
941
|
unified_result = await call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
|
|
@@ -882,13 +945,15 @@ class testMainClass:
|
|
|
882
945
|
self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
|
|
883
946
|
except Exception as e:
|
|
884
947
|
self.response_tests_failed = True
|
|
885
|
-
error_message = '[' + self.lang + '][STATIC_RESPONSE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' +
|
|
948
|
+
error_message = '[' + self.lang + '][STATIC_RESPONSE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + exception_message(e)
|
|
886
949
|
dump('[TEST_FAILURE]' + error_message)
|
|
887
950
|
set_fetch_response(exchange, None) # reset state
|
|
951
|
+
return True
|
|
888
952
|
|
|
889
953
|
def init_offline_exchange(self, exchange_name):
|
|
890
954
|
markets = self.load_markets_from_file(exchange_name)
|
|
891
955
|
currencies = self.load_currencies_from_file(exchange_name)
|
|
956
|
+
# we add "proxy" 2 times to intentionally trigger InvalidProxySettings
|
|
892
957
|
exchange = init_exchange(exchange_name, {
|
|
893
958
|
'markets': markets,
|
|
894
959
|
'currencies': currencies,
|
|
@@ -903,7 +968,8 @@ class testMainClass:
|
|
|
903
968
|
'privateKey': '0xff3bdd43534543d421f05aec535965b5050ad6ac15345435345435453495e771',
|
|
904
969
|
'uid': 'uid',
|
|
905
970
|
'token': 'token',
|
|
906
|
-
'
|
|
971
|
+
'login': 'login',
|
|
972
|
+
'accountId': '12345',
|
|
907
973
|
'accounts': [{
|
|
908
974
|
'id': 'myAccount',
|
|
909
975
|
'code': 'USDT',
|
|
@@ -919,7 +985,8 @@ class testMainClass:
|
|
|
919
985
|
'leverageBrackets': {},
|
|
920
986
|
},
|
|
921
987
|
})
|
|
922
|
-
exchange.currencies = currencies
|
|
988
|
+
exchange.currencies = currencies
|
|
989
|
+
# not working in python if assigned in the config dict
|
|
923
990
|
return exchange
|
|
924
991
|
|
|
925
992
|
async def test_exchange_request_statically(self, exchange_name, exchange_data, test_name=None):
|
|
@@ -939,6 +1006,9 @@ class testMainClass:
|
|
|
939
1006
|
wallet_address = exchange.safe_string(exchange_data, 'walletAddress')
|
|
940
1007
|
if wallet_address:
|
|
941
1008
|
exchange.walletAddress = str(wallet_address)
|
|
1009
|
+
accounts = exchange.safe_list(exchange_data, 'accounts')
|
|
1010
|
+
if accounts:
|
|
1011
|
+
exchange.accounts = accounts
|
|
942
1012
|
# exchange.options = exchange.deepExtend (exchange.options, globalOptions); # custom options to be used in the tests
|
|
943
1013
|
exchange.extend_exchange_options(global_options)
|
|
944
1014
|
methods = exchange.safe_value(exchange_data, 'methods', {})
|
|
@@ -964,12 +1034,14 @@ class testMainClass:
|
|
|
964
1034
|
is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
|
|
965
1035
|
if is_disabled_c_sharp and (self.lang == 'C#'):
|
|
966
1036
|
continue
|
|
1037
|
+
is_disabled_go = exchange.safe_bool(result, 'disabledGO', False)
|
|
1038
|
+
if is_disabled_go and (self.lang == 'GO'):
|
|
1039
|
+
continue
|
|
967
1040
|
type = exchange.safe_string(exchange_data, 'outputType')
|
|
968
1041
|
skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
|
|
969
1042
|
await self.test_request_statically(exchange, method, result, type, skip_keys)
|
|
970
1043
|
# reset options
|
|
971
|
-
|
|
972
|
-
exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
|
|
1044
|
+
exchange.options = exchange.convert_to_safe_dictionary(exchange.deep_extend(old_exchange_options, {}))
|
|
973
1045
|
if not is_sync():
|
|
974
1046
|
await close(exchange)
|
|
975
1047
|
return True # in c# methods that will be used with promiseAll need to return something
|
|
@@ -1015,6 +1087,9 @@ class testMainClass:
|
|
|
1015
1087
|
continue
|
|
1016
1088
|
if (test_name is not None) and (test_name != description):
|
|
1017
1089
|
continue
|
|
1090
|
+
is_disabled_go = exchange.safe_bool(result, 'disabledGO', False)
|
|
1091
|
+
if is_disabled_go and (self.lang == 'GO'):
|
|
1092
|
+
continue
|
|
1018
1093
|
skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
|
|
1019
1094
|
await self.test_response_statically(exchange, method, skip_keys, result)
|
|
1020
1095
|
# reset options
|
|
@@ -1037,14 +1112,35 @@ class testMainClass:
|
|
|
1037
1112
|
sum = exchange.sum(sum, results_length)
|
|
1038
1113
|
return sum
|
|
1039
1114
|
|
|
1115
|
+
def check_if_exchange_is_disabled(self, exchange_name, exchange_data):
|
|
1116
|
+
exchange = init_exchange('Exchange', {})
|
|
1117
|
+
is_disabled_py = exchange.safe_bool(exchange_data, 'disabledPy', False)
|
|
1118
|
+
if is_disabled_py and (self.lang == 'PY'):
|
|
1119
|
+
dump('[TEST_WARNING] Exchange ' + exchange_name + ' is disabled in python')
|
|
1120
|
+
return True
|
|
1121
|
+
is_disabled_php = exchange.safe_bool(exchange_data, 'disabledPHP', False)
|
|
1122
|
+
if is_disabled_php and (self.lang == 'PHP'):
|
|
1123
|
+
dump('[TEST_WARNING] Exchange ' + exchange_name + ' is disabled in php')
|
|
1124
|
+
return True
|
|
1125
|
+
is_disabled_c_sharp = exchange.safe_bool(exchange_data, 'disabledCS', False)
|
|
1126
|
+
if is_disabled_c_sharp and (self.lang == 'C#'):
|
|
1127
|
+
dump('[TEST_WARNING] Exchange ' + exchange_name + ' is disabled in c#')
|
|
1128
|
+
return True
|
|
1129
|
+
is_disabled_go = exchange.safe_bool(exchange_data, 'disabledGO', False)
|
|
1130
|
+
if is_disabled_go and (self.lang == 'GO'):
|
|
1131
|
+
dump('[TEST_WARNING] Exchange ' + exchange_name + ' is disabled in go')
|
|
1132
|
+
return True
|
|
1133
|
+
return False
|
|
1134
|
+
|
|
1040
1135
|
async def run_static_request_tests(self, target_exchange=None, test_name=None):
|
|
1041
1136
|
await self.run_static_tests('request', target_exchange, test_name)
|
|
1137
|
+
return True
|
|
1042
1138
|
|
|
1043
1139
|
async def run_static_tests(self, type, target_exchange=None, test_name=None):
|
|
1044
1140
|
folder = get_root_dir() + './ts/src/test/static/' + type + '/'
|
|
1045
1141
|
static_data = self.load_static_data(folder, target_exchange)
|
|
1046
1142
|
if static_data is None:
|
|
1047
|
-
return
|
|
1143
|
+
return True
|
|
1048
1144
|
exchanges = list(static_data.keys())
|
|
1049
1145
|
exchange = init_exchange('Exchange', {}) # tmp to do the calculations until we have the ast-transpiler transpiling this code
|
|
1050
1146
|
promises = []
|
|
@@ -1056,13 +1152,24 @@ class testMainClass:
|
|
|
1056
1152
|
for i in range(0, len(exchanges)):
|
|
1057
1153
|
exchange_name = exchanges[i]
|
|
1058
1154
|
exchange_data = static_data[exchange_name]
|
|
1155
|
+
disabled = self.check_if_exchange_is_disabled(exchange_name, exchange_data)
|
|
1156
|
+
if disabled:
|
|
1157
|
+
continue
|
|
1059
1158
|
number_of_tests = self.get_number_of_tests_from_exchange(exchange, exchange_data, test_name)
|
|
1060
1159
|
sum = exchange.sum(sum, number_of_tests)
|
|
1061
1160
|
if type == 'request':
|
|
1062
1161
|
promises.append(self.test_exchange_request_statically(exchange_name, exchange_data, test_name))
|
|
1063
1162
|
else:
|
|
1064
1163
|
promises.append(self.test_exchange_response_statically(exchange_name, exchange_data, test_name))
|
|
1065
|
-
|
|
1164
|
+
try:
|
|
1165
|
+
await asyncio.gather(*promises)
|
|
1166
|
+
except Exception as e:
|
|
1167
|
+
if type == 'request':
|
|
1168
|
+
self.request_tests_failed = True
|
|
1169
|
+
else:
|
|
1170
|
+
self.response_tests_failed = True
|
|
1171
|
+
error_message = '[' + self.lang + '][STATIC_REQUEST]' + exception_message(e)
|
|
1172
|
+
dump('[TEST_FAILURE]' + error_message)
|
|
1066
1173
|
if self.request_tests_failed or self.response_tests_failed:
|
|
1067
1174
|
exit_script(1)
|
|
1068
1175
|
else:
|
|
@@ -1075,20 +1182,24 @@ class testMainClass:
|
|
|
1075
1182
|
# --- Init of mockResponses tests functions------------------------------------
|
|
1076
1183
|
# -----------------------------------------------------------------------------
|
|
1077
1184
|
await self.run_static_tests('response', exchange_name, test)
|
|
1185
|
+
return True
|
|
1078
1186
|
|
|
1079
1187
|
async def run_broker_id_tests(self):
|
|
1080
1188
|
# -----------------------------------------------------------------------------
|
|
1081
1189
|
# --- Init of brokerId tests functions-----------------------------------------
|
|
1082
1190
|
# -----------------------------------------------------------------------------
|
|
1083
|
-
promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.
|
|
1191
|
+
promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex(), self.test_hashkey(), self.test_coincatch(), self.test_defx(), self.test_cryptomus(), self.test_derive(), self.test_mode_trade()]
|
|
1084
1192
|
await asyncio.gather(*promises)
|
|
1085
1193
|
success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
|
|
1086
1194
|
dump('[INFO]' + success_message)
|
|
1087
1195
|
exit_script(0)
|
|
1196
|
+
return True
|
|
1088
1197
|
|
|
1089
1198
|
async def test_binance(self):
|
|
1090
1199
|
exchange = self.init_offline_exchange('binance')
|
|
1091
|
-
spot_id = 'x-
|
|
1200
|
+
spot_id = 'x-TKT5PX2F'
|
|
1201
|
+
swap_id = 'x-cvBPrNm9'
|
|
1202
|
+
inverse_swap_id = 'x-xcKtGhcu'
|
|
1092
1203
|
spot_order_request = None
|
|
1093
1204
|
try:
|
|
1094
1205
|
await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
|
|
@@ -1097,7 +1208,6 @@ class testMainClass:
|
|
|
1097
1208
|
client_order_id = spot_order_request['newClientOrderId']
|
|
1098
1209
|
spot_id_string = str(spot_id)
|
|
1099
1210
|
assert client_order_id.startswith(spot_id_string), 'binance - spot clientOrderId: ' + client_order_id + ' does not start with spotId' + spot_id_string
|
|
1100
|
-
swap_id = 'x-xcKtGhcu'
|
|
1101
1211
|
swap_order_request = None
|
|
1102
1212
|
try:
|
|
1103
1213
|
await exchange.create_order('BTC/USDT:USDT', 'limit', 'buy', 1, 20000)
|
|
@@ -1108,11 +1218,35 @@ class testMainClass:
|
|
|
1108
1218
|
await exchange.create_order('BTC/USD:BTC', 'limit', 'buy', 1, 20000)
|
|
1109
1219
|
except Exception as e:
|
|
1110
1220
|
swap_inverse_order_request = self.urlencoded_to_dict(exchange.last_request_body)
|
|
1221
|
+
# linear swap
|
|
1111
1222
|
client_order_id_swap = swap_order_request['newClientOrderId']
|
|
1112
1223
|
swap_id_string = str(swap_id)
|
|
1113
1224
|
assert client_order_id_swap.startswith(swap_id_string), 'binance - swap clientOrderId: ' + client_order_id_swap + ' does not start with swapId' + swap_id_string
|
|
1225
|
+
# inverse swap
|
|
1114
1226
|
client_order_id_inverse = swap_inverse_order_request['newClientOrderId']
|
|
1115
|
-
assert client_order_id_inverse.startswith(
|
|
1227
|
+
assert client_order_id_inverse.startswith(inverse_swap_id), 'binance - swap clientOrderIdInverse: ' + client_order_id_inverse + ' does not start with swapId' + inverse_swap_id
|
|
1228
|
+
create_orders_request = None
|
|
1229
|
+
try:
|
|
1230
|
+
orders = [{
|
|
1231
|
+
'symbol': 'BTC/USDT:USDT',
|
|
1232
|
+
'type': 'limit',
|
|
1233
|
+
'side': 'sell',
|
|
1234
|
+
'amount': 1,
|
|
1235
|
+
'price': 100000,
|
|
1236
|
+
}, {
|
|
1237
|
+
'symbol': 'BTC/USDT:USDT',
|
|
1238
|
+
'type': 'market',
|
|
1239
|
+
'side': 'buy',
|
|
1240
|
+
'amount': 1,
|
|
1241
|
+
}]
|
|
1242
|
+
await exchange.create_orders(orders)
|
|
1243
|
+
except Exception as e:
|
|
1244
|
+
create_orders_request = self.urlencoded_to_dict(exchange.last_request_body)
|
|
1245
|
+
batch_orders = create_orders_request['batchOrders']
|
|
1246
|
+
for i in range(0, len(batch_orders)):
|
|
1247
|
+
current = batch_orders[i]
|
|
1248
|
+
current_client_order_id = current['newClientOrderId']
|
|
1249
|
+
assert current_client_order_id.startswith(swap_id_string), 'binance createOrders - clientOrderId: ' + current_client_order_id + ' does not start with swapId' + swap_id_string
|
|
1116
1250
|
if not is_sync():
|
|
1117
1251
|
await close(exchange)
|
|
1118
1252
|
return True
|
|
@@ -1276,7 +1410,7 @@ class testMainClass:
|
|
|
1276
1410
|
try:
|
|
1277
1411
|
await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
|
|
1278
1412
|
except Exception as e:
|
|
1279
|
-
spot_order_request =
|
|
1413
|
+
spot_order_request = json_parse(exchange.last_request_body)
|
|
1280
1414
|
broker_id = spot_order_request['broker_id']
|
|
1281
1415
|
id_string = str(id)
|
|
1282
1416
|
assert broker_id.startswith(id_string), 'woo - broker_id: ' + broker_id + ' does not start with id: ' + id_string
|
|
@@ -1338,6 +1472,7 @@ class testMainClass:
|
|
|
1338
1472
|
assert req_headers['X-SOURCE-KEY'] == id, 'bingx - id: ' + id + ' not in headers.'
|
|
1339
1473
|
if not is_sync():
|
|
1340
1474
|
await close(exchange)
|
|
1475
|
+
return True
|
|
1341
1476
|
|
|
1342
1477
|
async def test_phemex(self):
|
|
1343
1478
|
exchange = self.init_offline_exchange('phemex')
|
|
@@ -1352,6 +1487,7 @@ class testMainClass:
|
|
|
1352
1487
|
assert client_order_id.startswith(id_string), 'phemex - clOrdID: ' + client_order_id + ' does not start with id: ' + id_string
|
|
1353
1488
|
if not is_sync():
|
|
1354
1489
|
await close(exchange)
|
|
1490
|
+
return True
|
|
1355
1491
|
|
|
1356
1492
|
async def test_blofin(self):
|
|
1357
1493
|
exchange = self.init_offline_exchange('blofin')
|
|
@@ -1366,20 +1502,24 @@ class testMainClass:
|
|
|
1366
1502
|
assert broker_id.startswith(id_string), 'blofin - brokerId: ' + broker_id + ' does not start with id: ' + id_string
|
|
1367
1503
|
if not is_sync():
|
|
1368
1504
|
await close(exchange)
|
|
1505
|
+
return True
|
|
1369
1506
|
|
|
1370
|
-
async
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1507
|
+
# async testHyperliquid () {
|
|
1508
|
+
# const exchange = this.initOfflineExchange ('hyperliquid');
|
|
1509
|
+
# const id = '1';
|
|
1510
|
+
# let request = undefined;
|
|
1511
|
+
# try {
|
|
1512
|
+
# await exchange.createOrder ('SOL/USDC:USDC', 'limit', 'buy', 1, 100);
|
|
1513
|
+
# } catch (e) {
|
|
1514
|
+
# request = jsonParse (exchange.last_request_body);
|
|
1515
|
+
# }
|
|
1516
|
+
# const brokerId = (request['action']['brokerCode']).toString ();
|
|
1517
|
+
# assert (brokerId === id, 'hyperliquid - brokerId: ' + brokerId + ' does not start with id: ' + id);
|
|
1518
|
+
# if (!isSync ()) {
|
|
1519
|
+
# await close (exchange);
|
|
1520
|
+
# }
|
|
1521
|
+
# return true;
|
|
1522
|
+
# }
|
|
1383
1523
|
async def test_coinbaseinternational(self):
|
|
1384
1524
|
exchange = self.init_offline_exchange('coinbaseinternational')
|
|
1385
1525
|
exchange.options['portfolio'] = 'random'
|
|
@@ -1556,3 +1696,67 @@ class testMainClass:
|
|
|
1556
1696
|
if not is_sync():
|
|
1557
1697
|
await close(exchange)
|
|
1558
1698
|
return True
|
|
1699
|
+
|
|
1700
|
+
async def test_defx(self):
|
|
1701
|
+
exchange = self.init_offline_exchange('defx')
|
|
1702
|
+
req_headers = None
|
|
1703
|
+
try:
|
|
1704
|
+
await exchange.create_order('DOGE/USDC:USDC', 'limit', 'buy', 100, 1)
|
|
1705
|
+
except Exception as e:
|
|
1706
|
+
# we expect an error here, we're only interested in the headers
|
|
1707
|
+
req_headers = exchange.last_request_headers
|
|
1708
|
+
id = 'ccxt'
|
|
1709
|
+
assert req_headers['X-DEFX-SOURCE'] == id, 'defx - id: ' + id + ' not in headers.'
|
|
1710
|
+
if not is_sync():
|
|
1711
|
+
await close(exchange)
|
|
1712
|
+
return True
|
|
1713
|
+
|
|
1714
|
+
async def test_cryptomus(self):
|
|
1715
|
+
exchange = self.init_offline_exchange('cryptomus')
|
|
1716
|
+
request = None
|
|
1717
|
+
try:
|
|
1718
|
+
await exchange.create_order('BTC/USDT', 'limit', 'sell', 1, 20000)
|
|
1719
|
+
except Exception as e:
|
|
1720
|
+
request = json_parse(exchange.last_request_body)
|
|
1721
|
+
tag = 'ccxt'
|
|
1722
|
+
assert request['tag'] == tag, 'cryptomus - tag: ' + tag + ' not in request.'
|
|
1723
|
+
if not is_sync():
|
|
1724
|
+
await close(exchange)
|
|
1725
|
+
return True
|
|
1726
|
+
|
|
1727
|
+
async def test_derive(self):
|
|
1728
|
+
exchange = self.init_offline_exchange('derive')
|
|
1729
|
+
id = '0x0ad42b8e602c2d3d475ae52d678cf63d84ab2749'
|
|
1730
|
+
assert exchange.options['id'] == id, 'derive - id: ' + id + ' not in options'
|
|
1731
|
+
request = None
|
|
1732
|
+
try:
|
|
1733
|
+
params = {
|
|
1734
|
+
'subaccount_id': 1234,
|
|
1735
|
+
'max_fee': 10,
|
|
1736
|
+
'deriveWalletAddress': '0x0ad42b8e602c2d3d475ae52d678cf63d84ab2749',
|
|
1737
|
+
}
|
|
1738
|
+
exchange.walletAddress = '0x0ad42b8e602c2d3d475ae52d678cf63d84ab2749'
|
|
1739
|
+
exchange.privateKey = '0x7b77bb7b20e92bbb85f2a22b330b896959229a5790e35f2f290922de3fb22ad5'
|
|
1740
|
+
await exchange.create_order('LBTC/USDC', 'limit', 'sell', 0.01, 3000, params)
|
|
1741
|
+
except Exception as e:
|
|
1742
|
+
request = json_parse(exchange.last_request_body)
|
|
1743
|
+
assert request['referral_code'] == id, 'derive - referral_code: ' + id + ' not in request.'
|
|
1744
|
+
if not is_sync():
|
|
1745
|
+
await close(exchange)
|
|
1746
|
+
return True
|
|
1747
|
+
|
|
1748
|
+
async def test_mode_trade(self):
|
|
1749
|
+
exchange = self.init_offline_exchange('modetrade')
|
|
1750
|
+
exchange.secret = 'secretsecretsecretsecretsecretsecretsecrets'
|
|
1751
|
+
id = 'CCXTMODE'
|
|
1752
|
+
await exchange.load_markets()
|
|
1753
|
+
request = None
|
|
1754
|
+
try:
|
|
1755
|
+
await exchange.create_order('BTC/USDC:USDC', 'limit', 'buy', 1, 20000)
|
|
1756
|
+
except Exception as e:
|
|
1757
|
+
request = json_parse(exchange.last_request_body)
|
|
1758
|
+
broker_id = request['order_tag']
|
|
1759
|
+
assert broker_id == id, 'modetrade - id: ' + id + ' different from broker_id: ' + broker_id
|
|
1760
|
+
if not is_sync():
|
|
1761
|
+
await close(exchange)
|
|
1762
|
+
return True
|