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_sync.py
CHANGED
|
@@ -9,7 +9,6 @@ class testMainClass:
|
|
|
9
9
|
request_tests = False
|
|
10
10
|
ws_tests = False
|
|
11
11
|
response_tests = False
|
|
12
|
-
static_tests = False
|
|
13
12
|
info = False
|
|
14
13
|
verbose = False
|
|
15
14
|
debug = False
|
|
@@ -47,16 +46,16 @@ class testMainClass:
|
|
|
47
46
|
if self.request_tests and self.response_tests:
|
|
48
47
|
self.run_static_request_tests(exchange_id, symbol_argv)
|
|
49
48
|
self.run_static_response_tests(exchange_id, symbol_argv)
|
|
50
|
-
return
|
|
49
|
+
return True
|
|
51
50
|
if self.response_tests:
|
|
52
51
|
self.run_static_response_tests(exchange_id, symbol_argv)
|
|
53
|
-
return
|
|
52
|
+
return True
|
|
54
53
|
if self.request_tests:
|
|
55
54
|
self.run_static_request_tests(exchange_id, symbol_argv) # symbol here is the testname
|
|
56
|
-
return
|
|
55
|
+
return True
|
|
57
56
|
if self.id_tests:
|
|
58
57
|
self.run_broker_id_tests()
|
|
59
|
-
return
|
|
58
|
+
return True
|
|
60
59
|
new_line = '\n'
|
|
61
60
|
dump(new_line + '' + new_line + '' + '[INFO] TESTING ', self.ext, {
|
|
62
61
|
'exchange': exchange_id,
|
|
@@ -101,6 +100,7 @@ class testMainClass:
|
|
|
101
100
|
self.test_files = get_test_files_sync(properties, self.ws_tests)
|
|
102
101
|
else:
|
|
103
102
|
self.test_files = get_test_files(properties, self.ws_tests)
|
|
103
|
+
return True
|
|
104
104
|
|
|
105
105
|
def load_credentials_from_env(self, exchange):
|
|
106
106
|
exchange_id = exchange.id
|
|
@@ -123,8 +123,12 @@ class testMainClass:
|
|
|
123
123
|
keys_local = get_root_dir() + 'keys.local.json'
|
|
124
124
|
keys_global_exists = io_file_exists(keys_global)
|
|
125
125
|
keys_local_exists = io_file_exists(keys_local)
|
|
126
|
-
global_settings =
|
|
127
|
-
|
|
126
|
+
global_settings = {}
|
|
127
|
+
if keys_global_exists:
|
|
128
|
+
global_settings = io_file_read(keys_global)
|
|
129
|
+
local_settings = {}
|
|
130
|
+
if keys_local_exists:
|
|
131
|
+
local_settings = io_file_read(keys_local)
|
|
128
132
|
all_settings = exchange.deep_extend(global_settings, local_settings)
|
|
129
133
|
exchange_settings = exchange.safe_value(all_settings, exchange_id, {})
|
|
130
134
|
if exchange_settings:
|
|
@@ -175,19 +179,20 @@ class testMainClass:
|
|
|
175
179
|
exchange.options['checksum'] = False
|
|
176
180
|
# todo: temporary skip for php
|
|
177
181
|
if 'OrderBook' in method_name and self.ext == 'php':
|
|
178
|
-
return
|
|
182
|
+
return True
|
|
179
183
|
skipped_properties_for_method = self.get_skips(exchange, method_name)
|
|
180
184
|
is_load_markets = (method_name == 'loadMarkets')
|
|
181
185
|
is_fetch_currencies = (method_name == 'fetchCurrencies')
|
|
182
186
|
is_proxy_test = (method_name == self.proxy_test_file_name)
|
|
187
|
+
is_feature_test = (method_name == 'features')
|
|
183
188
|
# 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)
|
|
184
189
|
if not is_public and (method_name in self.checked_public_tests) and not is_fetch_currencies:
|
|
185
|
-
return
|
|
190
|
+
return True
|
|
186
191
|
skip_message = None
|
|
187
192
|
supported_by_exchange = (method_name in exchange.has) and exchange.has[method_name]
|
|
188
193
|
if not is_load_markets and (len(self.only_specific_tests) > 0 and not exchange.in_array(method_name, self.only_specific_tests)):
|
|
189
194
|
skip_message = '[INFO] IGNORED_TEST'
|
|
190
|
-
elif not is_load_markets and not supported_by_exchange and not is_proxy_test:
|
|
195
|
+
elif not is_load_markets and not supported_by_exchange and not is_proxy_test and not is_feature_test:
|
|
191
196
|
skip_message = '[INFO] UNSUPPORTED_TEST' # keep it aligned with the longest message
|
|
192
197
|
elif isinstance(skipped_properties_for_method, str):
|
|
193
198
|
skip_message = '[INFO] SKIPPED_TEST'
|
|
@@ -200,7 +205,7 @@ class testMainClass:
|
|
|
200
205
|
if skip_message:
|
|
201
206
|
if self.info:
|
|
202
207
|
dump(self.add_padding(skip_message, 25), name, method_name)
|
|
203
|
-
return
|
|
208
|
+
return True
|
|
204
209
|
if self.info:
|
|
205
210
|
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"
|
|
206
211
|
dump(self.add_padding('[INFO] TESTING', 25), name, method_name, args_stringified)
|
|
@@ -213,7 +218,7 @@ class testMainClass:
|
|
|
213
218
|
# add to the list of successed tests
|
|
214
219
|
if is_public:
|
|
215
220
|
self.checked_public_tests[method_name] = True
|
|
216
|
-
return
|
|
221
|
+
return True
|
|
217
222
|
|
|
218
223
|
def get_skips(self, exchange, method_name):
|
|
219
224
|
final_skips = {}
|
|
@@ -282,10 +287,10 @@ class testMainClass:
|
|
|
282
287
|
is_on_maintenance = (isinstance(e, OnMaintenance))
|
|
283
288
|
is_exchange_not_available = (isinstance(e, ExchangeNotAvailable))
|
|
284
289
|
should_fail = None
|
|
285
|
-
|
|
290
|
+
ret_success = None
|
|
286
291
|
if is_load_markets:
|
|
287
292
|
# if "loadMarkets" does not succeed, we must return "false" to caller method, to stop tests continual
|
|
288
|
-
|
|
293
|
+
ret_success = False
|
|
289
294
|
# we might not break exchange tests, if exchange is on maintenance at this moment
|
|
290
295
|
if is_on_maintenance:
|
|
291
296
|
should_fail = False
|
|
@@ -296,20 +301,19 @@ class testMainClass:
|
|
|
296
301
|
if is_exchange_not_available and not is_on_maintenance:
|
|
297
302
|
# break exchange tests if "ExchangeNotAvailable" exception is thrown, but it's not maintenance
|
|
298
303
|
should_fail = True
|
|
299
|
-
|
|
304
|
+
ret_success = False
|
|
300
305
|
else:
|
|
301
306
|
# in all other cases of OperationFailed, show Warning, but don't mark test as failed
|
|
302
307
|
should_fail = False
|
|
303
|
-
|
|
308
|
+
ret_success = True
|
|
304
309
|
# output the message
|
|
305
310
|
fail_type = '[TEST_FAILURE]' if should_fail else '[TEST_WARNING]'
|
|
306
311
|
dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ', exchange.id, method_name, args_stringified, exception_message(e))
|
|
307
|
-
return
|
|
312
|
+
return ret_success
|
|
308
313
|
else:
|
|
309
314
|
# wait and retry again
|
|
310
315
|
# (increase wait time on every retry)
|
|
311
316
|
exchange.sleep((i + 1) * 1000)
|
|
312
|
-
continue
|
|
313
317
|
else:
|
|
314
318
|
# if it's loadMarkets, then fail test, because it's mandatory for tests
|
|
315
319
|
if is_load_markets:
|
|
@@ -333,6 +337,7 @@ class testMainClass:
|
|
|
333
337
|
|
|
334
338
|
def run_public_tests(self, exchange, symbol):
|
|
335
339
|
tests = {
|
|
340
|
+
'features': [],
|
|
336
341
|
'fetchCurrencies': [],
|
|
337
342
|
'fetchTicker': [symbol],
|
|
338
343
|
'fetchTickers': [symbol],
|
|
@@ -340,7 +345,6 @@ class testMainClass:
|
|
|
340
345
|
'fetchOHLCV': [symbol],
|
|
341
346
|
'fetchTrades': [symbol],
|
|
342
347
|
'fetchOrderBook': [symbol],
|
|
343
|
-
'fetchL2OrderBook': [symbol],
|
|
344
348
|
'fetchOrderBooks': [],
|
|
345
349
|
'fetchBidsAsks': [],
|
|
346
350
|
'fetchStatus': [],
|
|
@@ -372,6 +376,7 @@ class testMainClass:
|
|
|
372
376
|
tests['fetchPremiumIndexOHLCV'] = [symbol]
|
|
373
377
|
self.public_tests = tests
|
|
374
378
|
self.run_tests(exchange, tests, True)
|
|
379
|
+
return True
|
|
375
380
|
|
|
376
381
|
def run_tests(self, exchange, tests, is_public_test):
|
|
377
382
|
test_names = list(tests.keys())
|
|
@@ -396,6 +401,7 @@ class testMainClass:
|
|
|
396
401
|
dump('[TEST_FAILURE]', exchange.id, test_prefix_string, 'Failed methods : ' + errors_string)
|
|
397
402
|
if self.info:
|
|
398
403
|
dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' + exchange.id, 25))
|
|
404
|
+
return True
|
|
399
405
|
|
|
400
406
|
def load_exchange(self, exchange):
|
|
401
407
|
result = self.test_safe('loadMarkets', exchange, [], True)
|
|
@@ -516,11 +522,12 @@ class testMainClass:
|
|
|
516
522
|
if exchange.has['swap'] and swap_symbol is not None:
|
|
517
523
|
exchange.options['defaultType'] = 'swap'
|
|
518
524
|
self.run_private_tests(exchange, swap_symbol)
|
|
525
|
+
return True
|
|
519
526
|
|
|
520
527
|
def run_private_tests(self, exchange, symbol):
|
|
521
528
|
if not exchange.check_required_credentials(False):
|
|
522
529
|
dump('[INFO] Skipping private tests', 'Keys not found')
|
|
523
|
-
return
|
|
530
|
+
return True
|
|
524
531
|
code = self.get_exchange_code(exchange)
|
|
525
532
|
# if (exchange.deepExtendedTest) {
|
|
526
533
|
# test ('InvalidNonce', exchange, symbol);
|
|
@@ -557,6 +564,8 @@ class testMainClass:
|
|
|
557
564
|
'fetchBorrowRateHistory': [code],
|
|
558
565
|
'fetchLedgerEntry': [code],
|
|
559
566
|
}
|
|
567
|
+
if get_cli_arg_value('--fundedTests'):
|
|
568
|
+
tests['createOrder'] = [symbol]
|
|
560
569
|
if self.ws_tests:
|
|
561
570
|
tests = {
|
|
562
571
|
'watchBalance': [code],
|
|
@@ -588,14 +597,14 @@ class testMainClass:
|
|
|
588
597
|
proxy_test_name = self.proxy_test_file_name
|
|
589
598
|
# todo: temporary skip for sync py
|
|
590
599
|
if self.ext == 'py' and is_sync():
|
|
591
|
-
return
|
|
600
|
+
return True
|
|
592
601
|
# try proxy several times
|
|
593
602
|
max_retries = 3
|
|
594
603
|
exception = None
|
|
595
604
|
for j in range(0, max_retries):
|
|
596
605
|
try:
|
|
597
606
|
self.test_method(proxy_test_name, exchange, [], True)
|
|
598
|
-
return # if successfull, then end the test
|
|
607
|
+
return True # if successfull, then end the test
|
|
599
608
|
except Exception as e:
|
|
600
609
|
exception = e
|
|
601
610
|
exchange.sleep(j * 1000)
|
|
@@ -604,12 +613,39 @@ class testMainClass:
|
|
|
604
613
|
error_message = '[TEST_FAILURE] Failed ' + proxy_test_name + ' : ' + exception_message(exception)
|
|
605
614
|
# temporary comment the below, because c# transpilation failure
|
|
606
615
|
# throw new Exchange Error (errorMessage.toString ());
|
|
607
|
-
dump('[TEST_WARNING]' +
|
|
616
|
+
dump('[TEST_WARNING]' + error_message)
|
|
617
|
+
return True
|
|
618
|
+
|
|
619
|
+
def check_constructor(self, exchange):
|
|
620
|
+
# todo: this might be moved in base tests later
|
|
621
|
+
if exchange.id == 'binance':
|
|
622
|
+
assert exchange.hostname is None or exchange.hostname == '', 'binance.com hostname should be empty'
|
|
623
|
+
assert exchange.urls['api']['public'] == 'https://api.binance.com/api/v3', 'https://api.binance.com/api/v3 does not match: ' + exchange.urls['api']['public']
|
|
624
|
+
assert ('lending/union/account' in exchange.api['sapi']['get']), 'SAPI should contain the endpoint lending/union/account, ' + json_stringify(exchange.api['sapi']['get'])
|
|
625
|
+
elif exchange.id == 'binanceus':
|
|
626
|
+
assert exchange.hostname == 'binance.us', 'binance.us hostname does not match ' + exchange.hostname
|
|
627
|
+
assert exchange.urls['api']['public'] == 'https://api.binance.us/api/v3', 'https://api.binance.us/api/v3 does not match: ' + exchange.urls['api']['public']
|
|
628
|
+
|
|
629
|
+
def test_return_response_headers(self, exchange):
|
|
630
|
+
if exchange.id != 'binance':
|
|
631
|
+
return False # this test is only for binance exchange for now
|
|
632
|
+
exchange.return_response_headers = True
|
|
633
|
+
ticker = exchange.fetch_ticker('BTC/USDT')
|
|
634
|
+
info = ticker['info']
|
|
635
|
+
headers = info['responseHeaders']
|
|
636
|
+
headers_keys = list(headers.keys())
|
|
637
|
+
assert len(headers_keys) > 0, 'Response headers should not be empty'
|
|
638
|
+
header_values = list(headers.values())
|
|
639
|
+
assert len(header_values) > 0, 'Response headers values should not be empty'
|
|
640
|
+
exchange.return_response_headers = False
|
|
641
|
+
return True
|
|
608
642
|
|
|
609
643
|
def start_test(self, exchange, symbol):
|
|
610
644
|
# we do not need to test aliases
|
|
611
645
|
if exchange.alias:
|
|
612
|
-
return
|
|
646
|
+
return True
|
|
647
|
+
self.check_constructor(exchange)
|
|
648
|
+
# this.testReturnResponseHeaders (exchange);
|
|
613
649
|
if self.sandbox or get_exchange_prop(exchange, 'sandbox'):
|
|
614
650
|
exchange.set_sandbox_mode(True)
|
|
615
651
|
try:
|
|
@@ -617,7 +653,7 @@ class testMainClass:
|
|
|
617
653
|
if not result:
|
|
618
654
|
if not is_sync():
|
|
619
655
|
close(exchange)
|
|
620
|
-
return
|
|
656
|
+
return True
|
|
621
657
|
# if (exchange.id === 'binance') {
|
|
622
658
|
# # 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
|
|
623
659
|
# # this.testProxies (exchange);
|
|
@@ -709,7 +745,7 @@ class testMainClass:
|
|
|
709
745
|
result[key] = value
|
|
710
746
|
return result
|
|
711
747
|
|
|
712
|
-
def
|
|
748
|
+
def assert_new_and_stored_output_inner(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
|
|
713
749
|
if is_null_value(new_output) and is_null_value(stored_output):
|
|
714
750
|
return True
|
|
715
751
|
if not new_output and not stored_output:
|
|
@@ -740,8 +776,8 @@ class testMainClass:
|
|
|
740
776
|
self.assert_new_and_stored_output(exchange, skip_keys, new_item, stored_item, strict_type_check)
|
|
741
777
|
else:
|
|
742
778
|
# built-in types like strings, numbers, booleans
|
|
743
|
-
sanitized_new_output = None if (
|
|
744
|
-
sanitized_stored_output = None if (
|
|
779
|
+
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
|
|
780
|
+
sanitized_stored_output = None if (is_null_value(stored_output)) else stored_output
|
|
745
781
|
new_output_string = str(sanitized_new_output) if sanitized_new_output else 'undefined'
|
|
746
782
|
stored_output_string = str(sanitized_stored_output) if sanitized_stored_output else 'undefined'
|
|
747
783
|
message_error = 'output value mismatch:' + new_output_string + ' != ' + stored_output_string
|
|
@@ -762,7 +798,7 @@ class testMainClass:
|
|
|
762
798
|
is_string = is_computed_string or is_stored_string
|
|
763
799
|
is_undefined = is_computed_undefined or is_stored_undefined # undefined is a perfetly valid value
|
|
764
800
|
if is_boolean or is_string or is_undefined:
|
|
765
|
-
if self.lang == 'C#':
|
|
801
|
+
if (self.lang == 'C#') or (self.lang == 'GO'):
|
|
766
802
|
# tmp c# number comparsion
|
|
767
803
|
is_number = False
|
|
768
804
|
try:
|
|
@@ -791,6 +827,27 @@ class testMainClass:
|
|
|
791
827
|
self.assert_static_error(numeric_new_output == numeric_stored_output, message_error, stored_output, new_output, asserting_key)
|
|
792
828
|
return True # c# requ
|
|
793
829
|
|
|
830
|
+
def assert_new_and_stored_output(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
|
|
831
|
+
res = True
|
|
832
|
+
try:
|
|
833
|
+
res = self.assert_new_and_stored_output_inner(exchange, skip_keys, new_output, stored_output, strict_type_check, asserting_key)
|
|
834
|
+
except Exception as e:
|
|
835
|
+
if self.info:
|
|
836
|
+
error_message = self.var_to_string(new_output) + '(calculated)' + ' != ' + self.var_to_string(stored_output) + '(stored)'
|
|
837
|
+
dump('[TEST_FAILURE_DETAIL]' + error_message)
|
|
838
|
+
raise e
|
|
839
|
+
return res
|
|
840
|
+
|
|
841
|
+
def var_to_string(self, obj=None):
|
|
842
|
+
new_string = None
|
|
843
|
+
if obj is None:
|
|
844
|
+
new_string = 'undefined'
|
|
845
|
+
elif is_null_value(obj):
|
|
846
|
+
new_string = 'null'
|
|
847
|
+
else:
|
|
848
|
+
new_string = json_stringify(obj)
|
|
849
|
+
return new_string
|
|
850
|
+
|
|
794
851
|
def assert_static_request_output(self, exchange, type, skip_keys, stored_url, request_url, stored_output, new_output):
|
|
795
852
|
if stored_url != request_url:
|
|
796
853
|
# remove the host part from the url
|
|
@@ -808,11 +865,11 @@ class testMainClass:
|
|
|
808
865
|
if (stored_url_query is None) and (new_url_query is None):
|
|
809
866
|
# might be a get request without any query parameters
|
|
810
867
|
# example: https://api.gateio.ws/api/v4/delivery/usdt/positions
|
|
811
|
-
return
|
|
868
|
+
return True
|
|
812
869
|
stored_url_params = self.urlencoded_to_dict(stored_url_query)
|
|
813
870
|
new_url_params = self.urlencoded_to_dict(new_url_query)
|
|
814
871
|
self.assert_new_and_stored_output(exchange, skip_keys, new_url_params, stored_url_params)
|
|
815
|
-
return
|
|
872
|
+
return True
|
|
816
873
|
if type == 'json' and (stored_output is not None) and (new_output is not None):
|
|
817
874
|
if isinstance(stored_output, str):
|
|
818
875
|
stored_output = json_parse(stored_output)
|
|
@@ -829,6 +886,7 @@ class testMainClass:
|
|
|
829
886
|
stored_output = self.urlencoded_to_dict(stored_output)
|
|
830
887
|
new_output = self.urlencoded_to_dict(new_output)
|
|
831
888
|
self.assert_new_and_stored_output(exchange, skip_keys, new_output, stored_output)
|
|
889
|
+
return True
|
|
832
890
|
|
|
833
891
|
def assert_static_response_output(self, exchange, skip_keys, computed_result, stored_result):
|
|
834
892
|
self.assert_new_and_stored_output(exchange, skip_keys, computed_result, stored_result, False)
|
|
@@ -849,6 +907,8 @@ class testMainClass:
|
|
|
849
907
|
def test_request_statically(self, exchange, method, data, type, skip_keys):
|
|
850
908
|
output = None
|
|
851
909
|
request_url = None
|
|
910
|
+
if self.info:
|
|
911
|
+
dump('[INFO] STATIC REQUEST TEST:', method, ':', data['description'])
|
|
852
912
|
try:
|
|
853
913
|
if not is_sync():
|
|
854
914
|
call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
|
|
@@ -864,12 +924,15 @@ class testMainClass:
|
|
|
864
924
|
self.assert_static_request_output(exchange, type, skip_keys, data['url'], request_url, call_output, output)
|
|
865
925
|
except Exception as e:
|
|
866
926
|
self.request_tests_failed = True
|
|
867
|
-
error_message = '[' + self.lang + '][STATIC_REQUEST]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' +
|
|
927
|
+
error_message = '[' + self.lang + '][STATIC_REQUEST]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + exception_message(e)
|
|
868
928
|
dump('[TEST_FAILURE]' + error_message)
|
|
929
|
+
return True
|
|
869
930
|
|
|
870
931
|
def test_response_statically(self, exchange, method, skip_keys, data):
|
|
871
932
|
expected_result = exchange.safe_value(data, 'parsedResponse')
|
|
872
933
|
mocked_exchange = set_fetch_response(exchange, data['httpResponse'])
|
|
934
|
+
if self.info:
|
|
935
|
+
dump('[INFO] STATIC RESPONSE TEST:', method, ':', data['description'])
|
|
873
936
|
try:
|
|
874
937
|
if not is_sync():
|
|
875
938
|
unified_result = call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
|
|
@@ -879,13 +942,15 @@ class testMainClass:
|
|
|
879
942
|
self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
|
|
880
943
|
except Exception as e:
|
|
881
944
|
self.response_tests_failed = True
|
|
882
|
-
error_message = '[' + self.lang + '][STATIC_RESPONSE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' +
|
|
945
|
+
error_message = '[' + self.lang + '][STATIC_RESPONSE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + exception_message(e)
|
|
883
946
|
dump('[TEST_FAILURE]' + error_message)
|
|
884
947
|
set_fetch_response(exchange, None) # reset state
|
|
948
|
+
return True
|
|
885
949
|
|
|
886
950
|
def init_offline_exchange(self, exchange_name):
|
|
887
951
|
markets = self.load_markets_from_file(exchange_name)
|
|
888
952
|
currencies = self.load_currencies_from_file(exchange_name)
|
|
953
|
+
# we add "proxy" 2 times to intentionally trigger InvalidProxySettings
|
|
889
954
|
exchange = init_exchange(exchange_name, {
|
|
890
955
|
'markets': markets,
|
|
891
956
|
'currencies': currencies,
|
|
@@ -900,7 +965,8 @@ class testMainClass:
|
|
|
900
965
|
'privateKey': '0xff3bdd43534543d421f05aec535965b5050ad6ac15345435345435453495e771',
|
|
901
966
|
'uid': 'uid',
|
|
902
967
|
'token': 'token',
|
|
903
|
-
'
|
|
968
|
+
'login': 'login',
|
|
969
|
+
'accountId': '12345',
|
|
904
970
|
'accounts': [{
|
|
905
971
|
'id': 'myAccount',
|
|
906
972
|
'code': 'USDT',
|
|
@@ -916,7 +982,8 @@ class testMainClass:
|
|
|
916
982
|
'leverageBrackets': {},
|
|
917
983
|
},
|
|
918
984
|
})
|
|
919
|
-
exchange.currencies = currencies
|
|
985
|
+
exchange.currencies = currencies
|
|
986
|
+
# not working in python if assigned in the config dict
|
|
920
987
|
return exchange
|
|
921
988
|
|
|
922
989
|
def test_exchange_request_statically(self, exchange_name, exchange_data, test_name=None):
|
|
@@ -936,6 +1003,9 @@ class testMainClass:
|
|
|
936
1003
|
wallet_address = exchange.safe_string(exchange_data, 'walletAddress')
|
|
937
1004
|
if wallet_address:
|
|
938
1005
|
exchange.walletAddress = str(wallet_address)
|
|
1006
|
+
accounts = exchange.safe_list(exchange_data, 'accounts')
|
|
1007
|
+
if accounts:
|
|
1008
|
+
exchange.accounts = accounts
|
|
939
1009
|
# exchange.options = exchange.deepExtend (exchange.options, globalOptions); # custom options to be used in the tests
|
|
940
1010
|
exchange.extend_exchange_options(global_options)
|
|
941
1011
|
methods = exchange.safe_value(exchange_data, 'methods', {})
|
|
@@ -961,12 +1031,14 @@ class testMainClass:
|
|
|
961
1031
|
is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
|
|
962
1032
|
if is_disabled_c_sharp and (self.lang == 'C#'):
|
|
963
1033
|
continue
|
|
1034
|
+
is_disabled_go = exchange.safe_bool(result, 'disabledGO', False)
|
|
1035
|
+
if is_disabled_go and (self.lang == 'GO'):
|
|
1036
|
+
continue
|
|
964
1037
|
type = exchange.safe_string(exchange_data, 'outputType')
|
|
965
1038
|
skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
|
|
966
1039
|
self.test_request_statically(exchange, method, result, type, skip_keys)
|
|
967
1040
|
# reset options
|
|
968
|
-
|
|
969
|
-
exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
|
|
1041
|
+
exchange.options = exchange.convert_to_safe_dictionary(exchange.deep_extend(old_exchange_options, {}))
|
|
970
1042
|
if not is_sync():
|
|
971
1043
|
close(exchange)
|
|
972
1044
|
return True # in c# methods that will be used with promiseAll need to return something
|
|
@@ -1012,6 +1084,9 @@ class testMainClass:
|
|
|
1012
1084
|
continue
|
|
1013
1085
|
if (test_name is not None) and (test_name != description):
|
|
1014
1086
|
continue
|
|
1087
|
+
is_disabled_go = exchange.safe_bool(result, 'disabledGO', False)
|
|
1088
|
+
if is_disabled_go and (self.lang == 'GO'):
|
|
1089
|
+
continue
|
|
1015
1090
|
skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
|
|
1016
1091
|
self.test_response_statically(exchange, method, skip_keys, result)
|
|
1017
1092
|
# reset options
|
|
@@ -1034,14 +1109,35 @@ class testMainClass:
|
|
|
1034
1109
|
sum = exchange.sum(sum, results_length)
|
|
1035
1110
|
return sum
|
|
1036
1111
|
|
|
1112
|
+
def check_if_exchange_is_disabled(self, exchange_name, exchange_data):
|
|
1113
|
+
exchange = init_exchange('Exchange', {})
|
|
1114
|
+
is_disabled_py = exchange.safe_bool(exchange_data, 'disabledPy', False)
|
|
1115
|
+
if is_disabled_py and (self.lang == 'PY'):
|
|
1116
|
+
dump('[TEST_WARNING] Exchange ' + exchange_name + ' is disabled in python')
|
|
1117
|
+
return True
|
|
1118
|
+
is_disabled_php = exchange.safe_bool(exchange_data, 'disabledPHP', False)
|
|
1119
|
+
if is_disabled_php and (self.lang == 'PHP'):
|
|
1120
|
+
dump('[TEST_WARNING] Exchange ' + exchange_name + ' is disabled in php')
|
|
1121
|
+
return True
|
|
1122
|
+
is_disabled_c_sharp = exchange.safe_bool(exchange_data, 'disabledCS', False)
|
|
1123
|
+
if is_disabled_c_sharp and (self.lang == 'C#'):
|
|
1124
|
+
dump('[TEST_WARNING] Exchange ' + exchange_name + ' is disabled in c#')
|
|
1125
|
+
return True
|
|
1126
|
+
is_disabled_go = exchange.safe_bool(exchange_data, 'disabledGO', False)
|
|
1127
|
+
if is_disabled_go and (self.lang == 'GO'):
|
|
1128
|
+
dump('[TEST_WARNING] Exchange ' + exchange_name + ' is disabled in go')
|
|
1129
|
+
return True
|
|
1130
|
+
return False
|
|
1131
|
+
|
|
1037
1132
|
def run_static_request_tests(self, target_exchange=None, test_name=None):
|
|
1038
1133
|
self.run_static_tests('request', target_exchange, test_name)
|
|
1134
|
+
return True
|
|
1039
1135
|
|
|
1040
1136
|
def run_static_tests(self, type, target_exchange=None, test_name=None):
|
|
1041
1137
|
folder = get_root_dir() + './ts/src/test/static/' + type + '/'
|
|
1042
1138
|
static_data = self.load_static_data(folder, target_exchange)
|
|
1043
1139
|
if static_data is None:
|
|
1044
|
-
return
|
|
1140
|
+
return True
|
|
1045
1141
|
exchanges = list(static_data.keys())
|
|
1046
1142
|
exchange = init_exchange('Exchange', {}) # tmp to do the calculations until we have the ast-transpiler transpiling this code
|
|
1047
1143
|
promises = []
|
|
@@ -1053,13 +1149,24 @@ class testMainClass:
|
|
|
1053
1149
|
for i in range(0, len(exchanges)):
|
|
1054
1150
|
exchange_name = exchanges[i]
|
|
1055
1151
|
exchange_data = static_data[exchange_name]
|
|
1152
|
+
disabled = self.check_if_exchange_is_disabled(exchange_name, exchange_data)
|
|
1153
|
+
if disabled:
|
|
1154
|
+
continue
|
|
1056
1155
|
number_of_tests = self.get_number_of_tests_from_exchange(exchange, exchange_data, test_name)
|
|
1057
1156
|
sum = exchange.sum(sum, number_of_tests)
|
|
1058
1157
|
if type == 'request':
|
|
1059
1158
|
promises.append(self.test_exchange_request_statically(exchange_name, exchange_data, test_name))
|
|
1060
1159
|
else:
|
|
1061
1160
|
promises.append(self.test_exchange_response_statically(exchange_name, exchange_data, test_name))
|
|
1062
|
-
|
|
1161
|
+
try:
|
|
1162
|
+
(promises)
|
|
1163
|
+
except Exception as e:
|
|
1164
|
+
if type == 'request':
|
|
1165
|
+
self.request_tests_failed = True
|
|
1166
|
+
else:
|
|
1167
|
+
self.response_tests_failed = True
|
|
1168
|
+
error_message = '[' + self.lang + '][STATIC_REQUEST]' + exception_message(e)
|
|
1169
|
+
dump('[TEST_FAILURE]' + error_message)
|
|
1063
1170
|
if self.request_tests_failed or self.response_tests_failed:
|
|
1064
1171
|
exit_script(1)
|
|
1065
1172
|
else:
|
|
@@ -1072,20 +1179,24 @@ class testMainClass:
|
|
|
1072
1179
|
# --- Init of mockResponses tests functions------------------------------------
|
|
1073
1180
|
# -----------------------------------------------------------------------------
|
|
1074
1181
|
self.run_static_tests('response', exchange_name, test)
|
|
1182
|
+
return True
|
|
1075
1183
|
|
|
1076
1184
|
def run_broker_id_tests(self):
|
|
1077
1185
|
# -----------------------------------------------------------------------------
|
|
1078
1186
|
# --- Init of brokerId tests functions-----------------------------------------
|
|
1079
1187
|
# -----------------------------------------------------------------------------
|
|
1080
|
-
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.
|
|
1188
|
+
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()]
|
|
1081
1189
|
(promises)
|
|
1082
1190
|
success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
|
|
1083
1191
|
dump('[INFO]' + success_message)
|
|
1084
1192
|
exit_script(0)
|
|
1193
|
+
return True
|
|
1085
1194
|
|
|
1086
1195
|
def test_binance(self):
|
|
1087
1196
|
exchange = self.init_offline_exchange('binance')
|
|
1088
|
-
spot_id = 'x-
|
|
1197
|
+
spot_id = 'x-TKT5PX2F'
|
|
1198
|
+
swap_id = 'x-cvBPrNm9'
|
|
1199
|
+
inverse_swap_id = 'x-xcKtGhcu'
|
|
1089
1200
|
spot_order_request = None
|
|
1090
1201
|
try:
|
|
1091
1202
|
exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
|
|
@@ -1094,7 +1205,6 @@ class testMainClass:
|
|
|
1094
1205
|
client_order_id = spot_order_request['newClientOrderId']
|
|
1095
1206
|
spot_id_string = str(spot_id)
|
|
1096
1207
|
assert client_order_id.startswith(spot_id_string), 'binance - spot clientOrderId: ' + client_order_id + ' does not start with spotId' + spot_id_string
|
|
1097
|
-
swap_id = 'x-xcKtGhcu'
|
|
1098
1208
|
swap_order_request = None
|
|
1099
1209
|
try:
|
|
1100
1210
|
exchange.create_order('BTC/USDT:USDT', 'limit', 'buy', 1, 20000)
|
|
@@ -1105,11 +1215,35 @@ class testMainClass:
|
|
|
1105
1215
|
exchange.create_order('BTC/USD:BTC', 'limit', 'buy', 1, 20000)
|
|
1106
1216
|
except Exception as e:
|
|
1107
1217
|
swap_inverse_order_request = self.urlencoded_to_dict(exchange.last_request_body)
|
|
1218
|
+
# linear swap
|
|
1108
1219
|
client_order_id_swap = swap_order_request['newClientOrderId']
|
|
1109
1220
|
swap_id_string = str(swap_id)
|
|
1110
1221
|
assert client_order_id_swap.startswith(swap_id_string), 'binance - swap clientOrderId: ' + client_order_id_swap + ' does not start with swapId' + swap_id_string
|
|
1222
|
+
# inverse swap
|
|
1111
1223
|
client_order_id_inverse = swap_inverse_order_request['newClientOrderId']
|
|
1112
|
-
assert client_order_id_inverse.startswith(
|
|
1224
|
+
assert client_order_id_inverse.startswith(inverse_swap_id), 'binance - swap clientOrderIdInverse: ' + client_order_id_inverse + ' does not start with swapId' + inverse_swap_id
|
|
1225
|
+
create_orders_request = None
|
|
1226
|
+
try:
|
|
1227
|
+
orders = [{
|
|
1228
|
+
'symbol': 'BTC/USDT:USDT',
|
|
1229
|
+
'type': 'limit',
|
|
1230
|
+
'side': 'sell',
|
|
1231
|
+
'amount': 1,
|
|
1232
|
+
'price': 100000,
|
|
1233
|
+
}, {
|
|
1234
|
+
'symbol': 'BTC/USDT:USDT',
|
|
1235
|
+
'type': 'market',
|
|
1236
|
+
'side': 'buy',
|
|
1237
|
+
'amount': 1,
|
|
1238
|
+
}]
|
|
1239
|
+
exchange.create_orders(orders)
|
|
1240
|
+
except Exception as e:
|
|
1241
|
+
create_orders_request = self.urlencoded_to_dict(exchange.last_request_body)
|
|
1242
|
+
batch_orders = create_orders_request['batchOrders']
|
|
1243
|
+
for i in range(0, len(batch_orders)):
|
|
1244
|
+
current = batch_orders[i]
|
|
1245
|
+
current_client_order_id = current['newClientOrderId']
|
|
1246
|
+
assert current_client_order_id.startswith(swap_id_string), 'binance createOrders - clientOrderId: ' + current_client_order_id + ' does not start with swapId' + swap_id_string
|
|
1113
1247
|
if not is_sync():
|
|
1114
1248
|
close(exchange)
|
|
1115
1249
|
return True
|
|
@@ -1273,7 +1407,7 @@ class testMainClass:
|
|
|
1273
1407
|
try:
|
|
1274
1408
|
exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
|
|
1275
1409
|
except Exception as e:
|
|
1276
|
-
spot_order_request =
|
|
1410
|
+
spot_order_request = json_parse(exchange.last_request_body)
|
|
1277
1411
|
broker_id = spot_order_request['broker_id']
|
|
1278
1412
|
id_string = str(id)
|
|
1279
1413
|
assert broker_id.startswith(id_string), 'woo - broker_id: ' + broker_id + ' does not start with id: ' + id_string
|
|
@@ -1335,6 +1469,7 @@ class testMainClass:
|
|
|
1335
1469
|
assert req_headers['X-SOURCE-KEY'] == id, 'bingx - id: ' + id + ' not in headers.'
|
|
1336
1470
|
if not is_sync():
|
|
1337
1471
|
close(exchange)
|
|
1472
|
+
return True
|
|
1338
1473
|
|
|
1339
1474
|
def test_phemex(self):
|
|
1340
1475
|
exchange = self.init_offline_exchange('phemex')
|
|
@@ -1349,6 +1484,7 @@ class testMainClass:
|
|
|
1349
1484
|
assert client_order_id.startswith(id_string), 'phemex - clOrdID: ' + client_order_id + ' does not start with id: ' + id_string
|
|
1350
1485
|
if not is_sync():
|
|
1351
1486
|
close(exchange)
|
|
1487
|
+
return True
|
|
1352
1488
|
|
|
1353
1489
|
def test_blofin(self):
|
|
1354
1490
|
exchange = self.init_offline_exchange('blofin')
|
|
@@ -1363,20 +1499,24 @@ class testMainClass:
|
|
|
1363
1499
|
assert broker_id.startswith(id_string), 'blofin - brokerId: ' + broker_id + ' does not start with id: ' + id_string
|
|
1364
1500
|
if not is_sync():
|
|
1365
1501
|
close(exchange)
|
|
1502
|
+
return True
|
|
1366
1503
|
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1504
|
+
# testHyperliquid () {
|
|
1505
|
+
# const exchange = this.initOfflineExchange ('hyperliquid');
|
|
1506
|
+
# const id = '1';
|
|
1507
|
+
# let request = undefined;
|
|
1508
|
+
# try {
|
|
1509
|
+
# exchange.createOrder ('SOL/USDC:USDC', 'limit', 'buy', 1, 100);
|
|
1510
|
+
# } catch (e) {
|
|
1511
|
+
# request = jsonParse (exchange.last_request_body);
|
|
1512
|
+
# }
|
|
1513
|
+
# const brokerId = (request['action']['brokerCode']).toString ();
|
|
1514
|
+
# assert (brokerId === id, 'hyperliquid - brokerId: ' + brokerId + ' does not start with id: ' + id);
|
|
1515
|
+
# if (!isSync ()) {
|
|
1516
|
+
# close (exchange);
|
|
1517
|
+
# }
|
|
1518
|
+
# return true;
|
|
1519
|
+
# }
|
|
1380
1520
|
def test_coinbaseinternational(self):
|
|
1381
1521
|
exchange = self.init_offline_exchange('coinbaseinternational')
|
|
1382
1522
|
exchange.options['portfolio'] = 'random'
|
|
@@ -1553,3 +1693,67 @@ class testMainClass:
|
|
|
1553
1693
|
if not is_sync():
|
|
1554
1694
|
close(exchange)
|
|
1555
1695
|
return True
|
|
1696
|
+
|
|
1697
|
+
def test_defx(self):
|
|
1698
|
+
exchange = self.init_offline_exchange('defx')
|
|
1699
|
+
req_headers = None
|
|
1700
|
+
try:
|
|
1701
|
+
exchange.create_order('DOGE/USDC:USDC', 'limit', 'buy', 100, 1)
|
|
1702
|
+
except Exception as e:
|
|
1703
|
+
# we expect an error here, we're only interested in the headers
|
|
1704
|
+
req_headers = exchange.last_request_headers
|
|
1705
|
+
id = 'ccxt'
|
|
1706
|
+
assert req_headers['X-DEFX-SOURCE'] == id, 'defx - id: ' + id + ' not in headers.'
|
|
1707
|
+
if not is_sync():
|
|
1708
|
+
close(exchange)
|
|
1709
|
+
return True
|
|
1710
|
+
|
|
1711
|
+
def test_cryptomus(self):
|
|
1712
|
+
exchange = self.init_offline_exchange('cryptomus')
|
|
1713
|
+
request = None
|
|
1714
|
+
try:
|
|
1715
|
+
exchange.create_order('BTC/USDT', 'limit', 'sell', 1, 20000)
|
|
1716
|
+
except Exception as e:
|
|
1717
|
+
request = json_parse(exchange.last_request_body)
|
|
1718
|
+
tag = 'ccxt'
|
|
1719
|
+
assert request['tag'] == tag, 'cryptomus - tag: ' + tag + ' not in request.'
|
|
1720
|
+
if not is_sync():
|
|
1721
|
+
close(exchange)
|
|
1722
|
+
return True
|
|
1723
|
+
|
|
1724
|
+
def test_derive(self):
|
|
1725
|
+
exchange = self.init_offline_exchange('derive')
|
|
1726
|
+
id = '0x0ad42b8e602c2d3d475ae52d678cf63d84ab2749'
|
|
1727
|
+
assert exchange.options['id'] == id, 'derive - id: ' + id + ' not in options'
|
|
1728
|
+
request = None
|
|
1729
|
+
try:
|
|
1730
|
+
params = {
|
|
1731
|
+
'subaccount_id': 1234,
|
|
1732
|
+
'max_fee': 10,
|
|
1733
|
+
'deriveWalletAddress': '0x0ad42b8e602c2d3d475ae52d678cf63d84ab2749',
|
|
1734
|
+
}
|
|
1735
|
+
exchange.walletAddress = '0x0ad42b8e602c2d3d475ae52d678cf63d84ab2749'
|
|
1736
|
+
exchange.privateKey = '0x7b77bb7b20e92bbb85f2a22b330b896959229a5790e35f2f290922de3fb22ad5'
|
|
1737
|
+
exchange.create_order('LBTC/USDC', 'limit', 'sell', 0.01, 3000, params)
|
|
1738
|
+
except Exception as e:
|
|
1739
|
+
request = json_parse(exchange.last_request_body)
|
|
1740
|
+
assert request['referral_code'] == id, 'derive - referral_code: ' + id + ' not in request.'
|
|
1741
|
+
if not is_sync():
|
|
1742
|
+
close(exchange)
|
|
1743
|
+
return True
|
|
1744
|
+
|
|
1745
|
+
def test_mode_trade(self):
|
|
1746
|
+
exchange = self.init_offline_exchange('modetrade')
|
|
1747
|
+
exchange.secret = 'secretsecretsecretsecretsecretsecretsecrets'
|
|
1748
|
+
id = 'CCXTMODE'
|
|
1749
|
+
exchange.load_markets()
|
|
1750
|
+
request = None
|
|
1751
|
+
try:
|
|
1752
|
+
exchange.create_order('BTC/USDC:USDC', 'limit', 'buy', 1, 20000)
|
|
1753
|
+
except Exception as e:
|
|
1754
|
+
request = json_parse(exchange.last_request_body)
|
|
1755
|
+
broker_id = request['order_tag']
|
|
1756
|
+
assert broker_id == id, 'modetrade - id: ' + id + ' different from broker_id: ' + broker_id
|
|
1757
|
+
if not is_sync():
|
|
1758
|
+
close(exchange)
|
|
1759
|
+
return True
|