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/async_support/cex.py
CHANGED
|
@@ -5,76 +5,103 @@
|
|
|
5
5
|
|
|
6
6
|
from ccxt.async_support.base.exchange import Exchange
|
|
7
7
|
from ccxt.abstract.cex import ImplicitAPI
|
|
8
|
+
import asyncio
|
|
8
9
|
import hashlib
|
|
9
|
-
import
|
|
10
|
-
from ccxt.base.types import Balances, Currencies, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees
|
|
10
|
+
from ccxt.base.types import Account, Any, Balances, Currencies, Currency, DepositAddress, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees, Transaction, TransferEntry
|
|
11
11
|
from typing import List
|
|
12
12
|
from ccxt.base.errors import ExchangeError
|
|
13
13
|
from ccxt.base.errors import AuthenticationError
|
|
14
|
+
from ccxt.base.errors import PermissionDenied
|
|
14
15
|
from ccxt.base.errors import ArgumentsRequired
|
|
15
|
-
from ccxt.base.errors import
|
|
16
|
-
from ccxt.base.errors import NullResponse
|
|
16
|
+
from ccxt.base.errors import BadRequest
|
|
17
17
|
from ccxt.base.errors import InsufficientFunds
|
|
18
|
-
from ccxt.base.errors import
|
|
19
|
-
from ccxt.base.errors import OrderNotFound
|
|
20
|
-
from ccxt.base.errors import DDoSProtection
|
|
21
|
-
from ccxt.base.errors import RateLimitExceeded
|
|
22
|
-
from ccxt.base.errors import InvalidNonce
|
|
18
|
+
from ccxt.base.errors import NullResponse
|
|
23
19
|
from ccxt.base.decimal_to_precision import TICK_SIZE
|
|
24
20
|
from ccxt.base.precise import Precise
|
|
25
21
|
|
|
26
22
|
|
|
27
23
|
class cex(Exchange, ImplicitAPI):
|
|
28
24
|
|
|
29
|
-
def describe(self):
|
|
25
|
+
def describe(self) -> Any:
|
|
30
26
|
return self.deep_extend(super(cex, self).describe(), {
|
|
31
27
|
'id': 'cex',
|
|
32
28
|
'name': 'CEX.IO',
|
|
33
29
|
'countries': ['GB', 'EU', 'CY', 'RU'],
|
|
34
|
-
'rateLimit':
|
|
30
|
+
'rateLimit': 300, # 200 req/min
|
|
35
31
|
'pro': True,
|
|
36
32
|
'has': {
|
|
37
33
|
'CORS': None,
|
|
38
34
|
'spot': True,
|
|
39
|
-
'margin': False, # has but not through api
|
|
35
|
+
'margin': False, # has, but not through api
|
|
40
36
|
'swap': False,
|
|
41
37
|
'future': False,
|
|
42
38
|
'option': False,
|
|
43
39
|
'addMargin': False,
|
|
40
|
+
'borrowCrossMargin': False,
|
|
41
|
+
'borrowIsolatedMargin': False,
|
|
42
|
+
'borrowMargin': False,
|
|
44
43
|
'cancelAllOrders': True,
|
|
45
44
|
'cancelOrder': True,
|
|
46
|
-
'
|
|
47
|
-
'
|
|
48
|
-
'createMarketBuyOrderWithCost': True,
|
|
49
|
-
'createMarketOrderWithCost': False,
|
|
50
|
-
'createMarketSellOrderWithCost': False,
|
|
45
|
+
'closeAllPositions': False,
|
|
46
|
+
'closePosition': False,
|
|
51
47
|
'createOrder': True,
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
-
'
|
|
48
|
+
'createOrderWithTakeProfitAndStopLoss': False,
|
|
49
|
+
'createOrderWithTakeProfitAndStopLossWs': False,
|
|
50
|
+
'createPostOnlyOrder': False,
|
|
51
|
+
'createReduceOnlyOrder': False,
|
|
52
|
+
'createStopOrder': True,
|
|
53
|
+
'createTriggerOrder': True,
|
|
54
|
+
'fetchAccounts': True,
|
|
56
55
|
'fetchBalance': True,
|
|
56
|
+
'fetchBorrowInterest': False,
|
|
57
|
+
'fetchBorrowRate': False,
|
|
58
|
+
'fetchBorrowRateHistories': False,
|
|
59
|
+
'fetchBorrowRateHistory': False,
|
|
60
|
+
'fetchBorrowRates': False,
|
|
61
|
+
'fetchBorrowRatesPerSymbol': False,
|
|
62
|
+
'fetchClosedOrder': True,
|
|
57
63
|
'fetchClosedOrders': True,
|
|
64
|
+
'fetchCrossBorrowRate': False,
|
|
65
|
+
'fetchCrossBorrowRates': False,
|
|
58
66
|
'fetchCurrencies': True,
|
|
59
|
-
'fetchDeposit': False,
|
|
60
67
|
'fetchDepositAddress': True,
|
|
61
|
-
'
|
|
62
|
-
'fetchDeposits': False,
|
|
63
|
-
'fetchDepositsWithdrawals': False,
|
|
68
|
+
'fetchDepositsWithdrawals': True,
|
|
64
69
|
'fetchFundingHistory': False,
|
|
70
|
+
'fetchFundingInterval': False,
|
|
71
|
+
'fetchFundingIntervals': False,
|
|
65
72
|
'fetchFundingRate': False,
|
|
66
73
|
'fetchFundingRateHistory': False,
|
|
67
74
|
'fetchFundingRates': False,
|
|
75
|
+
'fetchGreeks': False,
|
|
68
76
|
'fetchIndexOHLCV': False,
|
|
77
|
+
'fetchIsolatedBorrowRate': False,
|
|
78
|
+
'fetchIsolatedBorrowRates': False,
|
|
79
|
+
'fetchIsolatedPositions': False,
|
|
80
|
+
'fetchLedger': True,
|
|
81
|
+
'fetchLeverage': False,
|
|
82
|
+
'fetchLeverages': False,
|
|
83
|
+
'fetchLeverageTiers': False,
|
|
84
|
+
'fetchLiquidations': False,
|
|
85
|
+
'fetchLongShortRatio': False,
|
|
86
|
+
'fetchLongShortRatioHistory': False,
|
|
87
|
+
'fetchMarginAdjustmentHistory': False,
|
|
69
88
|
'fetchMarginMode': False,
|
|
89
|
+
'fetchMarginModes': False,
|
|
90
|
+
'fetchMarketLeverageTiers': False,
|
|
70
91
|
'fetchMarkets': True,
|
|
71
92
|
'fetchMarkOHLCV': False,
|
|
93
|
+
'fetchMarkPrices': False,
|
|
94
|
+
'fetchMyLiquidations': False,
|
|
95
|
+
'fetchMySettlementHistory': False,
|
|
72
96
|
'fetchOHLCV': True,
|
|
97
|
+
'fetchOpenInterest': False,
|
|
73
98
|
'fetchOpenInterestHistory': False,
|
|
99
|
+
'fetchOpenInterests': False,
|
|
100
|
+
'fetchOpenOrder': True,
|
|
74
101
|
'fetchOpenOrders': True,
|
|
75
|
-
'
|
|
102
|
+
'fetchOption': False,
|
|
103
|
+
'fetchOptionChain': False,
|
|
76
104
|
'fetchOrderBook': True,
|
|
77
|
-
'fetchOrders': True,
|
|
78
105
|
'fetchPosition': False,
|
|
79
106
|
'fetchPositionHistory': False,
|
|
80
107
|
'fetchPositionMode': False,
|
|
@@ -83,1523 +110,1633 @@ class cex(Exchange, ImplicitAPI):
|
|
|
83
110
|
'fetchPositionsHistory': False,
|
|
84
111
|
'fetchPositionsRisk': False,
|
|
85
112
|
'fetchPremiumIndexOHLCV': False,
|
|
113
|
+
'fetchSettlementHistory': False,
|
|
86
114
|
'fetchTicker': True,
|
|
87
115
|
'fetchTickers': True,
|
|
116
|
+
'fetchTime': True,
|
|
88
117
|
'fetchTrades': True,
|
|
89
|
-
'fetchTradingFee': False,
|
|
90
118
|
'fetchTradingFees': True,
|
|
91
|
-
'
|
|
92
|
-
'fetchTransfer': False,
|
|
93
|
-
'fetchTransfers': False,
|
|
94
|
-
'fetchWithdrawal': False,
|
|
95
|
-
'fetchWithdrawals': False,
|
|
96
|
-
'fetchWithdrawalWhitelist': False,
|
|
119
|
+
'fetchVolatilityHistory': False,
|
|
97
120
|
'reduceMargin': False,
|
|
121
|
+
'repayCrossMargin': False,
|
|
122
|
+
'repayIsolatedMargin': False,
|
|
123
|
+
'repayMargin': False,
|
|
98
124
|
'setLeverage': False,
|
|
99
125
|
'setMargin': False,
|
|
100
126
|
'setMarginMode': False,
|
|
101
|
-
'
|
|
102
|
-
'
|
|
103
|
-
},
|
|
104
|
-
'timeframes': {
|
|
105
|
-
'1m': '1m',
|
|
106
|
-
'1h': '1h',
|
|
107
|
-
'1d': '1d',
|
|
127
|
+
'setPositionMode': False,
|
|
128
|
+
'transfer': True,
|
|
108
129
|
},
|
|
109
130
|
'urls': {
|
|
110
131
|
'logo': 'https://user-images.githubusercontent.com/1294454/27766442-8ddc33b0-5ed8-11e7-8b98-f786aef0f3c9.jpg',
|
|
111
132
|
'api': {
|
|
112
|
-
'
|
|
133
|
+
'public': 'https://trade.cex.io/api/spot/rest-public',
|
|
134
|
+
'private': 'https://trade.cex.io/api/spot/rest',
|
|
113
135
|
},
|
|
114
136
|
'www': 'https://cex.io',
|
|
115
|
-
'doc': 'https://cex.io/
|
|
137
|
+
'doc': 'https://trade.cex.io/docs/',
|
|
116
138
|
'fees': [
|
|
117
139
|
'https://cex.io/fee-schedule',
|
|
118
140
|
'https://cex.io/limits-commissions',
|
|
119
141
|
],
|
|
120
142
|
'referral': 'https://cex.io/r/0/up105393824/0/',
|
|
121
143
|
},
|
|
122
|
-
'requiredCredentials': {
|
|
123
|
-
'apiKey': True,
|
|
124
|
-
'secret': True,
|
|
125
|
-
'uid': True,
|
|
126
|
-
},
|
|
127
144
|
'api': {
|
|
128
145
|
'public': {
|
|
129
|
-
'get':
|
|
130
|
-
|
|
131
|
-
'
|
|
132
|
-
'
|
|
133
|
-
'
|
|
134
|
-
'
|
|
135
|
-
'
|
|
136
|
-
'
|
|
137
|
-
'
|
|
138
|
-
'
|
|
139
|
-
|
|
140
|
-
'post': [
|
|
141
|
-
'convert/{pair}',
|
|
142
|
-
'price_stats/{pair}',
|
|
143
|
-
],
|
|
146
|
+
'get': {},
|
|
147
|
+
'post': {
|
|
148
|
+
'get_server_time': 1,
|
|
149
|
+
'get_pairs_info': 1,
|
|
150
|
+
'get_currencies_info': 1,
|
|
151
|
+
'get_processing_info': 10,
|
|
152
|
+
'get_ticker': 1,
|
|
153
|
+
'get_trade_history': 1,
|
|
154
|
+
'get_order_book': 1,
|
|
155
|
+
'get_candles': 1,
|
|
156
|
+
},
|
|
144
157
|
},
|
|
145
158
|
'private': {
|
|
146
|
-
'
|
|
147
|
-
|
|
148
|
-
'
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
'
|
|
152
|
-
'
|
|
153
|
-
'
|
|
154
|
-
'
|
|
155
|
-
'
|
|
156
|
-
'
|
|
157
|
-
'
|
|
158
|
-
'
|
|
159
|
-
'
|
|
160
|
-
'
|
|
161
|
-
'
|
|
162
|
-
'
|
|
163
|
-
'
|
|
164
|
-
'
|
|
165
|
-
|
|
159
|
+
'get': {},
|
|
160
|
+
'post': {
|
|
161
|
+
'get_my_current_fee': 5,
|
|
162
|
+
'get_fee_strategy': 1,
|
|
163
|
+
'get_my_volume': 5,
|
|
164
|
+
'do_create_account': 1,
|
|
165
|
+
'get_my_account_status_v3': 5,
|
|
166
|
+
'get_my_wallet_balance': 5,
|
|
167
|
+
'get_my_orders': 5,
|
|
168
|
+
'do_my_new_order': 1,
|
|
169
|
+
'do_cancel_my_order': 1,
|
|
170
|
+
'do_cancel_all_orders': 5,
|
|
171
|
+
'get_order_book': 1,
|
|
172
|
+
'get_candles': 1,
|
|
173
|
+
'get_trade_history': 1,
|
|
174
|
+
'get_my_transaction_history': 1,
|
|
175
|
+
'get_my_funding_history': 5,
|
|
176
|
+
'do_my_internal_transfer': 1,
|
|
177
|
+
'get_processing_info': 10,
|
|
178
|
+
'get_deposit_address': 5,
|
|
179
|
+
'do_deposit_funds_from_wallet': 1,
|
|
180
|
+
'do_withdrawal_funds_to_wallet': 1,
|
|
181
|
+
},
|
|
166
182
|
},
|
|
167
183
|
},
|
|
168
|
-
'
|
|
169
|
-
'
|
|
170
|
-
'
|
|
171
|
-
'
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
'
|
|
186
|
-
'
|
|
187
|
-
'
|
|
184
|
+
'features': {
|
|
185
|
+
'spot': {
|
|
186
|
+
'sandbox': False,
|
|
187
|
+
'createOrder': {
|
|
188
|
+
'marginMode': False,
|
|
189
|
+
'triggerPrice': True,
|
|
190
|
+
'triggerPriceType': None,
|
|
191
|
+
'triggerDirection': False,
|
|
192
|
+
'stopLossPrice': False, # todo
|
|
193
|
+
'takeProfitPrice': False, # todo
|
|
194
|
+
'attachedStopLossTakeProfit': None,
|
|
195
|
+
'timeInForce': {
|
|
196
|
+
'IOC': True,
|
|
197
|
+
'FOK': True,
|
|
198
|
+
'PO': False, # todo check
|
|
199
|
+
'GTD': True,
|
|
200
|
+
},
|
|
201
|
+
'hedged': False,
|
|
202
|
+
'leverage': False,
|
|
203
|
+
'marketBuyRequiresPrice': False,
|
|
204
|
+
'marketBuyByCost': True, # todo check
|
|
205
|
+
'selfTradePrevention': False,
|
|
206
|
+
'trailing': False,
|
|
207
|
+
'iceberg': False,
|
|
188
208
|
},
|
|
209
|
+
'createOrders': None,
|
|
210
|
+
'fetchMyTrades': None,
|
|
211
|
+
'fetchOrder': None,
|
|
212
|
+
'fetchOpenOrders': {
|
|
213
|
+
'marginMode': False,
|
|
214
|
+
'limit': 1000,
|
|
215
|
+
'trigger': False,
|
|
216
|
+
'trailing': False,
|
|
217
|
+
'symbolRequired': False,
|
|
218
|
+
},
|
|
219
|
+
'fetchOrders': None,
|
|
220
|
+
'fetchClosedOrders': {
|
|
221
|
+
'marginMode': False,
|
|
222
|
+
'limit': 1000,
|
|
223
|
+
'daysBack': 100000,
|
|
224
|
+
'daysBackCanceled': 1,
|
|
225
|
+
'untilDays': 100000,
|
|
226
|
+
'trigger': False,
|
|
227
|
+
'trailing': False,
|
|
228
|
+
'symbolRequired': False,
|
|
229
|
+
},
|
|
230
|
+
'fetchOHLCV': {
|
|
231
|
+
'limit': 1000,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
'swap': {
|
|
235
|
+
'linear': None,
|
|
236
|
+
'inverse': None,
|
|
237
|
+
},
|
|
238
|
+
'future': {
|
|
239
|
+
'linear': None,
|
|
240
|
+
'inverse': None,
|
|
189
241
|
},
|
|
190
242
|
},
|
|
191
243
|
'precisionMode': TICK_SIZE,
|
|
192
244
|
'exceptions': {
|
|
193
245
|
'exact': {},
|
|
194
246
|
'broad': {
|
|
247
|
+
'You have negative balance on following accounts': InsufficientFunds,
|
|
248
|
+
'Mandatory parameter side should be one of BUY,SELL': BadRequest,
|
|
249
|
+
'API orders from Main account are not allowed': BadRequest,
|
|
250
|
+
'check failed': BadRequest,
|
|
195
251
|
'Insufficient funds': InsufficientFunds,
|
|
196
|
-
'
|
|
197
|
-
'
|
|
198
|
-
'
|
|
199
|
-
'limit exceeded': RateLimitExceeded, # {"error":"rate limit exceeded"}
|
|
200
|
-
'Invalid API key': AuthenticationError,
|
|
201
|
-
'There was an error while placing your order': InvalidOrder,
|
|
202
|
-
'Sorry, too many clients already': DDoSProtection,
|
|
203
|
-
'Invalid Symbols Pair': BadSymbol,
|
|
204
|
-
'Wrong currency pair': BadSymbol, # {"error":"There was an error while placing your order: Wrong currency pair.","safe":true}
|
|
252
|
+
'Get deposit address for main account is not allowed': PermissionDenied,
|
|
253
|
+
'Market Trigger orders are not allowed': BadRequest, # for some reason, triggerPrice does not work for market orders
|
|
254
|
+
'key not passed or incorrect': AuthenticationError,
|
|
205
255
|
},
|
|
206
256
|
},
|
|
257
|
+
'timeframes': {
|
|
258
|
+
'1m': '1m',
|
|
259
|
+
'5m': '5m',
|
|
260
|
+
'15m': '15m',
|
|
261
|
+
'30m': '30m',
|
|
262
|
+
'1h': '1h',
|
|
263
|
+
'2h': '2h',
|
|
264
|
+
'4h': '4h',
|
|
265
|
+
'1d': '1d',
|
|
266
|
+
},
|
|
207
267
|
'options': {
|
|
208
|
-
'fetchOHLCVWarning': True,
|
|
209
|
-
'createMarketBuyOrderRequiresPrice': True,
|
|
210
|
-
'order': {
|
|
211
|
-
'status': {
|
|
212
|
-
'c': 'canceled',
|
|
213
|
-
'd': 'closed',
|
|
214
|
-
'cd': 'canceled',
|
|
215
|
-
'a': 'open',
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
'defaultNetwork': 'ERC20',
|
|
219
|
-
'defaultNetworks': {
|
|
220
|
-
'USDT': 'TRC20',
|
|
221
|
-
},
|
|
222
268
|
'networks': {
|
|
223
|
-
'
|
|
224
|
-
'
|
|
225
|
-
'
|
|
226
|
-
'
|
|
269
|
+
'BTC': 'bitcoin',
|
|
270
|
+
'ERC20': 'ERC20',
|
|
271
|
+
'BSC20': 'binancesmartchain',
|
|
272
|
+
'DOGE': 'dogecoin',
|
|
273
|
+
'ALGO': 'algorand',
|
|
274
|
+
'XLM': 'stellar',
|
|
275
|
+
'ATOM': 'cosmos',
|
|
276
|
+
'LTC': 'litecoin',
|
|
277
|
+
'XRP': 'ripple',
|
|
278
|
+
'FTM': 'fantom',
|
|
279
|
+
'MINA': 'mina',
|
|
280
|
+
'THETA': 'theta',
|
|
281
|
+
'XTZ': 'tezos',
|
|
282
|
+
'TIA': 'celestia',
|
|
283
|
+
'CRONOS': 'cronos', # CRC20
|
|
284
|
+
'MATIC': 'polygon',
|
|
285
|
+
'TON': 'ton',
|
|
286
|
+
'TRC20': 'tron',
|
|
287
|
+
'SOLANA': 'solana',
|
|
288
|
+
'SGB': 'songbird',
|
|
289
|
+
'DYDX': 'dydx',
|
|
290
|
+
'DASH': 'dash',
|
|
291
|
+
'ZIL': 'zilliqa',
|
|
292
|
+
'EOS': 'eos',
|
|
293
|
+
'AVALANCHEC': 'avalanche',
|
|
294
|
+
'ETHPOW': 'ethereumpow',
|
|
295
|
+
'NEAR': 'near',
|
|
296
|
+
'ARB': 'arbitrum',
|
|
297
|
+
'DOT': 'polkadot',
|
|
298
|
+
'OPT': 'optimism',
|
|
299
|
+
'INJ': 'injective',
|
|
300
|
+
'ADA': 'cardano',
|
|
301
|
+
'ONT': 'ontology',
|
|
302
|
+
'ICP': 'icp',
|
|
303
|
+
'KAVA': 'kava',
|
|
304
|
+
'KSM': 'kusama',
|
|
305
|
+
'SEI': 'sei',
|
|
306
|
+
# 'OSM': 'osmosis',
|
|
307
|
+
'NEO': 'neo',
|
|
308
|
+
'NEO3': 'neo3',
|
|
309
|
+
# 'TERRAOLD': 'terra', # tbd
|
|
310
|
+
# 'TERRA': 'terra2', # tbd
|
|
311
|
+
# 'EVER': 'everscale', # tbd
|
|
312
|
+
'XDC': 'xdc',
|
|
227
313
|
},
|
|
228
314
|
},
|
|
229
315
|
})
|
|
230
316
|
|
|
231
|
-
async def fetch_currencies_from_cache(self, params={}):
|
|
232
|
-
# self method is now redundant
|
|
233
|
-
# currencies are now fetched before markets
|
|
234
|
-
options = self.safe_value(self.options, 'fetchCurrencies', {})
|
|
235
|
-
timestamp = self.safe_integer(options, 'timestamp')
|
|
236
|
-
expires = self.safe_integer(options, 'expires', 1000)
|
|
237
|
-
now = self.milliseconds()
|
|
238
|
-
if (timestamp is None) or ((now - timestamp) > expires):
|
|
239
|
-
response = await self.publicGetCurrencyProfile(params)
|
|
240
|
-
self.options['fetchCurrencies'] = self.extend(options, {
|
|
241
|
-
'response': response,
|
|
242
|
-
'timestamp': now,
|
|
243
|
-
})
|
|
244
|
-
return self.safe_value(self.options['fetchCurrencies'], 'response')
|
|
245
|
-
|
|
246
317
|
async def fetch_currencies(self, params={}) -> Currencies:
|
|
247
318
|
"""
|
|
248
319
|
fetches all available currencies on an exchange
|
|
320
|
+
|
|
321
|
+
https://trade.cex.io/docs/#rest-public-api-calls-currencies-info
|
|
322
|
+
|
|
249
323
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
250
324
|
:returns dict: an associative dictionary of currencies
|
|
251
325
|
"""
|
|
252
|
-
|
|
253
|
-
self.
|
|
254
|
-
'timestamp': self.milliseconds(),
|
|
255
|
-
'response': response,
|
|
256
|
-
}
|
|
326
|
+
promises = []
|
|
327
|
+
promises.append(self.publicPostGetCurrenciesInfo(params))
|
|
257
328
|
#
|
|
258
|
-
#
|
|
259
|
-
#
|
|
260
|
-
#
|
|
261
|
-
#
|
|
262
|
-
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
265
|
-
#
|
|
266
|
-
#
|
|
267
|
-
#
|
|
268
|
-
#
|
|
269
|
-
#
|
|
270
|
-
# "scale":0,
|
|
271
|
-
# "minimumCurrencyAmount":"0.00000001",
|
|
272
|
-
# "minimalWithdrawalAmount":-1
|
|
273
|
-
# },
|
|
274
|
-
# {
|
|
275
|
-
# "code":"BTC",
|
|
276
|
-
# "contract":false,
|
|
277
|
-
# "commodity":false,
|
|
278
|
-
# "fiat":false,
|
|
279
|
-
# "description":"",
|
|
280
|
-
# "precision":8,
|
|
281
|
-
# "scale":0,
|
|
282
|
-
# "minimumCurrencyAmount":"0.00000001",
|
|
283
|
-
# "minimalWithdrawalAmount":0.002
|
|
284
|
-
# },
|
|
285
|
-
# {
|
|
286
|
-
# "code":"ETH",
|
|
287
|
-
# "contract":false,
|
|
288
|
-
# "commodity":false,
|
|
289
|
-
# "fiat":false,
|
|
290
|
-
# "description":"",
|
|
291
|
-
# "precision":8,
|
|
292
|
-
# "scale":2,
|
|
293
|
-
# "minimumCurrencyAmount":"0.00000100",
|
|
294
|
-
# "minimalWithdrawalAmount":0.01
|
|
295
|
-
# }
|
|
296
|
-
# ],
|
|
297
|
-
# "pairs":[
|
|
298
|
-
# {
|
|
299
|
-
# "symbol1":"BTC",
|
|
300
|
-
# "symbol2":"USD",
|
|
301
|
-
# "pricePrecision":1,
|
|
302
|
-
# "priceScale":"/1000000",
|
|
303
|
-
# "minLotSize":0.002,
|
|
304
|
-
# "minLotSizeS2":20
|
|
305
|
-
# },
|
|
306
|
-
# {
|
|
307
|
-
# "symbol1":"ETH",
|
|
308
|
-
# "symbol2":"USD",
|
|
309
|
-
# "pricePrecision":2,
|
|
310
|
-
# "priceScale":"/10000",
|
|
311
|
-
# "minLotSize":0.1,
|
|
312
|
-
# "minLotSizeS2":20
|
|
313
|
-
# }
|
|
314
|
-
# ]
|
|
315
|
-
# }
|
|
316
|
-
# }
|
|
329
|
+
# {
|
|
330
|
+
# "ok": "ok",
|
|
331
|
+
# "data": [
|
|
332
|
+
# {
|
|
333
|
+
# "currency": "ZAP",
|
|
334
|
+
# "fiat": False,
|
|
335
|
+
# "precision": "8",
|
|
336
|
+
# "walletPrecision": "6",
|
|
337
|
+
# "walletDeposit": True,
|
|
338
|
+
# "walletWithdrawal": True
|
|
339
|
+
# },
|
|
340
|
+
# ...
|
|
317
341
|
#
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
342
|
+
promises.append(self.publicPostGetProcessingInfo(params))
|
|
343
|
+
#
|
|
344
|
+
# {
|
|
345
|
+
# "ok": "ok",
|
|
346
|
+
# "data": {
|
|
347
|
+
# "ADA": {
|
|
348
|
+
# "name": "Cardano",
|
|
349
|
+
# "blockchains": {
|
|
350
|
+
# "cardano": {
|
|
351
|
+
# "type": "coin",
|
|
352
|
+
# "deposit": "enabled",
|
|
353
|
+
# "minDeposit": "1",
|
|
354
|
+
# "withdrawal": "enabled",
|
|
355
|
+
# "minWithdrawal": "5",
|
|
356
|
+
# "withdrawalFee": "1",
|
|
357
|
+
# "withdrawalFeePercent": "0",
|
|
358
|
+
# "depositConfirmations": "15"
|
|
359
|
+
# }
|
|
360
|
+
# }
|
|
361
|
+
# },
|
|
362
|
+
# ...
|
|
363
|
+
#
|
|
364
|
+
responses = await asyncio.gather(*promises)
|
|
365
|
+
dataCurrencies = self.safe_list(responses[0], 'data', [])
|
|
366
|
+
dataNetworks = self.safe_dict(responses[1], 'data', {})
|
|
367
|
+
currenciesIndexed = self.index_by(dataCurrencies, 'currency')
|
|
368
|
+
data = self.deep_extend(currenciesIndexed, dataNetworks)
|
|
369
|
+
return self.parse_currencies(self.to_array(data))
|
|
370
|
+
|
|
371
|
+
def parse_currency(self, rawCurrency: dict) -> Currency:
|
|
372
|
+
id = self.safe_string(rawCurrency, 'currency')
|
|
373
|
+
code = self.safe_currency_code(id)
|
|
374
|
+
type = 'fiat' if self.safe_bool(rawCurrency, 'fiat') else 'crypto'
|
|
375
|
+
currencyPrecision = self.parse_number(self.parse_precision(self.safe_string(rawCurrency, 'precision')))
|
|
376
|
+
networks: dict = {}
|
|
377
|
+
rawNetworks = self.safe_dict(rawCurrency, 'blockchains', {})
|
|
378
|
+
keys = list(rawNetworks.keys())
|
|
379
|
+
for j in range(0, len(keys)):
|
|
380
|
+
networkId = keys[j]
|
|
381
|
+
rawNetwork = rawNetworks[networkId]
|
|
382
|
+
networkCode = self.network_id_to_code(networkId)
|
|
383
|
+
deposit = self.safe_string(rawNetwork, 'deposit') == 'enabled'
|
|
384
|
+
withdraw = self.safe_string(rawNetwork, 'withdrawal') == 'enabled'
|
|
385
|
+
networks[networkCode] = {
|
|
386
|
+
'id': networkId,
|
|
387
|
+
'network': networkCode,
|
|
388
|
+
'margin': None,
|
|
389
|
+
'deposit': deposit,
|
|
390
|
+
'withdraw': withdraw,
|
|
391
|
+
'active': None,
|
|
392
|
+
'fee': self.safe_number(rawNetwork, 'withdrawalFee'),
|
|
393
|
+
'precision': currencyPrecision,
|
|
335
394
|
'limits': {
|
|
336
|
-
'
|
|
337
|
-
'min': self.safe_number(
|
|
395
|
+
'deposit': {
|
|
396
|
+
'min': self.safe_number(rawNetwork, 'minDeposit'),
|
|
338
397
|
'max': None,
|
|
339
398
|
},
|
|
340
399
|
'withdraw': {
|
|
341
|
-
'min': self.safe_number(
|
|
400
|
+
'min': self.safe_number(rawNetwork, 'minWithdrawal'),
|
|
342
401
|
'max': None,
|
|
343
402
|
},
|
|
344
403
|
},
|
|
345
|
-
'info':
|
|
404
|
+
'info': rawNetwork,
|
|
346
405
|
}
|
|
347
|
-
return
|
|
406
|
+
return self.safe_currency_structure({
|
|
407
|
+
'id': id,
|
|
408
|
+
'code': code,
|
|
409
|
+
'name': None,
|
|
410
|
+
'type': type,
|
|
411
|
+
'active': None,
|
|
412
|
+
'deposit': self.safe_bool(rawCurrency, 'walletDeposit'),
|
|
413
|
+
'withdraw': self.safe_bool(rawCurrency, 'walletWithdrawal'),
|
|
414
|
+
'fee': None,
|
|
415
|
+
'precision': currencyPrecision,
|
|
416
|
+
'limits': {
|
|
417
|
+
'amount': {
|
|
418
|
+
'min': None,
|
|
419
|
+
'max': None,
|
|
420
|
+
},
|
|
421
|
+
'withdraw': {
|
|
422
|
+
'min': None,
|
|
423
|
+
'max': None,
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
'networks': networks,
|
|
427
|
+
'info': rawCurrency,
|
|
428
|
+
})
|
|
348
429
|
|
|
349
430
|
async def fetch_markets(self, params={}) -> List[Market]:
|
|
350
431
|
"""
|
|
351
|
-
retrieves data on all markets for
|
|
432
|
+
retrieves data on all markets for ace
|
|
433
|
+
|
|
434
|
+
https://trade.cex.io/docs/#rest-public-api-calls-pairs-info
|
|
435
|
+
|
|
352
436
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
353
437
|
:returns dict[]: an array of objects representing market data
|
|
354
438
|
"""
|
|
355
|
-
|
|
356
|
-
currenciesData = self.safe_value(currenciesResponse, 'data', {})
|
|
357
|
-
currencies = self.safe_value(currenciesData, 'symbols', [])
|
|
358
|
-
currenciesById = self.index_by(currencies, 'code')
|
|
359
|
-
pairs = self.safe_value(currenciesData, 'pairs', [])
|
|
360
|
-
response = await self.publicGetCurrencyLimits(params)
|
|
439
|
+
response = await self.publicPostGetPairsInfo(params)
|
|
361
440
|
#
|
|
362
|
-
#
|
|
363
|
-
#
|
|
364
|
-
#
|
|
365
|
-
#
|
|
366
|
-
#
|
|
367
|
-
#
|
|
368
|
-
#
|
|
369
|
-
#
|
|
370
|
-
#
|
|
371
|
-
#
|
|
372
|
-
#
|
|
373
|
-
#
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
#
|
|
377
|
-
#
|
|
378
|
-
#
|
|
379
|
-
#
|
|
380
|
-
#
|
|
381
|
-
# "maxLotSize":null,
|
|
382
|
-
# "minPrice":"25",
|
|
383
|
-
# "maxPrice":"8192"
|
|
384
|
-
# }
|
|
385
|
-
# ]
|
|
386
|
-
# }
|
|
387
|
-
# }
|
|
441
|
+
# {
|
|
442
|
+
# "ok": "ok",
|
|
443
|
+
# "data": [
|
|
444
|
+
# {
|
|
445
|
+
# "base": "AI",
|
|
446
|
+
# "quote": "USD",
|
|
447
|
+
# "baseMin": "30",
|
|
448
|
+
# "baseMax": "2516000",
|
|
449
|
+
# "baseLotSize": "0.000001",
|
|
450
|
+
# "quoteMin": "10",
|
|
451
|
+
# "quoteMax": "1000000",
|
|
452
|
+
# "quoteLotSize": "0.01000000",
|
|
453
|
+
# "basePrecision": "6",
|
|
454
|
+
# "quotePrecision": "8",
|
|
455
|
+
# "pricePrecision": "4",
|
|
456
|
+
# "minPrice": "0.0377",
|
|
457
|
+
# "maxPrice": "19.5000"
|
|
458
|
+
# },
|
|
459
|
+
# ...
|
|
388
460
|
#
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
'
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
'inverse': None,
|
|
427
|
-
'contractSize': None,
|
|
428
|
-
'expiry': None,
|
|
429
|
-
'expiryDatetime': None,
|
|
430
|
-
'strike': None,
|
|
431
|
-
'optionType': None,
|
|
432
|
-
'precision': {
|
|
433
|
-
'amount': self.parse_number(self.parse_precision(amountPrecisionString)),
|
|
434
|
-
'price': self.parse_number(self.parse_precision(pricePrecisionString)),
|
|
461
|
+
data = self.safe_list(response, 'data', [])
|
|
462
|
+
return self.parse_markets(data)
|
|
463
|
+
|
|
464
|
+
def parse_market(self, market: dict) -> Market:
|
|
465
|
+
baseId = self.safe_string(market, 'base')
|
|
466
|
+
base = self.safe_currency_code(baseId)
|
|
467
|
+
quoteId = self.safe_string(market, 'quote')
|
|
468
|
+
quote = self.safe_currency_code(quoteId)
|
|
469
|
+
id = base + '-' + quote # not actual id, but for self exchange we can use self abbreviation, because e.g. tickers have hyphen in between
|
|
470
|
+
symbol = base + '/' + quote
|
|
471
|
+
return self.safe_market_structure({
|
|
472
|
+
'id': id,
|
|
473
|
+
'symbol': symbol,
|
|
474
|
+
'base': base,
|
|
475
|
+
'baseId': baseId,
|
|
476
|
+
'quote': quote,
|
|
477
|
+
'quoteId': quoteId,
|
|
478
|
+
'settle': None,
|
|
479
|
+
'settleId': None,
|
|
480
|
+
'type': 'spot',
|
|
481
|
+
'spot': True,
|
|
482
|
+
'margin': False,
|
|
483
|
+
'swap': False,
|
|
484
|
+
'future': False,
|
|
485
|
+
'option': False,
|
|
486
|
+
'contract': False,
|
|
487
|
+
'linear': None,
|
|
488
|
+
'inverse': None,
|
|
489
|
+
'contractSize': None,
|
|
490
|
+
'expiry': None,
|
|
491
|
+
'expiryDatetime': None,
|
|
492
|
+
'strike': None,
|
|
493
|
+
'optionType': None,
|
|
494
|
+
'limits': {
|
|
495
|
+
'amount': {
|
|
496
|
+
'min': self.safe_number(market, 'baseMin'),
|
|
497
|
+
'max': self.safe_number(market, 'baseMax'),
|
|
435
498
|
},
|
|
436
|
-
'
|
|
437
|
-
'
|
|
438
|
-
|
|
439
|
-
'max': None,
|
|
440
|
-
},
|
|
441
|
-
'amount': {
|
|
442
|
-
'min': self.safe_number(market, 'minLotSize'),
|
|
443
|
-
'max': self.safe_number(market, 'maxLotSize'),
|
|
444
|
-
},
|
|
445
|
-
'price': {
|
|
446
|
-
'min': self.safe_number(market, 'minPrice'),
|
|
447
|
-
'max': self.safe_number(market, 'maxPrice'),
|
|
448
|
-
},
|
|
449
|
-
'cost': {
|
|
450
|
-
'min': self.safe_number(market, 'minLotSizeS2'),
|
|
451
|
-
'max': None,
|
|
452
|
-
},
|
|
499
|
+
'price': {
|
|
500
|
+
'min': self.safe_number(market, 'minPrice'),
|
|
501
|
+
'max': self.safe_number(market, 'maxPrice'),
|
|
453
502
|
},
|
|
454
|
-
'
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
503
|
+
'cost': {
|
|
504
|
+
'min': self.safe_number(market, 'quoteMin'),
|
|
505
|
+
'max': self.safe_number(market, 'quoteMax'),
|
|
506
|
+
},
|
|
507
|
+
'leverage': {
|
|
508
|
+
'min': None,
|
|
509
|
+
'max': None,
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
'precision': {
|
|
513
|
+
'amount': self.safe_string(market, 'baseLotSize'),
|
|
514
|
+
'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision'))),
|
|
515
|
+
# 'cost': self.parse_number(self.parse_precision(self.safe_string(market, 'quoteLotSize'))), # buggy, doesn't reflect their documentation
|
|
516
|
+
'base': self.parse_number(self.parse_precision(self.safe_string(market, 'basePrecision'))),
|
|
517
|
+
'quote': self.parse_number(self.parse_precision(self.safe_string(market, 'quotePrecision'))),
|
|
518
|
+
},
|
|
519
|
+
'active': None,
|
|
520
|
+
'created': None,
|
|
521
|
+
'info': market,
|
|
522
|
+
})
|
|
474
523
|
|
|
475
|
-
async def
|
|
524
|
+
async def fetch_time(self, params={}) -> Int:
|
|
476
525
|
"""
|
|
477
|
-
|
|
478
|
-
query for balance and get the amount of funds available for trading or funds locked in orders
|
|
526
|
+
fetches the current integer timestamp in milliseconds from the exchange server
|
|
479
527
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
480
|
-
:returns
|
|
528
|
+
:returns int: the current integer timestamp in milliseconds from the exchange server
|
|
481
529
|
"""
|
|
482
|
-
await self.
|
|
483
|
-
|
|
484
|
-
|
|
530
|
+
response = await self.publicPostGetServerTime(params)
|
|
531
|
+
#
|
|
532
|
+
# {
|
|
533
|
+
# "ok": "ok",
|
|
534
|
+
# "data": {
|
|
535
|
+
# "timestamp": "1728472063472",
|
|
536
|
+
# "ISODate": "2024-10-09T11:07:43.472Z"
|
|
537
|
+
# }
|
|
538
|
+
# }
|
|
539
|
+
#
|
|
540
|
+
data = self.safe_dict(response, 'data')
|
|
541
|
+
timestamp = self.safe_integer(data, 'timestamp')
|
|
542
|
+
return timestamp
|
|
485
543
|
|
|
486
|
-
async def
|
|
544
|
+
async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
|
|
487
545
|
"""
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
546
|
+
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
547
|
+
|
|
548
|
+
https://trade.cex.io/docs/#rest-public-api-calls-ticker
|
|
549
|
+
|
|
550
|
+
:param str symbol:
|
|
492
551
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
493
|
-
:returns dict:
|
|
552
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
494
553
|
"""
|
|
495
554
|
await self.load_markets()
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
'pair': market['id'],
|
|
499
|
-
}
|
|
500
|
-
if limit is not None:
|
|
501
|
-
request['depth'] = limit
|
|
502
|
-
response = await self.publicGetOrderBookPair(self.extend(request, params))
|
|
503
|
-
timestamp = self.safe_timestamp(response, 'timestamp')
|
|
504
|
-
return self.parse_order_book(response, market['symbol'], timestamp)
|
|
505
|
-
|
|
506
|
-
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
|
507
|
-
#
|
|
508
|
-
# [
|
|
509
|
-
# 1591403940,
|
|
510
|
-
# 0.024972,
|
|
511
|
-
# 0.024972,
|
|
512
|
-
# 0.024969,
|
|
513
|
-
# 0.024969,
|
|
514
|
-
# 0.49999900
|
|
515
|
-
# ]
|
|
516
|
-
#
|
|
517
|
-
return [
|
|
518
|
-
self.safe_timestamp(ohlcv, 0),
|
|
519
|
-
self.safe_number(ohlcv, 1),
|
|
520
|
-
self.safe_number(ohlcv, 2),
|
|
521
|
-
self.safe_number(ohlcv, 3),
|
|
522
|
-
self.safe_number(ohlcv, 4),
|
|
523
|
-
self.safe_number(ohlcv, 5),
|
|
524
|
-
]
|
|
555
|
+
response = await self.fetch_tickers([symbol], params)
|
|
556
|
+
return self.safe_dict(response, symbol, {})
|
|
525
557
|
|
|
526
|
-
async def
|
|
558
|
+
async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
527
559
|
"""
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
:param
|
|
533
|
-
:param int [limit]: the maximum amount of candles to fetch
|
|
560
|
+
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
561
|
+
|
|
562
|
+
https://trade.cex.io/docs/#rest-public-api-calls-ticker
|
|
563
|
+
|
|
564
|
+
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
534
565
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
535
|
-
:returns
|
|
566
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
536
567
|
"""
|
|
537
568
|
await self.load_markets()
|
|
538
|
-
|
|
539
|
-
if
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
569
|
+
request = {}
|
|
570
|
+
if symbols is not None:
|
|
571
|
+
request['pairs'] = self.market_ids(symbols)
|
|
572
|
+
response = await self.publicPostGetTicker(self.extend(request, params))
|
|
573
|
+
#
|
|
574
|
+
# {
|
|
575
|
+
# "ok": "ok",
|
|
576
|
+
# "data": {
|
|
577
|
+
# "AI-USD": {
|
|
578
|
+
# "bestBid": "0.3917",
|
|
579
|
+
# "bestAsk": "0.3949",
|
|
580
|
+
# "bestBidChange": "0.0035",
|
|
581
|
+
# "bestBidChangePercentage": "0.90",
|
|
582
|
+
# "bestAskChange": "0.0038",
|
|
583
|
+
# "bestAskChangePercentage": "0.97",
|
|
584
|
+
# "low": "0.3787",
|
|
585
|
+
# "high": "0.3925",
|
|
586
|
+
# "volume30d": "2945.722277",
|
|
587
|
+
# "lastTradeDateISO": "2024-10-11T06:18:42.077Z",
|
|
588
|
+
# "volume": "120.736000",
|
|
589
|
+
# "quoteVolume": "46.65654070",
|
|
590
|
+
# "lastTradeVolume": "67.914000",
|
|
591
|
+
# "volumeUSD": "46.65",
|
|
592
|
+
# "last": "0.3949",
|
|
593
|
+
# "lastTradePrice": "0.3925",
|
|
594
|
+
# "priceChange": "0.0038",
|
|
595
|
+
# "priceChangePercentage": "0.97"
|
|
596
|
+
# },
|
|
597
|
+
# ...
|
|
598
|
+
#
|
|
599
|
+
data = self.safe_dict(response, 'data', {})
|
|
600
|
+
return self.parse_tickers(data, symbols)
|
|
564
601
|
|
|
565
602
|
def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
high = self.safe_string(ticker, 'high')
|
|
569
|
-
low = self.safe_string(ticker, 'low')
|
|
570
|
-
bid = self.safe_string(ticker, 'bid')
|
|
571
|
-
ask = self.safe_string(ticker, 'ask')
|
|
572
|
-
last = self.safe_string(ticker, 'last')
|
|
573
|
-
symbol = self.safe_symbol(None, market)
|
|
603
|
+
marketId = self.safe_string(ticker, 'id')
|
|
604
|
+
symbol = self.safe_symbol(marketId, market)
|
|
574
605
|
return self.safe_ticker({
|
|
575
606
|
'symbol': symbol,
|
|
576
|
-
'timestamp':
|
|
577
|
-
'datetime':
|
|
578
|
-
'high': high,
|
|
579
|
-
'low': low,
|
|
580
|
-
'bid':
|
|
607
|
+
'timestamp': None,
|
|
608
|
+
'datetime': None,
|
|
609
|
+
'high': self.safe_number(ticker, 'high'),
|
|
610
|
+
'low': self.safe_number(ticker, 'low'),
|
|
611
|
+
'bid': self.safe_number(ticker, 'bestBid'),
|
|
581
612
|
'bidVolume': None,
|
|
582
|
-
'ask':
|
|
613
|
+
'ask': self.safe_number(ticker, 'bestAsk'),
|
|
583
614
|
'askVolume': None,
|
|
584
615
|
'vwap': None,
|
|
585
616
|
'open': None,
|
|
586
|
-
'close': last,
|
|
587
|
-
'last': last,
|
|
617
|
+
'close': self.safe_string(ticker, 'last'), # last indicative price per api docs(difference also seen here: https://github.com/ccxt/ccxt/actions/runs/14593899575/job/40935513901?pr=25767#step:11:456 )
|
|
588
618
|
'previousClose': None,
|
|
589
|
-
'change':
|
|
590
|
-
'percentage':
|
|
619
|
+
'change': self.safe_number(ticker, 'priceChange'),
|
|
620
|
+
'percentage': self.safe_number(ticker, 'priceChangePercentage'),
|
|
591
621
|
'average': None,
|
|
592
|
-
'baseVolume': volume,
|
|
593
|
-
'quoteVolume':
|
|
622
|
+
'baseVolume': self.safe_string(ticker, 'volume'),
|
|
623
|
+
'quoteVolume': self.safe_string(ticker, 'quoteVolume'),
|
|
594
624
|
'info': ticker,
|
|
595
625
|
}, market)
|
|
596
626
|
|
|
597
|
-
async def
|
|
598
|
-
"""
|
|
599
|
-
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
600
|
-
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
601
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
602
|
-
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
627
|
+
async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
603
628
|
"""
|
|
604
|
-
|
|
605
|
-
symbols = self.market_symbols(symbols)
|
|
606
|
-
currencies = list(self.currencies.keys())
|
|
607
|
-
request: dict = {
|
|
608
|
-
'currencies': '/'.join(currencies),
|
|
609
|
-
}
|
|
610
|
-
response = await self.publicGetTickersCurrencies(self.extend(request, params))
|
|
611
|
-
tickers = self.safe_value(response, 'data', [])
|
|
612
|
-
result: dict = {}
|
|
613
|
-
for t in range(0, len(tickers)):
|
|
614
|
-
ticker = tickers[t]
|
|
615
|
-
marketId = self.safe_string(ticker, 'pair')
|
|
616
|
-
market = self.safe_market(marketId, None, ':')
|
|
617
|
-
symbol = market['symbol']
|
|
618
|
-
result[symbol] = self.parse_ticker(ticker, market)
|
|
619
|
-
return self.filter_by_array_tickers(result, 'symbol', symbols)
|
|
629
|
+
get the list of most recent trades for a particular symbol
|
|
620
630
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
:
|
|
624
|
-
|
|
625
|
-
:param
|
|
631
|
+
https://trade.cex.io/docs/#rest-public-api-calls-trade-history
|
|
632
|
+
|
|
633
|
+
:param str symbol: unified symbol of the market to fetch trades for
|
|
634
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
635
|
+
:param int [limit]: the maximum amount of trades to fetch
|
|
626
636
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
627
|
-
:
|
|
637
|
+
:param int [params.until]: timestamp in ms of the latest entry
|
|
638
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
628
639
|
"""
|
|
629
640
|
await self.load_markets()
|
|
630
641
|
market = self.market(symbol)
|
|
631
642
|
request: dict = {
|
|
632
643
|
'pair': market['id'],
|
|
633
644
|
}
|
|
634
|
-
|
|
635
|
-
|
|
645
|
+
if since is not None:
|
|
646
|
+
request['fromDateISO'] = self.iso8601(since)
|
|
647
|
+
until = None
|
|
648
|
+
until, params = self.handle_param_integer_2(params, 'until', 'till')
|
|
649
|
+
if until is not None:
|
|
650
|
+
request['toDateISO'] = self.iso8601(until)
|
|
651
|
+
if limit is not None:
|
|
652
|
+
request['pageSize'] = min(limit, 10000) # has a bug, still returns more trades
|
|
653
|
+
response = await self.publicPostGetTradeHistory(self.extend(request, params))
|
|
654
|
+
#
|
|
655
|
+
# {
|
|
656
|
+
# "ok": "ok",
|
|
657
|
+
# "data": {
|
|
658
|
+
# "pageSize": "10",
|
|
659
|
+
# "trades": [
|
|
660
|
+
# {
|
|
661
|
+
# "tradeId": "1728630559823-0",
|
|
662
|
+
# "dateISO": "2024-10-11T07:09:19.823Z",
|
|
663
|
+
# "side": "SELL",
|
|
664
|
+
# "price": "60879.5",
|
|
665
|
+
# "amount": "0.00165962"
|
|
666
|
+
# },
|
|
667
|
+
# ... followed by older trades
|
|
668
|
+
#
|
|
669
|
+
data = self.safe_dict(response, 'data', {})
|
|
670
|
+
trades = self.safe_list(data, 'trades', [])
|
|
671
|
+
return self.parse_trades(trades, market, since, limit)
|
|
636
672
|
|
|
637
673
|
def parse_trade(self, trade: dict, market: Market = None) -> Trade:
|
|
638
674
|
#
|
|
639
|
-
# fetchTrades
|
|
675
|
+
# public fetchTrades
|
|
640
676
|
#
|
|
641
|
-
#
|
|
642
|
-
#
|
|
643
|
-
#
|
|
644
|
-
#
|
|
645
|
-
#
|
|
646
|
-
#
|
|
647
|
-
#
|
|
677
|
+
# {
|
|
678
|
+
# "tradeId": "1728630559823-0",
|
|
679
|
+
# "dateISO": "2024-10-11T07:09:19.823Z",
|
|
680
|
+
# "side": "SELL",
|
|
681
|
+
# "price": "60879.5",
|
|
682
|
+
# "amount": "0.00165962"
|
|
683
|
+
# },
|
|
648
684
|
#
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
type = None
|
|
652
|
-
side = self.safe_string(trade, 'type')
|
|
653
|
-
priceString = self.safe_string(trade, 'price')
|
|
654
|
-
amountString = self.safe_string(trade, 'amount')
|
|
685
|
+
dateStr = self.safe_string(trade, 'dateISO')
|
|
686
|
+
timestamp = self.parse8601(dateStr)
|
|
655
687
|
market = self.safe_market(None, market)
|
|
656
688
|
return self.safe_trade({
|
|
657
689
|
'info': trade,
|
|
658
|
-
'id': id,
|
|
659
690
|
'timestamp': timestamp,
|
|
660
691
|
'datetime': self.iso8601(timestamp),
|
|
661
692
|
'symbol': market['symbol'],
|
|
662
|
-
'
|
|
663
|
-
'side': side,
|
|
693
|
+
'id': self.safe_string(trade, 'tradeId'),
|
|
664
694
|
'order': None,
|
|
695
|
+
'type': None,
|
|
665
696
|
'takerOrMaker': None,
|
|
666
|
-
'
|
|
667
|
-
'
|
|
697
|
+
'side': self.safe_string_lower(trade, 'side'),
|
|
698
|
+
'price': self.safe_string(trade, 'price'),
|
|
699
|
+
'amount': self.safe_string(trade, 'amount'),
|
|
668
700
|
'cost': None,
|
|
669
701
|
'fee': None,
|
|
670
702
|
}, market)
|
|
671
703
|
|
|
672
|
-
async def
|
|
704
|
+
async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
|
673
705
|
"""
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
:param
|
|
706
|
+
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
707
|
+
|
|
708
|
+
https://trade.cex.io/docs/#rest-public-api-calls-order-book
|
|
709
|
+
|
|
710
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
|
711
|
+
:param int [limit]: the maximum amount of order book entries to return
|
|
679
712
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
680
|
-
:returns
|
|
713
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
714
|
+
"""
|
|
715
|
+
await self.load_markets()
|
|
716
|
+
market = self.market(symbol)
|
|
717
|
+
request: dict = {
|
|
718
|
+
'pair': market['id'],
|
|
719
|
+
}
|
|
720
|
+
response = await self.publicPostGetOrderBook(self.extend(request, params))
|
|
721
|
+
#
|
|
722
|
+
# {
|
|
723
|
+
# "ok": "ok",
|
|
724
|
+
# "data": {
|
|
725
|
+
# "timestamp": "1728636922648",
|
|
726
|
+
# "currency1": "BTC",
|
|
727
|
+
# "currency2": "USDT",
|
|
728
|
+
# "bids": [
|
|
729
|
+
# [
|
|
730
|
+
# "60694.1",
|
|
731
|
+
# "13.12849761"
|
|
732
|
+
# ],
|
|
733
|
+
# [
|
|
734
|
+
# "60694.0",
|
|
735
|
+
# "0.71829244"
|
|
736
|
+
# ],
|
|
737
|
+
# ...
|
|
738
|
+
#
|
|
739
|
+
orderBook = self.safe_dict(response, 'data', {})
|
|
740
|
+
timestamp = self.safe_integer(orderBook, 'timestamp')
|
|
741
|
+
return self.parse_order_book(orderBook, market['symbol'], timestamp)
|
|
742
|
+
|
|
743
|
+
async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
744
|
+
"""
|
|
745
|
+
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
746
|
+
|
|
747
|
+
https://trade.cex.io/docs/#rest-public-api-calls-candles
|
|
748
|
+
|
|
749
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
750
|
+
:param str timeframe: the length of time each candle represents
|
|
751
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
752
|
+
:param int [limit]: the maximum amount of candles to fetch
|
|
753
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
754
|
+
:param int [params.until]: timestamp in ms of the latest entry
|
|
755
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
681
756
|
"""
|
|
757
|
+
dataType = None
|
|
758
|
+
dataType, params = self.handle_option_and_params(params, 'fetchOHLCV', 'dataType')
|
|
759
|
+
if dataType is None:
|
|
760
|
+
raise ArgumentsRequired(self.id + ' fetchOHLCV requires a parameter "dataType" to be either "bestBid" or "bestAsk"')
|
|
682
761
|
await self.load_markets()
|
|
683
762
|
market = self.market(symbol)
|
|
684
763
|
request: dict = {
|
|
685
764
|
'pair': market['id'],
|
|
765
|
+
'resolution': self.timeframes[timeframe],
|
|
766
|
+
'dataType': dataType,
|
|
686
767
|
}
|
|
687
|
-
|
|
688
|
-
|
|
768
|
+
if since is not None:
|
|
769
|
+
request['fromISO'] = self.iso8601(since)
|
|
770
|
+
until = None
|
|
771
|
+
until, params = self.handle_param_integer_2(params, 'until', 'till')
|
|
772
|
+
if until is not None:
|
|
773
|
+
request['toISO'] = self.iso8601(until)
|
|
774
|
+
elif since is None:
|
|
775
|
+
# exchange still requires that we provide one of them
|
|
776
|
+
request['toISO'] = self.iso8601(self.milliseconds())
|
|
777
|
+
if since is not None and until is not None and limit is not None:
|
|
778
|
+
raise ArgumentsRequired(self.id + ' fetchOHLCV does not support fetching candles with both a limit and since/until')
|
|
779
|
+
elif (since is not None or until is not None) and limit is None:
|
|
780
|
+
raise ArgumentsRequired(self.id + ' fetchOHLCV requires a limit parameter when fetching candles with since or until')
|
|
781
|
+
if limit is not None:
|
|
782
|
+
request['limit'] = limit
|
|
783
|
+
response = await self.publicPostGetCandles(self.extend(request, params))
|
|
784
|
+
#
|
|
785
|
+
# {
|
|
786
|
+
# "ok": "ok",
|
|
787
|
+
# "data": [
|
|
788
|
+
# {
|
|
789
|
+
# "timestamp": "1728643320000",
|
|
790
|
+
# "open": "61061",
|
|
791
|
+
# "high": "61095.1",
|
|
792
|
+
# "low": "61048.5",
|
|
793
|
+
# "close": "61087.8",
|
|
794
|
+
# "volume": "0",
|
|
795
|
+
# "resolution": "1m",
|
|
796
|
+
# "isClosed": True,
|
|
797
|
+
# "timestampISO": "2024-10-11T10:42:00.000Z"
|
|
798
|
+
# },
|
|
799
|
+
# ...
|
|
800
|
+
#
|
|
801
|
+
data = self.safe_list(response, 'data', [])
|
|
802
|
+
return self.parse_ohlcvs(data, market, timeframe, since, limit)
|
|
803
|
+
|
|
804
|
+
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
|
805
|
+
return [
|
|
806
|
+
self.safe_integer(ohlcv, 'timestamp'),
|
|
807
|
+
self.safe_number(ohlcv, 'open'),
|
|
808
|
+
self.safe_number(ohlcv, 'high'),
|
|
809
|
+
self.safe_number(ohlcv, 'low'),
|
|
810
|
+
self.safe_number(ohlcv, 'close'),
|
|
811
|
+
self.safe_number(ohlcv, 'volume'),
|
|
812
|
+
]
|
|
689
813
|
|
|
690
814
|
async def fetch_trading_fees(self, params={}) -> TradingFees:
|
|
691
815
|
"""
|
|
692
|
-
:see: https://docs.cex.io/#get-my-fee
|
|
693
816
|
fetch the trading fees for multiple markets
|
|
817
|
+
|
|
818
|
+
https://trade.cex.io/docs/#rest-public-api-calls-candles
|
|
819
|
+
|
|
694
820
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
695
821
|
:returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
|
|
696
822
|
"""
|
|
697
823
|
await self.load_markets()
|
|
698
|
-
response = await self.
|
|
824
|
+
response = await self.privatePostGetMyCurrentFee(params)
|
|
699
825
|
#
|
|
700
|
-
#
|
|
701
|
-
#
|
|
702
|
-
#
|
|
703
|
-
#
|
|
704
|
-
#
|
|
705
|
-
#
|
|
706
|
-
#
|
|
707
|
-
#
|
|
708
|
-
# }
|
|
826
|
+
# {
|
|
827
|
+
# "ok": "ok",
|
|
828
|
+
# "data": {
|
|
829
|
+
# "tradingFee": {
|
|
830
|
+
# "AI-USD": {
|
|
831
|
+
# "percent": "0.25"
|
|
832
|
+
# },
|
|
833
|
+
# ...
|
|
709
834
|
#
|
|
710
|
-
data = self.
|
|
835
|
+
data = self.safe_dict(response, 'data', {})
|
|
836
|
+
fees = self.safe_dict(data, 'tradingFee', {})
|
|
837
|
+
return self.parse_trading_fees(fees, True)
|
|
838
|
+
|
|
839
|
+
def parse_trading_fees(self, response, useKeyAsId=False) -> TradingFees:
|
|
711
840
|
result: dict = {}
|
|
841
|
+
keys = list(response.keys())
|
|
842
|
+
for i in range(0, len(keys)):
|
|
843
|
+
key = keys[i]
|
|
844
|
+
market = None
|
|
845
|
+
if useKeyAsId:
|
|
846
|
+
market = self.safe_market(key)
|
|
847
|
+
parsed = self.parse_trading_fee(response[key], market)
|
|
848
|
+
result[parsed['symbol']] = parsed
|
|
712
849
|
for i in range(0, len(self.symbols)):
|
|
713
850
|
symbol = self.symbols[i]
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
takerString = self.safe_string(fee, 'buy')
|
|
718
|
-
maker = self.parse_number(Precise.string_div(makerString, '100'))
|
|
719
|
-
taker = self.parse_number(Precise.string_div(takerString, '100'))
|
|
720
|
-
result[symbol] = {
|
|
721
|
-
'info': fee,
|
|
722
|
-
'symbol': symbol,
|
|
723
|
-
'maker': maker,
|
|
724
|
-
'taker': taker,
|
|
725
|
-
'percentage': True,
|
|
726
|
-
}
|
|
851
|
+
if not (symbol in result):
|
|
852
|
+
market = self.market(symbol)
|
|
853
|
+
result[symbol] = self.parse_trading_fee(response, market)
|
|
727
854
|
return result
|
|
728
855
|
|
|
856
|
+
def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
|
|
857
|
+
return {
|
|
858
|
+
'info': fee,
|
|
859
|
+
'symbol': self.safe_string(market, 'symbol'),
|
|
860
|
+
'maker': self.safe_number(fee, 'percent'),
|
|
861
|
+
'taker': self.safe_number(fee, 'percent'),
|
|
862
|
+
'percentage': None,
|
|
863
|
+
'tierBased': None,
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
async def fetch_accounts(self, params={}) -> List[Account]:
|
|
867
|
+
await self.load_markets()
|
|
868
|
+
response = await self.privatePostGetMyAccountStatusV3(params)
|
|
869
|
+
#
|
|
870
|
+
# {
|
|
871
|
+
# "ok": "ok",
|
|
872
|
+
# "data": {
|
|
873
|
+
# "convertedCurrency": "USD",
|
|
874
|
+
# "balancesPerAccounts": {
|
|
875
|
+
# "": {
|
|
876
|
+
# "AI": {
|
|
877
|
+
# "balance": "0.000000",
|
|
878
|
+
# "balanceOnHold": "0.000000"
|
|
879
|
+
# },
|
|
880
|
+
# "USDT": {
|
|
881
|
+
# "balance": "0.00000000",
|
|
882
|
+
# "balanceOnHold": "0.00000000"
|
|
883
|
+
# }
|
|
884
|
+
# }
|
|
885
|
+
# }
|
|
886
|
+
# }
|
|
887
|
+
# }
|
|
888
|
+
#
|
|
889
|
+
data = self.safe_dict(response, 'data', {})
|
|
890
|
+
balances = self.safe_dict(data, 'balancesPerAccounts', {})
|
|
891
|
+
arrays = self.to_array(balances)
|
|
892
|
+
return self.parse_accounts(arrays, params)
|
|
893
|
+
|
|
894
|
+
def parse_account(self, account: dict) -> Account:
|
|
895
|
+
return {
|
|
896
|
+
'id': None,
|
|
897
|
+
'type': None,
|
|
898
|
+
'code': None,
|
|
899
|
+
'info': account,
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
async def fetch_balance(self, params={}) -> Balances:
|
|
903
|
+
"""
|
|
904
|
+
query for balance and get the amount of funds available for trading or funds locked in orders
|
|
905
|
+
|
|
906
|
+
https://trade.cex.io/docs/#rest-private-api-calls-account-status-v3
|
|
907
|
+
|
|
908
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
909
|
+
:param dict [params.method]: 'privatePostGetMyWalletBalance' or 'privatePostGetMyAccountStatusV3'
|
|
910
|
+
:param dict [params.account]: in case 'privatePostGetMyAccountStatusV3' is chosen, self can specify the account name(default is empty string)
|
|
911
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
|
912
|
+
"""
|
|
913
|
+
accountName = None
|
|
914
|
+
accountName, params = self.handle_param_string(params, 'account', '') # default is empty string
|
|
915
|
+
method = None
|
|
916
|
+
method, params = self.handle_param_string(params, 'method', 'privatePostGetMyWalletBalance')
|
|
917
|
+
accountBalance = None
|
|
918
|
+
if method == 'privatePostGetMyAccountStatusV3':
|
|
919
|
+
response = await self.privatePostGetMyAccountStatusV3(params)
|
|
920
|
+
#
|
|
921
|
+
# {
|
|
922
|
+
# "ok": "ok",
|
|
923
|
+
# "data": {
|
|
924
|
+
# "convertedCurrency": "USD",
|
|
925
|
+
# "balancesPerAccounts": {
|
|
926
|
+
# "": {
|
|
927
|
+
# "AI": {
|
|
928
|
+
# "balance": "0.000000",
|
|
929
|
+
# "balanceOnHold": "0.000000"
|
|
930
|
+
# },
|
|
931
|
+
# ....
|
|
932
|
+
#
|
|
933
|
+
data = self.safe_dict(response, 'data', {})
|
|
934
|
+
balances = self.safe_dict(data, 'balancesPerAccounts', {})
|
|
935
|
+
accountBalance = self.safe_dict(balances, accountName, {})
|
|
936
|
+
else:
|
|
937
|
+
response = await self.privatePostGetMyWalletBalance(params)
|
|
938
|
+
#
|
|
939
|
+
# {
|
|
940
|
+
# "ok": "ok",
|
|
941
|
+
# "data": {
|
|
942
|
+
# "AI": {
|
|
943
|
+
# "balance": "25.606429"
|
|
944
|
+
# },
|
|
945
|
+
# "USDT": {
|
|
946
|
+
# "balance": "7.935449"
|
|
947
|
+
# },
|
|
948
|
+
# ...
|
|
949
|
+
#
|
|
950
|
+
accountBalance = self.safe_dict(response, 'data', {})
|
|
951
|
+
return self.parse_balance(accountBalance)
|
|
952
|
+
|
|
953
|
+
def parse_balance(self, response) -> Balances:
|
|
954
|
+
result: dict = {
|
|
955
|
+
'info': response,
|
|
956
|
+
}
|
|
957
|
+
keys = list(response.keys())
|
|
958
|
+
for i in range(0, len(keys)):
|
|
959
|
+
key = keys[i]
|
|
960
|
+
balance = self.safe_dict(response, key, {})
|
|
961
|
+
code = self.safe_currency_code(key)
|
|
962
|
+
account: dict = {
|
|
963
|
+
'used': self.safe_string(balance, 'balanceOnHold'),
|
|
964
|
+
'total': self.safe_string(balance, 'balance'),
|
|
965
|
+
}
|
|
966
|
+
result[code] = account
|
|
967
|
+
return self.safe_balance(result)
|
|
968
|
+
|
|
969
|
+
async def fetch_orders_by_status(self, status: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
970
|
+
"""
|
|
971
|
+
fetches information on multiple orders made by the user
|
|
972
|
+
|
|
973
|
+
https://trade.cex.io/docs/#rest-private-api-calls-orders
|
|
974
|
+
|
|
975
|
+
:param str status: order status to fetch for
|
|
976
|
+
:param str symbol: unified market symbol of the market orders were made in
|
|
977
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
|
978
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
|
979
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
980
|
+
:param int [params.until]: timestamp in ms of the latest entry
|
|
981
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
982
|
+
"""
|
|
983
|
+
await self.load_markets()
|
|
984
|
+
request: dict = {}
|
|
985
|
+
isClosedOrders = (status == 'closed')
|
|
986
|
+
if isClosedOrders:
|
|
987
|
+
request['archived'] = True
|
|
988
|
+
market = None
|
|
989
|
+
if symbol is not None:
|
|
990
|
+
market = self.market(symbol)
|
|
991
|
+
request['pair'] = market['id']
|
|
992
|
+
if limit is not None:
|
|
993
|
+
request['pageSize'] = limit
|
|
994
|
+
if since is not None:
|
|
995
|
+
request['serverCreateTimestampFrom'] = since
|
|
996
|
+
elif isClosedOrders:
|
|
997
|
+
# exchange requires a `since` parameter for closed orders, so set default to allowed 365
|
|
998
|
+
request['serverCreateTimestampFrom'] = self.milliseconds() - 364 * 24 * 60 * 60 * 1000
|
|
999
|
+
until = None
|
|
1000
|
+
until, params = self.handle_param_integer_2(params, 'until', 'till')
|
|
1001
|
+
if until is not None:
|
|
1002
|
+
request['serverCreateTimestampTo'] = until
|
|
1003
|
+
response = await self.privatePostGetMyOrders(self.extend(request, params))
|
|
1004
|
+
#
|
|
1005
|
+
# if called without `pair`
|
|
1006
|
+
#
|
|
1007
|
+
# {
|
|
1008
|
+
# "ok": "ok",
|
|
1009
|
+
# "data": [
|
|
1010
|
+
# {
|
|
1011
|
+
# "orderId": "1313003",
|
|
1012
|
+
# "clientOrderId": "037F0AFEB93A",
|
|
1013
|
+
# "clientId": "up421412345",
|
|
1014
|
+
# "accountId": null,
|
|
1015
|
+
# "status": "FILLED",
|
|
1016
|
+
# "statusIsFinal": True,
|
|
1017
|
+
# "currency1": "AI",
|
|
1018
|
+
# "currency2": "USDT",
|
|
1019
|
+
# "side": "BUY",
|
|
1020
|
+
# "orderType": "Market",
|
|
1021
|
+
# "timeInForce": "IOC",
|
|
1022
|
+
# "comment": null,
|
|
1023
|
+
# "rejectCode": null,
|
|
1024
|
+
# "rejectReason": null,
|
|
1025
|
+
# "initialOnHoldAmountCcy1": null,
|
|
1026
|
+
# "initialOnHoldAmountCcy2": "10.23456700",
|
|
1027
|
+
# "executedAmountCcy1": "25.606429",
|
|
1028
|
+
# "executedAmountCcy2": "10.20904439",
|
|
1029
|
+
# "requestedAmountCcy1": null,
|
|
1030
|
+
# "requestedAmountCcy2": "10.20904439",
|
|
1031
|
+
# "originalAmountCcy2": "10.23456700",
|
|
1032
|
+
# "feeAmount": "0.02552261",
|
|
1033
|
+
# "feeCurrency": "USDT",
|
|
1034
|
+
# "price": null,
|
|
1035
|
+
# "averagePrice": "0.3986",
|
|
1036
|
+
# "clientCreateTimestamp": "1728474625320",
|
|
1037
|
+
# "serverCreateTimestamp": "1728474624956",
|
|
1038
|
+
# "lastUpdateTimestamp": "1728474628015",
|
|
1039
|
+
# "expireTime": null,
|
|
1040
|
+
# "effectiveTime": null
|
|
1041
|
+
# },
|
|
1042
|
+
# ...
|
|
1043
|
+
#
|
|
1044
|
+
data = self.safe_list(response, 'data', [])
|
|
1045
|
+
return self.parse_orders(data, market, since, limit)
|
|
1046
|
+
|
|
1047
|
+
async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1048
|
+
"""
|
|
1049
|
+
|
|
1050
|
+
https://trade.cex.io/docs/#rest-private-api-calls-orders
|
|
1051
|
+
|
|
1052
|
+
fetches information on multiple canceled orders made by the user
|
|
1053
|
+
:param str symbol: unified market symbol of the market orders were made in
|
|
1054
|
+
:param int [since]: timestamp in ms of the earliest order, default is None
|
|
1055
|
+
:param int [limit]: max number of orders to return, default is None
|
|
1056
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1057
|
+
:returns dict: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1058
|
+
"""
|
|
1059
|
+
return await self.fetch_orders_by_status('closed', symbol, since, limit, params)
|
|
1060
|
+
|
|
1061
|
+
async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1062
|
+
"""
|
|
1063
|
+
|
|
1064
|
+
https://trade.cex.io/docs/#rest-private-api-calls-orders
|
|
1065
|
+
|
|
1066
|
+
fetches information on multiple canceled orders made by the user
|
|
1067
|
+
:param str symbol: unified market symbol of the market orders were made in
|
|
1068
|
+
:param int [since]: timestamp in ms of the earliest order, default is None
|
|
1069
|
+
:param int [limit]: max number of orders to return, default is None
|
|
1070
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1071
|
+
:returns dict: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1072
|
+
"""
|
|
1073
|
+
return await self.fetch_orders_by_status('open', symbol, since, limit, params)
|
|
1074
|
+
|
|
1075
|
+
async def fetch_open_order(self, id: str, symbol: Str = None, params={}):
|
|
1076
|
+
"""
|
|
1077
|
+
fetches information on an open order made by the user
|
|
1078
|
+
|
|
1079
|
+
https://trade.cex.io/docs/#rest-private-api-calls-orders
|
|
1080
|
+
|
|
1081
|
+
:param str id: order id
|
|
1082
|
+
:param str [symbol]: unified symbol of the market the order was made in
|
|
1083
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1084
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1085
|
+
"""
|
|
1086
|
+
await self.load_markets()
|
|
1087
|
+
request: dict = {
|
|
1088
|
+
'orderId': int(id),
|
|
1089
|
+
}
|
|
1090
|
+
result = await self.fetch_open_orders(symbol, None, None, self.extend(request, params))
|
|
1091
|
+
return result[0]
|
|
1092
|
+
|
|
1093
|
+
async def fetch_closed_order(self, id: str, symbol: Str = None, params={}):
|
|
1094
|
+
"""
|
|
1095
|
+
fetches information on an closed order made by the user
|
|
1096
|
+
|
|
1097
|
+
https://trade.cex.io/docs/#rest-private-api-calls-orders
|
|
1098
|
+
|
|
1099
|
+
:param str id: order id
|
|
1100
|
+
:param str [symbol]: unified symbol of the market the order was made in
|
|
1101
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1102
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1103
|
+
"""
|
|
1104
|
+
await self.load_markets()
|
|
1105
|
+
request: dict = {
|
|
1106
|
+
'orderId': int(id),
|
|
1107
|
+
}
|
|
1108
|
+
result = await self.fetch_closed_orders(symbol, None, None, self.extend(request, params))
|
|
1109
|
+
return result[0]
|
|
1110
|
+
|
|
1111
|
+
def parse_order_status(self, status: Str):
|
|
1112
|
+
statuses: dict = {
|
|
1113
|
+
'PENDING_NEW': 'open',
|
|
1114
|
+
'NEW': 'open',
|
|
1115
|
+
'PARTIALLY_FILLED': 'open',
|
|
1116
|
+
'FILLED': 'closed',
|
|
1117
|
+
'EXPIRED': 'expired',
|
|
1118
|
+
'REJECTED': 'rejected',
|
|
1119
|
+
'PENDING_CANCEL': 'canceling',
|
|
1120
|
+
'CANCELLED': 'canceled',
|
|
1121
|
+
}
|
|
1122
|
+
return self.safe_string(statuses, status, status)
|
|
1123
|
+
|
|
1124
|
+
def parse_order(self, order: dict, market: Market = None) -> Order:
|
|
1125
|
+
#
|
|
1126
|
+
# "orderId": "1313003",
|
|
1127
|
+
# "clientOrderId": "037F0AFEB93A",
|
|
1128
|
+
# "clientId": "up421412345",
|
|
1129
|
+
# "accountId": null,
|
|
1130
|
+
# "status": "FILLED",
|
|
1131
|
+
# "statusIsFinal": True,
|
|
1132
|
+
# "currency1": "AI",
|
|
1133
|
+
# "currency2": "USDT",
|
|
1134
|
+
# "side": "BUY",
|
|
1135
|
+
# "orderType": "Market",
|
|
1136
|
+
# "timeInForce": "IOC",
|
|
1137
|
+
# "comment": null,
|
|
1138
|
+
# "rejectCode": null,
|
|
1139
|
+
# "rejectReason": null,
|
|
1140
|
+
# "initialOnHoldAmountCcy1": null,
|
|
1141
|
+
# "initialOnHoldAmountCcy2": "10.23456700",
|
|
1142
|
+
# "executedAmountCcy1": "25.606429",
|
|
1143
|
+
# "executedAmountCcy2": "10.20904439",
|
|
1144
|
+
# "requestedAmountCcy1": null,
|
|
1145
|
+
# "requestedAmountCcy2": "10.20904439",
|
|
1146
|
+
# "originalAmountCcy2": "10.23456700",
|
|
1147
|
+
# "feeAmount": "0.02552261",
|
|
1148
|
+
# "feeCurrency": "USDT",
|
|
1149
|
+
# "price": null,
|
|
1150
|
+
# "averagePrice": "0.3986",
|
|
1151
|
+
# "clientCreateTimestamp": "1728474625320",
|
|
1152
|
+
# "serverCreateTimestamp": "1728474624956",
|
|
1153
|
+
# "lastUpdateTimestamp": "1728474628015",
|
|
1154
|
+
# "expireTime": null,
|
|
1155
|
+
# "effectiveTime": null
|
|
1156
|
+
#
|
|
1157
|
+
currency1 = self.safe_string(order, 'currency1')
|
|
1158
|
+
currency2 = self.safe_string(order, 'currency2')
|
|
1159
|
+
marketId = None
|
|
1160
|
+
if currency1 is not None and currency2 is not None:
|
|
1161
|
+
marketId = currency1 + '-' + currency2
|
|
1162
|
+
market = self.safe_market(marketId, market)
|
|
1163
|
+
symbol = market['symbol']
|
|
1164
|
+
status = self.parse_order_status(self.safe_string(order, 'status'))
|
|
1165
|
+
fee = {}
|
|
1166
|
+
feeAmount = self.safe_number(order, 'feeAmount')
|
|
1167
|
+
if feeAmount is not None:
|
|
1168
|
+
currencyId = self.safe_string(order, 'feeCurrency')
|
|
1169
|
+
feeCode = self.safe_currency_code(currencyId)
|
|
1170
|
+
fee['currency'] = feeCode
|
|
1171
|
+
fee['cost'] = feeAmount
|
|
1172
|
+
timestamp = self.safe_integer(order, 'serverCreateTimestamp')
|
|
1173
|
+
requestedBase = self.safe_number(order, 'requestedAmountCcy1')
|
|
1174
|
+
executedBase = self.safe_number(order, 'executedAmountCcy1')
|
|
1175
|
+
# requestedQuote = self.safe_number(order, 'requestedAmountCcy2')
|
|
1176
|
+
executedQuote = self.safe_number(order, 'executedAmountCcy2')
|
|
1177
|
+
return self.safe_order({
|
|
1178
|
+
'id': self.safe_string(order, 'orderId'),
|
|
1179
|
+
'clientOrderId': self.safe_string(order, 'clientOrderId'),
|
|
1180
|
+
'timestamp': timestamp,
|
|
1181
|
+
'datetime': self.iso8601(timestamp),
|
|
1182
|
+
'lastUpdateTimestamp': self.safe_integer(order, 'lastUpdateTimestamp'),
|
|
1183
|
+
'lastTradeTimestamp': None,
|
|
1184
|
+
'symbol': symbol,
|
|
1185
|
+
'type': self.safe_string_lower(order, 'orderType'),
|
|
1186
|
+
'timeInForce': self.safe_string(order, 'timeInForce'),
|
|
1187
|
+
'postOnly': None,
|
|
1188
|
+
'side': self.safe_string_lower(order, 'side'),
|
|
1189
|
+
'price': self.safe_number(order, 'price'),
|
|
1190
|
+
'triggerPrice': self.safe_number(order, 'stopPrice'),
|
|
1191
|
+
'amount': requestedBase,
|
|
1192
|
+
'cost': executedQuote,
|
|
1193
|
+
'average': self.safe_number(order, 'averagePrice'),
|
|
1194
|
+
'filled': executedBase,
|
|
1195
|
+
'remaining': None,
|
|
1196
|
+
'status': status,
|
|
1197
|
+
'fee': fee,
|
|
1198
|
+
'trades': None,
|
|
1199
|
+
'info': order,
|
|
1200
|
+
}, market)
|
|
1201
|
+
|
|
729
1202
|
async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
730
1203
|
"""
|
|
731
|
-
:see: https://docs.cex.io/#place-order
|
|
732
1204
|
create a trade order
|
|
733
|
-
|
|
1205
|
+
|
|
1206
|
+
https://trade.cex.io/docs/#rest-private-api-calls-new-order
|
|
1207
|
+
|
|
734
1208
|
:param str symbol: unified symbol of the market to create an order in
|
|
735
1209
|
:param str type: 'market' or 'limit'
|
|
736
1210
|
:param str side: 'buy' or 'sell'
|
|
737
1211
|
:param float amount: how much of currency you want to trade in units of base currency
|
|
738
|
-
:param float [price]: the price at which the order is to be
|
|
1212
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
|
739
1213
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
740
|
-
:param
|
|
1214
|
+
:param str [params.accountId]: account-id to use(default is empty string)
|
|
1215
|
+
:param float [params.triggerPrice]: the price at which a trigger order is triggered at
|
|
741
1216
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
742
1217
|
"""
|
|
1218
|
+
accountId = None
|
|
1219
|
+
accountId, params = self.handle_option_and_params(params, 'createOrder', 'accountId')
|
|
1220
|
+
if accountId is None:
|
|
1221
|
+
raise ArgumentsRequired(self.id + ' createOrder() : API trading is now allowed from main account, set params["accountId"] or .options["createOrder"]["accountId"] to the name of your sub-account')
|
|
743
1222
|
await self.load_markets()
|
|
744
1223
|
market = self.market(symbol)
|
|
745
1224
|
request: dict = {
|
|
746
|
-
'
|
|
747
|
-
'
|
|
1225
|
+
'clientOrderId': self.uuid(),
|
|
1226
|
+
'currency1': market['baseId'],
|
|
1227
|
+
'currency2': market['quoteId'],
|
|
1228
|
+
'accountId': accountId,
|
|
1229
|
+
'orderType': self.capitalize(type.lower()),
|
|
1230
|
+
'side': side.upper(),
|
|
1231
|
+
'timestamp': self.milliseconds(),
|
|
1232
|
+
'amountCcy1': self.amount_to_precision(symbol, amount),
|
|
748
1233
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
quoteAmount = None
|
|
752
|
-
createMarketBuyOrderRequiresPrice = True
|
|
753
|
-
createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
|
|
754
|
-
cost = self.safe_string(params, 'cost')
|
|
755
|
-
params = self.omit(params, 'cost')
|
|
756
|
-
if cost is not None:
|
|
757
|
-
quoteAmount = self.cost_to_precision(symbol, cost)
|
|
758
|
-
elif createMarketBuyOrderRequiresPrice:
|
|
759
|
-
if price is None:
|
|
760
|
-
raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend in the amount argument')
|
|
761
|
-
else:
|
|
762
|
-
amountString = self.number_to_string(amount)
|
|
763
|
-
priceString = self.number_to_string(price)
|
|
764
|
-
costRequest = Precise.string_mul(amountString, priceString)
|
|
765
|
-
quoteAmount = self.cost_to_precision(symbol, costRequest)
|
|
766
|
-
else:
|
|
767
|
-
quoteAmount = self.cost_to_precision(symbol, amount)
|
|
768
|
-
request['amount'] = quoteAmount
|
|
769
|
-
else:
|
|
770
|
-
request['amount'] = self.amount_to_precision(symbol, amount)
|
|
1234
|
+
timeInForce = None
|
|
1235
|
+
timeInForce, params = self.handle_option_and_params(params, 'createOrder', 'timeInForce', 'GTC')
|
|
771
1236
|
if type == 'limit':
|
|
772
|
-
request['price'] = self.
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
1237
|
+
request['price'] = self.price_to_precision(symbol, price)
|
|
1238
|
+
request['timeInForce'] = timeInForce
|
|
1239
|
+
triggerPrice = None
|
|
1240
|
+
triggerPrice, params = self.handle_param_string(params, 'triggerPrice')
|
|
1241
|
+
if triggerPrice is not None:
|
|
1242
|
+
request['type'] = 'Stop Limit'
|
|
1243
|
+
request['stopPrice'] = triggerPrice
|
|
1244
|
+
response = await self.privatePostDoMyNewOrder(self.extend(request, params))
|
|
776
1245
|
#
|
|
777
|
-
#
|
|
778
|
-
# "id": "12978363524",
|
|
779
|
-
# "time": 1586610022259,
|
|
780
|
-
# "type": "buy",
|
|
781
|
-
# "price": "0.033934",
|
|
782
|
-
# "amount": "0.10722802",
|
|
783
|
-
# "pending": "0.10722802",
|
|
784
|
-
# "complete": False
|
|
785
|
-
# }
|
|
1246
|
+
# on success
|
|
786
1247
|
#
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1248
|
+
# {
|
|
1249
|
+
# "ok": "ok",
|
|
1250
|
+
# "data": {
|
|
1251
|
+
# "messageType": "executionReport",
|
|
1252
|
+
# "clientId": "up132245425",
|
|
1253
|
+
# "orderId": "1318485",
|
|
1254
|
+
# "clientOrderId": "b5b6cd40-154c-4c1c-bd51-4a442f3d50b9",
|
|
1255
|
+
# "accountId": "sub1",
|
|
1256
|
+
# "status": "FILLED",
|
|
1257
|
+
# "currency1": "LTC",
|
|
1258
|
+
# "currency2": "USDT",
|
|
1259
|
+
# "side": "BUY",
|
|
1260
|
+
# "executedAmountCcy1": "0.23000000",
|
|
1261
|
+
# "executedAmountCcy2": "15.09030000",
|
|
1262
|
+
# "requestedAmountCcy1": "0.23000000",
|
|
1263
|
+
# "requestedAmountCcy2": null,
|
|
1264
|
+
# "orderType": "Market",
|
|
1265
|
+
# "timeInForce": null,
|
|
1266
|
+
# "comment": null,
|
|
1267
|
+
# "executionType": "Trade",
|
|
1268
|
+
# "executionId": "1726747124624_101_41116",
|
|
1269
|
+
# "transactTime": "2024-10-15T15:08:12.794Z",
|
|
1270
|
+
# "expireTime": null,
|
|
1271
|
+
# "effectiveTime": null,
|
|
1272
|
+
# "averagePrice": "65.61",
|
|
1273
|
+
# "lastQuantity": "0.23000000",
|
|
1274
|
+
# "lastAmountCcy1": "0.23000000",
|
|
1275
|
+
# "lastAmountCcy2": "15.09030000",
|
|
1276
|
+
# "lastPrice": "65.61",
|
|
1277
|
+
# "feeAmount": "0.03772575",
|
|
1278
|
+
# "feeCurrency": "USDT",
|
|
1279
|
+
# "clientCreateTimestamp": "1729004892014",
|
|
1280
|
+
# "serverCreateTimestamp": "1729004891628",
|
|
1281
|
+
# "lastUpdateTimestamp": "1729004892786"
|
|
1282
|
+
# }
|
|
1283
|
+
# }
|
|
1284
|
+
#
|
|
1285
|
+
# on failure, there are extra fields
|
|
1286
|
+
#
|
|
1287
|
+
# "status": "REJECTED",
|
|
1288
|
+
# "requestedAmountCcy1": null,
|
|
1289
|
+
# "orderRejectReason": "{\\" code \\ ":405,\\" reason \\ ":\\" Either AmountCcy1(OrderQty)or AmountCcy2(CashOrderQty)should be specified for market order not both \\ "}",
|
|
1290
|
+
# "rejectCode": 405,
|
|
1291
|
+
# "rejectReason": "Either AmountCcy1(OrderQty) or AmountCcy2(CashOrderQty) should be specified for market order not both",
|
|
1292
|
+
#
|
|
1293
|
+
data = self.safe_dict(response, 'data')
|
|
1294
|
+
return self.parse_order(data, market)
|
|
815
1295
|
|
|
816
1296
|
async def cancel_order(self, id: str, symbol: Str = None, params={}):
|
|
817
1297
|
"""
|
|
818
|
-
:see: https://docs.cex.io/#cancel-order
|
|
819
1298
|
cancels an open order
|
|
1299
|
+
|
|
1300
|
+
https://trade.cex.io/docs/#rest-private-api-calls-cancel-order
|
|
1301
|
+
|
|
820
1302
|
:param str id: order id
|
|
821
|
-
:param str symbol:
|
|
1303
|
+
:param str symbol: unified symbol of the market the order was made in
|
|
822
1304
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
823
1305
|
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
824
1306
|
"""
|
|
825
1307
|
await self.load_markets()
|
|
826
1308
|
request: dict = {
|
|
827
|
-
'
|
|
1309
|
+
'orderId': int(id),
|
|
1310
|
+
'cancelRequestId': 'c_' + str((self.milliseconds())),
|
|
1311
|
+
'timestamp': self.milliseconds(),
|
|
828
1312
|
}
|
|
829
|
-
response = await self.
|
|
830
|
-
#
|
|
831
|
-
|
|
1313
|
+
response = await self.privatePostDoCancelMyOrder(self.extend(request, params))
|
|
1314
|
+
#
|
|
1315
|
+
# {"ok":"ok","data":{}}
|
|
1316
|
+
#
|
|
1317
|
+
data = self.safe_dict(response, 'data', {})
|
|
1318
|
+
return self.parse_order(data)
|
|
832
1319
|
|
|
833
1320
|
async def cancel_all_orders(self, symbol: Str = None, params={}):
|
|
834
1321
|
"""
|
|
835
|
-
:see: https://docs.cex.io/#cancel-all-orders-for-given-pair
|
|
836
1322
|
cancel all open orders in a market
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
1323
|
+
|
|
1324
|
+
https://trade.cex.io/docs/#rest-private-api-calls-cancel-all-orders
|
|
1325
|
+
|
|
1326
|
+
:param str symbol: alpaca cancelAllOrders cannot setting symbol, it will cancel all open orders
|
|
1327
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
840
1328
|
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
841
1329
|
"""
|
|
842
|
-
if symbol is None:
|
|
843
|
-
raise ArgumentsRequired(self.id + ' cancelAllOrders requires a symbol.')
|
|
844
1330
|
await self.load_markets()
|
|
845
|
-
|
|
846
|
-
request: dict = {
|
|
847
|
-
'pair': market['id'],
|
|
848
|
-
}
|
|
849
|
-
orders = await self.privatePostCancelOrdersPair(self.extend(request, params))
|
|
1331
|
+
response = await self.privatePostDoCancelAllOrders(params)
|
|
850
1332
|
#
|
|
851
|
-
#
|
|
852
|
-
#
|
|
853
|
-
#
|
|
854
|
-
#
|
|
855
|
-
#
|
|
856
|
-
#
|
|
1333
|
+
# {
|
|
1334
|
+
# "ok": "ok",
|
|
1335
|
+
# "data": {
|
|
1336
|
+
# "clientOrderIds": [
|
|
1337
|
+
# "3AF77B67109F"
|
|
1338
|
+
# ]
|
|
1339
|
+
# }
|
|
1340
|
+
# }
|
|
857
1341
|
#
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
# ISO8601 string
|
|
866
|
-
timestamp = self.parse8601(timestamp)
|
|
867
|
-
elif timestamp is not None:
|
|
868
|
-
# either integer or string integer
|
|
869
|
-
timestamp = int(timestamp)
|
|
870
|
-
symbol = None
|
|
871
|
-
baseId = self.safe_string(order, 'symbol1')
|
|
872
|
-
quoteId = self.safe_string(order, 'symbol2')
|
|
873
|
-
if market is None and baseId is not None and quoteId is not None:
|
|
874
|
-
base = self.safe_currency_code(baseId)
|
|
875
|
-
quote = self.safe_currency_code(quoteId)
|
|
876
|
-
if (base is not None) and (quote is not None):
|
|
877
|
-
symbol = base + '/' + quote
|
|
878
|
-
if symbol in self.markets:
|
|
879
|
-
market = self.market(symbol)
|
|
880
|
-
status = self.parse_order_status(self.safe_string(order, 'status'))
|
|
881
|
-
price = self.safe_string(order, 'price')
|
|
882
|
-
amount = self.omit_zero(self.safe_string(order, 'amount'))
|
|
883
|
-
# sell orders can have a negative amount
|
|
884
|
-
# https://github.com/ccxt/ccxt/issues/5338
|
|
885
|
-
if amount is not None:
|
|
886
|
-
amount = Precise.string_abs(amount)
|
|
887
|
-
elif market is not None:
|
|
888
|
-
amountKey = 'a:' + market['base'] + 'cds:'
|
|
889
|
-
amount = Precise.string_abs(self.safe_string(order, amountKey))
|
|
890
|
-
remaining = self.safe_string_2(order, 'pending', 'remains')
|
|
891
|
-
filled = Precise.string_sub(amount, remaining)
|
|
892
|
-
fee = None
|
|
893
|
-
cost = None
|
|
894
|
-
if market is not None:
|
|
895
|
-
symbol = market['symbol']
|
|
896
|
-
taCost = self.safe_string(order, 'ta:' + market['quote'])
|
|
897
|
-
ttaCost = self.safe_string(order, 'tta:' + market['quote'])
|
|
898
|
-
cost = Precise.string_add(taCost, ttaCost)
|
|
899
|
-
baseFee = 'fa:' + market['base']
|
|
900
|
-
baseTakerFee = 'tfa:' + market['base']
|
|
901
|
-
quoteFee = 'fa:' + market['quote']
|
|
902
|
-
quoteTakerFee = 'tfa:' + market['quote']
|
|
903
|
-
feeRate = self.safe_string(order, 'tradingFeeMaker')
|
|
904
|
-
if not feeRate:
|
|
905
|
-
feeRate = self.safe_string(order, 'tradingFeeTaker', feeRate)
|
|
906
|
-
if feeRate:
|
|
907
|
-
feeRate = Precise.string_div(feeRate, '100') # convert to mathematically-correct percentage coefficients: 1.0 = 100%
|
|
908
|
-
if (baseFee in order) or (baseTakerFee in order):
|
|
909
|
-
baseFeeCost = self.safe_number_2(order, baseFee, baseTakerFee)
|
|
910
|
-
fee = {
|
|
911
|
-
'currency': market['base'],
|
|
912
|
-
'rate': self.parse_number(feeRate),
|
|
913
|
-
'cost': baseFeeCost,
|
|
914
|
-
}
|
|
915
|
-
elif (quoteFee in order) or (quoteTakerFee in order):
|
|
916
|
-
quoteFeeCost = self.safe_number_2(order, quoteFee, quoteTakerFee)
|
|
917
|
-
fee = {
|
|
918
|
-
'currency': market['quote'],
|
|
919
|
-
'rate': self.parse_number(feeRate),
|
|
920
|
-
'cost': quoteFeeCost,
|
|
921
|
-
}
|
|
922
|
-
if not cost:
|
|
923
|
-
cost = Precise.string_mul(price, filled)
|
|
924
|
-
side = self.safe_string(order, 'type')
|
|
925
|
-
trades = None
|
|
926
|
-
orderId = self.safe_string(order, 'id')
|
|
927
|
-
if 'vtx' in order:
|
|
928
|
-
trades = []
|
|
929
|
-
for i in range(0, len(order['vtx'])):
|
|
930
|
-
item = order['vtx'][i]
|
|
931
|
-
tradeSide = self.safe_string(item, 'type')
|
|
932
|
-
if tradeSide == 'cancel':
|
|
933
|
-
# looks like self might represent the cancelled part of an order
|
|
934
|
-
# {"id": "4426729543",
|
|
935
|
-
# "type": "cancel",
|
|
936
|
-
# "time": "2017-09-22T00:24:30.476Z",
|
|
937
|
-
# "user": "up106404164",
|
|
938
|
-
# "c": "user:up106404164:a:BCH",
|
|
939
|
-
# "d": "order:4426728375:a:BCH",
|
|
940
|
-
# "a": "0.09935956",
|
|
941
|
-
# "amount": "0.09935956",
|
|
942
|
-
# "balance": "0.42580261",
|
|
943
|
-
# "symbol": "BCH",
|
|
944
|
-
# "order": "4426728375",
|
|
945
|
-
# "buy": null,
|
|
946
|
-
# "sell": null,
|
|
947
|
-
# "pair": null,
|
|
948
|
-
# "pos": null,
|
|
949
|
-
# "cs": "0.42580261",
|
|
950
|
-
# "ds": 0}
|
|
951
|
-
continue
|
|
952
|
-
tradePrice = self.safe_string(item, 'price')
|
|
953
|
-
if tradePrice is None:
|
|
954
|
-
# self represents the order
|
|
955
|
-
# {
|
|
956
|
-
# "a": "0.47000000",
|
|
957
|
-
# "c": "user:up106404164:a:EUR",
|
|
958
|
-
# "d": "order:6065499239:a:EUR",
|
|
959
|
-
# "cs": "1432.93",
|
|
960
|
-
# "ds": "476.72",
|
|
961
|
-
# "id": "6065499249",
|
|
962
|
-
# "buy": null,
|
|
963
|
-
# "pos": null,
|
|
964
|
-
# "pair": null,
|
|
965
|
-
# "sell": null,
|
|
966
|
-
# "time": "2018-04-22T13:07:22.152Z",
|
|
967
|
-
# "type": "buy",
|
|
968
|
-
# "user": "up106404164",
|
|
969
|
-
# "order": "6065499239",
|
|
970
|
-
# "amount": "-715.97000000",
|
|
971
|
-
# "symbol": "EUR",
|
|
972
|
-
# "balance": "1432.93000000"}
|
|
973
|
-
continue
|
|
974
|
-
# todo: deal with these
|
|
975
|
-
if tradeSide == 'costsNothing':
|
|
976
|
-
continue
|
|
977
|
-
# --
|
|
978
|
-
# if side != tradeSide:
|
|
979
|
-
# raise Error(json.dumps(order, null, 2))
|
|
980
|
-
# if orderId != item['order']:
|
|
981
|
-
# raise Error(json.dumps(order, null, 2))
|
|
982
|
-
# --
|
|
983
|
-
# partial buy trade
|
|
984
|
-
# {
|
|
985
|
-
# "a": "0.01589885",
|
|
986
|
-
# "c": "user:up106404164:a:BTC",
|
|
987
|
-
# "d": "order:6065499239:a:BTC",
|
|
988
|
-
# "cs": "0.36300000",
|
|
989
|
-
# "ds": 0,
|
|
990
|
-
# "id": "6067991213",
|
|
991
|
-
# "buy": "6065499239",
|
|
992
|
-
# "pos": null,
|
|
993
|
-
# "pair": null,
|
|
994
|
-
# "sell": "6067991206",
|
|
995
|
-
# "time": "2018-04-22T23:09:11.773Z",
|
|
996
|
-
# "type": "buy",
|
|
997
|
-
# "user": "up106404164",
|
|
998
|
-
# "order": "6065499239",
|
|
999
|
-
# "price": 7146.5,
|
|
1000
|
-
# "amount": "0.01589885",
|
|
1001
|
-
# "symbol": "BTC",
|
|
1002
|
-
# "balance": "0.36300000",
|
|
1003
|
-
# "symbol2": "EUR",
|
|
1004
|
-
# "fee_amount": "0.19"}
|
|
1005
|
-
# --
|
|
1006
|
-
# trade with zero amount, but non-zero fee
|
|
1007
|
-
# {
|
|
1008
|
-
# "a": "0.00000000",
|
|
1009
|
-
# "c": "user:up106404164:a:EUR",
|
|
1010
|
-
# "d": "order:5840654423:a:EUR",
|
|
1011
|
-
# "cs": 559744,
|
|
1012
|
-
# "ds": 0,
|
|
1013
|
-
# "id": "5840654429",
|
|
1014
|
-
# "buy": "5807238573",
|
|
1015
|
-
# "pos": null,
|
|
1016
|
-
# "pair": null,
|
|
1017
|
-
# "sell": "5840654423",
|
|
1018
|
-
# "time": "2018-03-15T03:20:14.010Z",
|
|
1019
|
-
# "type": "sell",
|
|
1020
|
-
# "user": "up106404164",
|
|
1021
|
-
# "order": "5840654423",
|
|
1022
|
-
# "price": 730,
|
|
1023
|
-
# "amount": "0.00000000",
|
|
1024
|
-
# "symbol": "EUR",
|
|
1025
|
-
# "balance": "5597.44000000",
|
|
1026
|
-
# "symbol2": "BCH",
|
|
1027
|
-
# "fee_amount": "0.01"}
|
|
1028
|
-
# --
|
|
1029
|
-
# trade which should have an amount of exactly 0.002BTC
|
|
1030
|
-
# {
|
|
1031
|
-
# "a": "16.70000000",
|
|
1032
|
-
# "c": "user:up106404164:a:GBP",
|
|
1033
|
-
# "d": "order:9927386681:a:GBP",
|
|
1034
|
-
# "cs": "86.90",
|
|
1035
|
-
# "ds": 0,
|
|
1036
|
-
# "id": "9927401610",
|
|
1037
|
-
# "buy": "9927401601",
|
|
1038
|
-
# "pos": null,
|
|
1039
|
-
# "pair": null,
|
|
1040
|
-
# "sell": "9927386681",
|
|
1041
|
-
# "time": "2019-08-21T15:25:37.777Z",
|
|
1042
|
-
# "type": "sell",
|
|
1043
|
-
# "user": "up106404164",
|
|
1044
|
-
# "order": "9927386681",
|
|
1045
|
-
# "price": 8365,
|
|
1046
|
-
# "amount": "16.70000000",
|
|
1047
|
-
# "office": "UK",
|
|
1048
|
-
# "symbol": "GBP",
|
|
1049
|
-
# "balance": "86.90000000",
|
|
1050
|
-
# "symbol2": "BTC",
|
|
1051
|
-
# "fee_amount": "0.03"
|
|
1052
|
-
# }
|
|
1053
|
-
tradeTimestamp = self.parse8601(self.safe_string(item, 'time'))
|
|
1054
|
-
tradeAmount = self.safe_string(item, 'amount')
|
|
1055
|
-
feeCost = self.safe_string(item, 'fee_amount')
|
|
1056
|
-
absTradeAmount = Precise.string_abs(tradeAmount)
|
|
1057
|
-
tradeCost = None
|
|
1058
|
-
if tradeSide == 'sell':
|
|
1059
|
-
tradeCost = absTradeAmount
|
|
1060
|
-
absTradeAmount = Precise.string_div(Precise.string_add(feeCost, tradeCost), tradePrice)
|
|
1061
|
-
else:
|
|
1062
|
-
tradeCost = Precise.string_mul(absTradeAmount, tradePrice)
|
|
1063
|
-
trades.append({
|
|
1064
|
-
'id': self.safe_string(item, 'id'),
|
|
1065
|
-
'timestamp': tradeTimestamp,
|
|
1066
|
-
'datetime': self.iso8601(tradeTimestamp),
|
|
1067
|
-
'order': orderId,
|
|
1068
|
-
'symbol': symbol,
|
|
1069
|
-
'price': self.parse_number(tradePrice),
|
|
1070
|
-
'amount': self.parse_number(absTradeAmount),
|
|
1071
|
-
'cost': self.parse_number(tradeCost),
|
|
1072
|
-
'side': tradeSide,
|
|
1073
|
-
'fee': {
|
|
1074
|
-
'cost': self.parse_number(feeCost),
|
|
1075
|
-
'currency': market['quote'],
|
|
1076
|
-
},
|
|
1077
|
-
'info': item,
|
|
1078
|
-
'type': None,
|
|
1079
|
-
'takerOrMaker': None,
|
|
1080
|
-
})
|
|
1081
|
-
return self.safe_order({
|
|
1082
|
-
'info': order,
|
|
1083
|
-
'id': orderId,
|
|
1084
|
-
'clientOrderId': None,
|
|
1085
|
-
'datetime': self.iso8601(timestamp),
|
|
1086
|
-
'timestamp': timestamp,
|
|
1087
|
-
'lastTradeTimestamp': None,
|
|
1088
|
-
'status': status,
|
|
1089
|
-
'symbol': symbol,
|
|
1090
|
-
'type': 'market' if (price is None) else 'limit',
|
|
1091
|
-
'timeInForce': None,
|
|
1092
|
-
'postOnly': None,
|
|
1093
|
-
'side': side,
|
|
1094
|
-
'price': price,
|
|
1095
|
-
'stopPrice': None,
|
|
1096
|
-
'triggerPrice': None,
|
|
1097
|
-
'cost': cost,
|
|
1098
|
-
'amount': amount,
|
|
1099
|
-
'filled': filled,
|
|
1100
|
-
'remaining': remaining,
|
|
1101
|
-
'trades': trades,
|
|
1102
|
-
'fee': fee,
|
|
1103
|
-
'average': None,
|
|
1104
|
-
})
|
|
1342
|
+
data = self.safe_dict(response, 'data', {})
|
|
1343
|
+
ids = self.safe_list(data, 'clientOrderIds', [])
|
|
1344
|
+
orders = []
|
|
1345
|
+
for i in range(0, len(ids)):
|
|
1346
|
+
id = ids[i]
|
|
1347
|
+
orders.append({'clientOrderId': id})
|
|
1348
|
+
return self.parse_orders(orders)
|
|
1105
1349
|
|
|
1106
|
-
async def
|
|
1350
|
+
async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
|
|
1107
1351
|
"""
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
:param
|
|
1352
|
+
fetch the history of changes, actions done by the user or operations that altered the balance of the user
|
|
1353
|
+
|
|
1354
|
+
https://trade.cex.io/docs/#rest-private-api-calls-transaction-history
|
|
1355
|
+
|
|
1356
|
+
:param str [code]: unified currency code
|
|
1357
|
+
:param int [since]: timestamp in ms of the earliest ledger entry
|
|
1358
|
+
:param int [limit]: max number of ledger entries to return
|
|
1113
1359
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1114
|
-
:
|
|
1360
|
+
:param int [params.until]: timestamp in ms of the latest ledger entry
|
|
1361
|
+
:returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
|
|
1115
1362
|
"""
|
|
1116
1363
|
await self.load_markets()
|
|
1364
|
+
currency = None
|
|
1117
1365
|
request: dict = {}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
request['
|
|
1123
|
-
|
|
1366
|
+
if code is not None:
|
|
1367
|
+
currency = self.currency(code)
|
|
1368
|
+
request['currency'] = currency['id']
|
|
1369
|
+
if since is not None:
|
|
1370
|
+
request['dateFrom'] = since
|
|
1371
|
+
if limit is not None:
|
|
1372
|
+
request['pageSize'] = limit
|
|
1373
|
+
until = None
|
|
1374
|
+
until, params = self.handle_param_integer_2(params, 'until', 'till')
|
|
1375
|
+
if until is not None:
|
|
1376
|
+
request['dateTo'] = until
|
|
1377
|
+
response = await self.privatePostGetMyTransactionHistory(self.extend(request, params))
|
|
1378
|
+
#
|
|
1379
|
+
# {
|
|
1380
|
+
# "ok": "ok",
|
|
1381
|
+
# "data": [
|
|
1382
|
+
# {
|
|
1383
|
+
# "transactionId": "30367722",
|
|
1384
|
+
# "timestamp": "2024-10-14T14:08:49.987Z",
|
|
1385
|
+
# "accountId": "",
|
|
1386
|
+
# "type": "withdraw",
|
|
1387
|
+
# "amount": "-12.39060600",
|
|
1388
|
+
# "details": "Withdraw fundingId=1235039 clientId=up421412345 walletTxId=76337154166",
|
|
1389
|
+
# "currency": "USDT"
|
|
1390
|
+
# },
|
|
1391
|
+
# ...
|
|
1392
|
+
#
|
|
1393
|
+
data = self.safe_list(response, 'data', [])
|
|
1394
|
+
return self.parse_ledger(data, currency, since, limit)
|
|
1395
|
+
|
|
1396
|
+
def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
|
|
1397
|
+
amount = self.safe_string(item, 'amount')
|
|
1398
|
+
direction = None
|
|
1399
|
+
if Precise.string_le(amount, '0'):
|
|
1400
|
+
direction = 'out'
|
|
1401
|
+
amount = Precise.string_mul('-1', amount)
|
|
1124
1402
|
else:
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1403
|
+
direction = 'in'
|
|
1404
|
+
currencyId = self.safe_string(item, 'currency')
|
|
1405
|
+
currency = self.safe_currency(currencyId, currency)
|
|
1406
|
+
code = self.safe_currency_code(currencyId, currency)
|
|
1407
|
+
timestampString = self.safe_string(item, 'timestamp')
|
|
1408
|
+
timestamp = self.parse8601(timestampString)
|
|
1409
|
+
type = self.safe_string(item, 'type')
|
|
1410
|
+
return self.safe_ledger_entry({
|
|
1411
|
+
'info': item,
|
|
1412
|
+
'id': self.safe_string(item, 'transactionId'),
|
|
1413
|
+
'direction': direction,
|
|
1414
|
+
'account': self.safe_string(item, 'accountId', ''),
|
|
1415
|
+
'referenceAccount': None,
|
|
1416
|
+
'referenceId': None,
|
|
1417
|
+
'type': self.parse_ledger_entry_type(type),
|
|
1418
|
+
'currency': code,
|
|
1419
|
+
'amount': self.parse_number(amount),
|
|
1420
|
+
'timestamp': timestamp,
|
|
1421
|
+
'datetime': self.iso8601(timestamp),
|
|
1422
|
+
'before': None,
|
|
1423
|
+
'after': None,
|
|
1424
|
+
'status': None,
|
|
1425
|
+
'fee': None,
|
|
1426
|
+
}, currency)
|
|
1129
1427
|
|
|
1130
|
-
|
|
1428
|
+
def parse_ledger_entry_type(self, type):
|
|
1429
|
+
ledgerType: dict = {
|
|
1430
|
+
'deposit': 'deposit',
|
|
1431
|
+
'withdraw': 'withdrawal',
|
|
1432
|
+
'commission': 'fee',
|
|
1433
|
+
}
|
|
1434
|
+
return self.safe_string(ledgerType, type, type)
|
|
1435
|
+
|
|
1436
|
+
async def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
|
1131
1437
|
"""
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
:param
|
|
1438
|
+
fetch history of deposits and withdrawals
|
|
1439
|
+
|
|
1440
|
+
https://trade.cex.io/docs/#rest-private-api-calls-funding-history
|
|
1441
|
+
|
|
1442
|
+
:param str [code]: unified currency code for the currency of the deposit/withdrawals, default is None
|
|
1443
|
+
:param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None
|
|
1444
|
+
:param int [limit]: max number of deposit/withdrawals to return, default is None
|
|
1137
1445
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1138
|
-
:returns
|
|
1446
|
+
:returns dict: a list of `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
1139
1447
|
"""
|
|
1140
|
-
if symbol is None:
|
|
1141
|
-
raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
|
|
1142
1448
|
await self.load_markets()
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1449
|
+
request: dict = {}
|
|
1450
|
+
currency = None
|
|
1451
|
+
if code is not None:
|
|
1452
|
+
currency = self.currency(code)
|
|
1453
|
+
if since is not None:
|
|
1454
|
+
request['dateFrom'] = since
|
|
1455
|
+
if limit is not None:
|
|
1456
|
+
request['pageSize'] = limit
|
|
1457
|
+
until = None
|
|
1458
|
+
until, params = self.handle_param_integer_2(params, 'until', 'till')
|
|
1459
|
+
if until is not None:
|
|
1460
|
+
request['dateTo'] = until
|
|
1461
|
+
response = await self.privatePostGetMyFundingHistory(self.extend(request, params))
|
|
1462
|
+
#
|
|
1463
|
+
# {
|
|
1464
|
+
# "ok": "ok",
|
|
1465
|
+
# "data": [
|
|
1466
|
+
# {
|
|
1467
|
+
# "clientId": "up421412345",
|
|
1468
|
+
# "accountId": "",
|
|
1469
|
+
# "currency": "USDT",
|
|
1470
|
+
# "direction": "withdraw",
|
|
1471
|
+
# "amount": "12.39060600",
|
|
1472
|
+
# "commissionAmount": "0.00000000",
|
|
1473
|
+
# "status": "approved",
|
|
1474
|
+
# "updatedAt": "2024-10-14T14:08:50.013Z",
|
|
1475
|
+
# "txId": "30367718",
|
|
1476
|
+
# "details": {}
|
|
1477
|
+
# },
|
|
1478
|
+
# ...
|
|
1479
|
+
#
|
|
1480
|
+
data = self.safe_list(response, 'data', [])
|
|
1481
|
+
return self.parse_transactions(data, currency, since, limit)
|
|
1482
|
+
|
|
1483
|
+
def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
|
|
1484
|
+
currencyId = self.safe_string(transaction, 'currency')
|
|
1485
|
+
direction = self.safe_string(transaction, 'direction')
|
|
1486
|
+
type = 'withdrawal' if (direction == 'withdraw') else 'deposit'
|
|
1487
|
+
code = self.safe_currency_code(currencyId, currency)
|
|
1488
|
+
updatedAt = self.safe_string(transaction, 'updatedAt')
|
|
1489
|
+
timestamp = self.parse8601(updatedAt)
|
|
1490
|
+
return {
|
|
1491
|
+
'info': transaction,
|
|
1492
|
+
'id': self.safe_string(transaction, 'txId'),
|
|
1493
|
+
'txid': None,
|
|
1494
|
+
'type': type,
|
|
1495
|
+
'currency': code,
|
|
1496
|
+
'network': None,
|
|
1497
|
+
'amount': self.safe_number(transaction, 'amount'),
|
|
1498
|
+
'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
|
|
1499
|
+
'timestamp': timestamp,
|
|
1500
|
+
'datetime': self.iso8601(timestamp),
|
|
1501
|
+
'address': None,
|
|
1502
|
+
'addressFrom': None,
|
|
1503
|
+
'addressTo': None,
|
|
1504
|
+
'tag': None,
|
|
1505
|
+
'tagFrom': None,
|
|
1506
|
+
'tagTo': None,
|
|
1507
|
+
'updated': None,
|
|
1508
|
+
'comment': None,
|
|
1509
|
+
'fee': {
|
|
1510
|
+
'currency': code,
|
|
1511
|
+
'cost': self.safe_number(transaction, 'commissionAmount'),
|
|
1512
|
+
},
|
|
1513
|
+
'internal': None,
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
def parse_transaction_status(self, status: Str):
|
|
1517
|
+
statuses: dict = {
|
|
1518
|
+
'rejected': 'rejected',
|
|
1519
|
+
'pending': 'pending',
|
|
1520
|
+
'approved': 'ok',
|
|
1521
|
+
}
|
|
1522
|
+
return self.safe_string(statuses, status, status)
|
|
1147
1523
|
|
|
1148
|
-
async def
|
|
1524
|
+
async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
|
1149
1525
|
"""
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1526
|
+
transfer currency internally between wallets on the same account
|
|
1527
|
+
|
|
1528
|
+
https://trade.cex.io/docs/#rest-private-api-calls-internal-transfer
|
|
1529
|
+
|
|
1530
|
+
:param str code: unified currency code
|
|
1531
|
+
:param float amount: amount to transfer
|
|
1532
|
+
:param str fromAccount: 'SPOT', 'FUND', or 'CONTRACT'
|
|
1533
|
+
:param str toAccount: 'SPOT', 'FUND', or 'CONTRACT'
|
|
1153
1534
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1154
|
-
:returns dict:
|
|
1535
|
+
:returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
|
1155
1536
|
"""
|
|
1537
|
+
transfer = None
|
|
1538
|
+
if toAccount != '' and fromAccount != '':
|
|
1539
|
+
transfer = await self.transfer_between_sub_accounts(code, amount, fromAccount, toAccount, params)
|
|
1540
|
+
else:
|
|
1541
|
+
transfer = await self.transfer_between_main_and_sub_account(code, amount, fromAccount, toAccount, params)
|
|
1542
|
+
fillResponseFromRequest = self.handle_option('transfer', 'fillResponseFromRequest', True)
|
|
1543
|
+
if fillResponseFromRequest:
|
|
1544
|
+
transfer['fromAccount'] = fromAccount
|
|
1545
|
+
transfer['toAccount'] = toAccount
|
|
1546
|
+
return transfer
|
|
1547
|
+
|
|
1548
|
+
async def transfer_between_main_and_sub_account(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
|
1156
1549
|
await self.load_markets()
|
|
1550
|
+
currency = self.currency(code)
|
|
1551
|
+
fromMain = (fromAccount == '')
|
|
1552
|
+
targetAccount = toAccount if fromMain else fromAccount
|
|
1553
|
+
guid = self.safe_string(params, 'guid', self.uuid())
|
|
1157
1554
|
request: dict = {
|
|
1158
|
-
'
|
|
1555
|
+
'currency': currency['id'],
|
|
1556
|
+
'amount': self.currency_to_precision(code, amount),
|
|
1557
|
+
'accountId': targetAccount,
|
|
1558
|
+
'clientTxId': guid,
|
|
1159
1559
|
}
|
|
1160
|
-
response =
|
|
1161
|
-
|
|
1560
|
+
response = None
|
|
1561
|
+
if fromMain:
|
|
1562
|
+
response = await self.privatePostDoDepositFundsFromWallet(self.extend(request, params))
|
|
1563
|
+
else:
|
|
1564
|
+
response = await self.privatePostDoWithdrawalFundsToWallet(self.extend(request, params))
|
|
1565
|
+
# both endpoints return the same structure, the only difference is that
|
|
1566
|
+
# the "accountId" is filled with the "subAccount"
|
|
1162
1567
|
#
|
|
1163
1568
|
# {
|
|
1164
|
-
# "
|
|
1165
|
-
# "
|
|
1166
|
-
#
|
|
1167
|
-
#
|
|
1168
|
-
#
|
|
1169
|
-
#
|
|
1170
|
-
#
|
|
1171
|
-
# "status": "d",
|
|
1172
|
-
# "symbol1": "ETH",
|
|
1173
|
-
# "symbol2": "EUR",
|
|
1174
|
-
# "amount": "0.50000000",
|
|
1175
|
-
# "kind": "api",
|
|
1176
|
-
# "price": "923.3386",
|
|
1177
|
-
# "tfacf": "1",
|
|
1178
|
-
# "fa:EUR": "0.55",
|
|
1179
|
-
# "ta:EUR": "369.77",
|
|
1180
|
-
# "remains": "0.00000000",
|
|
1181
|
-
# "tfa:EUR": "0.22",
|
|
1182
|
-
# "tta:EUR": "91.95",
|
|
1183
|
-
# "a:ETH:cds": "0.50000000",
|
|
1184
|
-
# "a:EUR:cds": "461.72",
|
|
1185
|
-
# "f:EUR:cds": "0.77",
|
|
1186
|
-
# "tradingFeeMaker": "0.15",
|
|
1187
|
-
# "tradingFeeTaker": "0.23",
|
|
1188
|
-
# "tradingFeeStrategy": "userVolumeAmount",
|
|
1189
|
-
# "tradingFeeUserVolumeAmount": "2896912572",
|
|
1190
|
-
# "orderId": "5442731603",
|
|
1191
|
-
# "next": False,
|
|
1192
|
-
# "vtx": [
|
|
1193
|
-
# {
|
|
1194
|
-
# "id": "5442734452",
|
|
1195
|
-
# "type": "sell",
|
|
1196
|
-
# "time": "2018-01-16T19:52:58.452Z",
|
|
1197
|
-
# "user": "up106404164",
|
|
1198
|
-
# "c": "user:up106404164:a:EUR",
|
|
1199
|
-
# "d": "order:5442731603:a:EUR",
|
|
1200
|
-
# "a": "104.53000000",
|
|
1201
|
-
# "amount": "104.53000000",
|
|
1202
|
-
# "balance": "932.71000000",
|
|
1203
|
-
# "symbol": "EUR",
|
|
1204
|
-
# "order": "5442731603",
|
|
1205
|
-
# "buy": "5442734443",
|
|
1206
|
-
# "sell": "5442731603",
|
|
1207
|
-
# "pair": null,
|
|
1208
|
-
# "pos": null,
|
|
1209
|
-
# "office": null,
|
|
1210
|
-
# "cs": "932.71",
|
|
1211
|
-
# "ds": 0,
|
|
1212
|
-
# "price": 923.3386,
|
|
1213
|
-
# "symbol2": "ETH",
|
|
1214
|
-
# "fee_amount": "0.16"
|
|
1215
|
-
# },
|
|
1216
|
-
# {
|
|
1217
|
-
# "id": "5442731609",
|
|
1218
|
-
# "type": "sell",
|
|
1219
|
-
# "time": "2018-01-16T19:52:38.071Z",
|
|
1220
|
-
# "user": "up106404164",
|
|
1221
|
-
# "c": "user:up106404164:a:EUR",
|
|
1222
|
-
# "d": "order:5442731603:a:EUR",
|
|
1223
|
-
# "a": "91.73000000",
|
|
1224
|
-
# "amount": "91.73000000",
|
|
1225
|
-
# "balance": "563.49000000",
|
|
1226
|
-
# "symbol": "EUR",
|
|
1227
|
-
# "order": "5442731603",
|
|
1228
|
-
# "buy": "5442618127",
|
|
1229
|
-
# "sell": "5442731603",
|
|
1230
|
-
# "pair": null,
|
|
1231
|
-
# "pos": null,
|
|
1232
|
-
# "office": null,
|
|
1233
|
-
# "cs": "563.49",
|
|
1234
|
-
# "ds": 0,
|
|
1235
|
-
# "price": 924.0092,
|
|
1236
|
-
# "symbol2": "ETH",
|
|
1237
|
-
# "fee_amount": "0.22"
|
|
1238
|
-
# },
|
|
1239
|
-
# {
|
|
1240
|
-
# "id": "5442731604",
|
|
1241
|
-
# "type": "sell",
|
|
1242
|
-
# "time": "2018-01-16T19:52:38.071Z",
|
|
1243
|
-
# "user": "up106404164",
|
|
1244
|
-
# "c": "order:5442731603:a:ETH",
|
|
1245
|
-
# "d": "user:up106404164:a:ETH",
|
|
1246
|
-
# "a": "0.50000000",
|
|
1247
|
-
# "amount": "-0.50000000",
|
|
1248
|
-
# "balance": "15.80995000",
|
|
1249
|
-
# "symbol": "ETH",
|
|
1250
|
-
# "order": "5442731603",
|
|
1251
|
-
# "buy": null,
|
|
1252
|
-
# "sell": null,
|
|
1253
|
-
# "pair": null,
|
|
1254
|
-
# "pos": null,
|
|
1255
|
-
# "office": null,
|
|
1256
|
-
# "cs": "0.50000000",
|
|
1257
|
-
# "ds": "15.80995000"
|
|
1258
|
-
# }
|
|
1259
|
-
# ]
|
|
1569
|
+
# "ok": "ok",
|
|
1570
|
+
# "data": {
|
|
1571
|
+
# "accountId": "sub1",
|
|
1572
|
+
# "clientTxId": "27ba8284-67cf-4386-9ec7-80b3871abd45",
|
|
1573
|
+
# "currency": "USDT",
|
|
1574
|
+
# "status": "approved"
|
|
1575
|
+
# }
|
|
1260
1576
|
# }
|
|
1261
1577
|
#
|
|
1262
|
-
|
|
1578
|
+
data = self.safe_dict(response, 'data', {})
|
|
1579
|
+
return self.parse_transfer(data, currency)
|
|
1263
1580
|
|
|
1264
|
-
async def
|
|
1265
|
-
"""
|
|
1266
|
-
:see: https://docs.cex.io/#archived-orders
|
|
1267
|
-
fetches information on multiple orders made by the user
|
|
1268
|
-
:param str symbol: unified market symbol of the market orders were made in
|
|
1269
|
-
:param int [since]: the earliest time in ms to fetch orders for
|
|
1270
|
-
:param int [limit]: the maximum number of order structures to retrieve
|
|
1271
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1272
|
-
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1273
|
-
"""
|
|
1581
|
+
async def transfer_between_sub_accounts(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
|
1274
1582
|
await self.load_markets()
|
|
1275
|
-
|
|
1583
|
+
currency = self.currency(code)
|
|
1276
1584
|
request: dict = {
|
|
1277
|
-
'
|
|
1278
|
-
'
|
|
1279
|
-
'
|
|
1585
|
+
'currency': currency['id'],
|
|
1586
|
+
'amount': self.currency_to_precision(code, amount),
|
|
1587
|
+
'fromAccountId': fromAccount,
|
|
1588
|
+
'toAccountId': toAccount,
|
|
1280
1589
|
}
|
|
1281
|
-
response = await self.
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
# "symbol1": "ETH",
|
|
1293
|
-
# "symbol2": "GBP",
|
|
1294
|
-
# "amount": "0.20000000",
|
|
1295
|
-
# "price": "200.5625",
|
|
1296
|
-
# "remains": "0.20000000",
|
|
1297
|
-
# 'a:ETH:cds': "0.20000000",
|
|
1298
|
-
# "tradingFeeMaker": "0",
|
|
1299
|
-
# "tradingFeeTaker": "0.16",
|
|
1300
|
-
# "tradingFeeUserVolumeAmount": "10155061217",
|
|
1301
|
-
# "orderId": "4005785516"}
|
|
1302
|
-
# --
|
|
1303
|
-
# cancelled(partially filled buy):
|
|
1304
|
-
# {"id": "4084911657",
|
|
1305
|
-
# "type": "buy",
|
|
1306
|
-
# "time": "2017-08-05T03:18:39.596Z",
|
|
1307
|
-
# "lastTxTime": "2019-03-19T17:37:46.404Z",
|
|
1308
|
-
# "lastTx": "8459265833",
|
|
1309
|
-
# "pos": null,
|
|
1310
|
-
# "status": "cd",
|
|
1311
|
-
# "symbol1": "BTC",
|
|
1312
|
-
# "symbol2": "GBP",
|
|
1313
|
-
# "amount": "0.05000000",
|
|
1314
|
-
# "price": "2241.4692",
|
|
1315
|
-
# "tfacf": "1",
|
|
1316
|
-
# "remains": "0.03910535",
|
|
1317
|
-
# 'tfa:GBP': "0.04",
|
|
1318
|
-
# 'tta:GBP': "24.39",
|
|
1319
|
-
# 'a:BTC:cds': "0.01089465",
|
|
1320
|
-
# 'a:GBP:cds': "112.26",
|
|
1321
|
-
# 'f:GBP:cds': "0.04",
|
|
1322
|
-
# "tradingFeeMaker": "0",
|
|
1323
|
-
# "tradingFeeTaker": "0.16",
|
|
1324
|
-
# "tradingFeeUserVolumeAmount": "13336396963",
|
|
1325
|
-
# "orderId": "4084911657"}
|
|
1326
|
-
# --
|
|
1327
|
-
# cancelled(partially filled sell):
|
|
1328
|
-
# {"id": "4426728375",
|
|
1329
|
-
# "type": "sell",
|
|
1330
|
-
# "time": "2017-09-22T00:24:20.126Z",
|
|
1331
|
-
# "lastTxTime": "2017-09-22T00:24:30.476Z",
|
|
1332
|
-
# "lastTx": "4426729543",
|
|
1333
|
-
# "pos": null,
|
|
1334
|
-
# "status": "cd",
|
|
1335
|
-
# "symbol1": "BCH",
|
|
1336
|
-
# "symbol2": "BTC",
|
|
1337
|
-
# "amount": "0.10000000",
|
|
1338
|
-
# "price": "0.11757182",
|
|
1339
|
-
# "tfacf": "1",
|
|
1340
|
-
# "remains": "0.09935956",
|
|
1341
|
-
# 'tfa:BTC': "0.00000014",
|
|
1342
|
-
# 'tta:BTC': "0.00007537",
|
|
1343
|
-
# 'a:BCH:cds': "0.10000000",
|
|
1344
|
-
# 'a:BTC:cds': "0.00007537",
|
|
1345
|
-
# 'f:BTC:cds': "0.00000014",
|
|
1346
|
-
# "tradingFeeMaker": "0",
|
|
1347
|
-
# "tradingFeeTaker": "0.18",
|
|
1348
|
-
# "tradingFeeUserVolumeAmount": "3466715450",
|
|
1349
|
-
# "orderId": "4426728375"}
|
|
1350
|
-
# --
|
|
1351
|
-
# filled:
|
|
1352
|
-
# {"id": "5342275378",
|
|
1353
|
-
# "type": "sell",
|
|
1354
|
-
# "time": "2018-01-04T00:28:12.992Z",
|
|
1355
|
-
# "lastTxTime": "2018-01-04T00:28:12.992Z",
|
|
1356
|
-
# "lastTx": "5342275393",
|
|
1357
|
-
# "pos": null,
|
|
1358
|
-
# "status": "d",
|
|
1359
|
-
# "symbol1": "BCH",
|
|
1360
|
-
# "symbol2": "BTC",
|
|
1361
|
-
# "amount": "0.10000000",
|
|
1362
|
-
# "kind": "api",
|
|
1363
|
-
# "price": "0.17",
|
|
1364
|
-
# "remains": "0.00000000",
|
|
1365
|
-
# 'tfa:BTC': "0.00003902",
|
|
1366
|
-
# 'tta:BTC': "0.01699999",
|
|
1367
|
-
# 'a:BCH:cds': "0.10000000",
|
|
1368
|
-
# 'a:BTC:cds': "0.01699999",
|
|
1369
|
-
# 'f:BTC:cds': "0.00003902",
|
|
1370
|
-
# "tradingFeeMaker": "0.15",
|
|
1371
|
-
# "tradingFeeTaker": "0.23",
|
|
1372
|
-
# "tradingFeeUserVolumeAmount": "1525951128",
|
|
1373
|
-
# "orderId": "5342275378"}
|
|
1374
|
-
# --
|
|
1375
|
-
# market order(buy):
|
|
1376
|
-
# {"id": "6281946200",
|
|
1377
|
-
# "pos": null,
|
|
1378
|
-
# "time": "2018-05-23T11:55:43.467Z",
|
|
1379
|
-
# "type": "buy",
|
|
1380
|
-
# "amount": "0.00000000",
|
|
1381
|
-
# "lastTx": "6281946210",
|
|
1382
|
-
# "status": "d",
|
|
1383
|
-
# "amount2": "20.00",
|
|
1384
|
-
# "orderId": "6281946200",
|
|
1385
|
-
# "remains": "0.00000000",
|
|
1386
|
-
# "symbol1": "ETH",
|
|
1387
|
-
# "symbol2": "EUR",
|
|
1388
|
-
# "tfa:EUR": "0.05",
|
|
1389
|
-
# "tta:EUR": "19.94",
|
|
1390
|
-
# "a:ETH:cds": "0.03764100",
|
|
1391
|
-
# "a:EUR:cds": "20.00",
|
|
1392
|
-
# "f:EUR:cds": "0.05",
|
|
1393
|
-
# "lastTxTime": "2018-05-23T11:55:43.467Z",
|
|
1394
|
-
# "tradingFeeTaker": "0.25",
|
|
1395
|
-
# "tradingFeeUserVolumeAmount": "55998097"}
|
|
1396
|
-
# --
|
|
1397
|
-
# market order(sell):
|
|
1398
|
-
# {"id": "6282200948",
|
|
1399
|
-
# "pos": null,
|
|
1400
|
-
# "time": "2018-05-23T12:42:58.315Z",
|
|
1401
|
-
# "type": "sell",
|
|
1402
|
-
# "amount": "-0.05000000",
|
|
1403
|
-
# "lastTx": "6282200958",
|
|
1404
|
-
# "status": "d",
|
|
1405
|
-
# "orderId": "6282200948",
|
|
1406
|
-
# "remains": "0.00000000",
|
|
1407
|
-
# "symbol1": "ETH",
|
|
1408
|
-
# "symbol2": "EUR",
|
|
1409
|
-
# "tfa:EUR": "0.07",
|
|
1410
|
-
# "tta:EUR": "26.49",
|
|
1411
|
-
# "a:ETH:cds": "0.05000000",
|
|
1412
|
-
# "a:EUR:cds": "26.49",
|
|
1413
|
-
# "f:EUR:cds": "0.07",
|
|
1414
|
-
# "lastTxTime": "2018-05-23T12:42:58.315Z",
|
|
1415
|
-
# "tradingFeeTaker": "0.25",
|
|
1416
|
-
# "tradingFeeUserVolumeAmount": "56294576"}
|
|
1417
|
-
order = response[i]
|
|
1418
|
-
status = self.parse_order_status(self.safe_string(order, 'status'))
|
|
1419
|
-
baseId = self.safe_string(order, 'symbol1')
|
|
1420
|
-
quoteId = self.safe_string(order, 'symbol2')
|
|
1421
|
-
base = self.safe_currency_code(baseId)
|
|
1422
|
-
quote = self.safe_currency_code(quoteId)
|
|
1423
|
-
symbolInner = base + '/' + quote
|
|
1424
|
-
side = self.safe_string(order, 'type')
|
|
1425
|
-
baseAmount = self.safe_number(order, 'a:' + baseId + ':cds')
|
|
1426
|
-
quoteAmount = self.safe_number(order, 'a:' + quoteId + ':cds')
|
|
1427
|
-
fee = self.safe_number(order, 'f:' + quoteId + ':cds')
|
|
1428
|
-
amount = self.safe_string(order, 'amount')
|
|
1429
|
-
price = self.safe_string(order, 'price')
|
|
1430
|
-
remaining = self.safe_string(order, 'remains')
|
|
1431
|
-
filled = Precise.string_sub(amount, remaining)
|
|
1432
|
-
orderAmount = None
|
|
1433
|
-
cost = None
|
|
1434
|
-
average = None
|
|
1435
|
-
type = None
|
|
1436
|
-
if not price:
|
|
1437
|
-
type = 'market'
|
|
1438
|
-
orderAmount = baseAmount
|
|
1439
|
-
cost = quoteAmount
|
|
1440
|
-
average = Precise.string_div(orderAmount, cost)
|
|
1441
|
-
else:
|
|
1442
|
-
ta = self.safe_string(order, 'ta:' + quoteId, '0')
|
|
1443
|
-
tta = self.safe_string(order, 'tta:' + quoteId, '0')
|
|
1444
|
-
fa = self.safe_string(order, 'fa:' + quoteId, '0')
|
|
1445
|
-
tfa = self.safe_string(order, 'tfa:' + quoteId, '0')
|
|
1446
|
-
if side == 'sell':
|
|
1447
|
-
cost = Precise.string_add(Precise.string_add(ta, tta), Precise.string_add(fa, tfa))
|
|
1448
|
-
else:
|
|
1449
|
-
cost = Precise.string_sub(Precise.string_add(ta, tta), Precise.string_add(fa, tfa))
|
|
1450
|
-
type = 'limit'
|
|
1451
|
-
orderAmount = amount
|
|
1452
|
-
average = Precise.string_div(cost, filled)
|
|
1453
|
-
time = self.safe_string(order, 'time')
|
|
1454
|
-
lastTxTime = self.safe_string(order, 'lastTxTime')
|
|
1455
|
-
timestamp = self.parse8601(time)
|
|
1456
|
-
safeOrder = self.safe_order({
|
|
1457
|
-
'info': order,
|
|
1458
|
-
'id': self.safe_string(order, 'id'),
|
|
1459
|
-
'timestamp': timestamp,
|
|
1460
|
-
'datetime': self.iso8601(timestamp),
|
|
1461
|
-
'lastUpdated': self.parse8601(lastTxTime),
|
|
1462
|
-
'status': status,
|
|
1463
|
-
'symbol': symbolInner,
|
|
1464
|
-
'side': side,
|
|
1465
|
-
'price': price,
|
|
1466
|
-
'amount': orderAmount,
|
|
1467
|
-
'average': average,
|
|
1468
|
-
'type': type,
|
|
1469
|
-
'filled': filled,
|
|
1470
|
-
'cost': cost,
|
|
1471
|
-
'remaining': remaining,
|
|
1472
|
-
'fee': {
|
|
1473
|
-
'cost': fee,
|
|
1474
|
-
'currency': quote,
|
|
1475
|
-
},
|
|
1476
|
-
})
|
|
1477
|
-
results.append(safeOrder)
|
|
1478
|
-
return results
|
|
1479
|
-
|
|
1480
|
-
def parse_order_status(self, status: Str):
|
|
1481
|
-
return self.safe_string(self.options['order']['status'], status, status)
|
|
1590
|
+
response = await self.privatePostDoMyInternalTransfer(self.extend(request, params))
|
|
1591
|
+
#
|
|
1592
|
+
# {
|
|
1593
|
+
# "ok": "ok",
|
|
1594
|
+
# "data": {
|
|
1595
|
+
# "transactionId": "30225415"
|
|
1596
|
+
# }
|
|
1597
|
+
# }
|
|
1598
|
+
#
|
|
1599
|
+
data = self.safe_dict(response, 'data', {})
|
|
1600
|
+
return self.parse_transfer(data, currency)
|
|
1482
1601
|
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
:
|
|
1489
|
-
:
|
|
1490
|
-
:
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
#
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1602
|
+
def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
|
|
1603
|
+
#
|
|
1604
|
+
# transferBetweenSubAccounts
|
|
1605
|
+
#
|
|
1606
|
+
# {
|
|
1607
|
+
# "ok": "ok",
|
|
1608
|
+
# "data": {
|
|
1609
|
+
# "transactionId": "30225415"
|
|
1610
|
+
# }
|
|
1611
|
+
# }
|
|
1612
|
+
#
|
|
1613
|
+
# transfer between main/sub
|
|
1614
|
+
#
|
|
1615
|
+
# {
|
|
1616
|
+
# "ok": "ok",
|
|
1617
|
+
# "data": {
|
|
1618
|
+
# "accountId": "sub1",
|
|
1619
|
+
# "clientTxId": "27ba8284-67cf-4386-9ec7-80b3871abd45",
|
|
1620
|
+
# "currency": "USDT",
|
|
1621
|
+
# "status": "approved"
|
|
1622
|
+
# }
|
|
1623
|
+
# }
|
|
1624
|
+
#
|
|
1625
|
+
currencyId = self.safe_string(transfer, 'currency')
|
|
1626
|
+
currencyCode = self.safe_currency_code(currencyId, currency)
|
|
1627
|
+
return {
|
|
1628
|
+
'info': transfer,
|
|
1629
|
+
'id': self.safe_string_2(transfer, 'transactionId', 'clientTxId'),
|
|
1630
|
+
'timestamp': None,
|
|
1631
|
+
'datetime': None,
|
|
1632
|
+
'currency': currencyCode,
|
|
1633
|
+
'amount': None,
|
|
1634
|
+
'fromAccount': None,
|
|
1635
|
+
'toAccount': None,
|
|
1636
|
+
'status': self.parse_transaction_status(self.safe_string(transfer, 'status')),
|
|
1509
1637
|
}
|
|
1510
|
-
response = await self.privatePostCancelReplaceOrderPair(self.extend(request, params))
|
|
1511
|
-
return self.parse_order(response, market)
|
|
1512
1638
|
|
|
1513
|
-
async def fetch_deposit_address(self, code: str, params={}):
|
|
1639
|
+
async def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
|
|
1514
1640
|
"""
|
|
1515
|
-
:see: https://docs.cex.io/#get-crypto-address
|
|
1516
1641
|
fetch the deposit address for a currency associated with self account
|
|
1642
|
+
|
|
1643
|
+
https://trade.cex.io/docs/#rest-private-api-calls-deposit-address
|
|
1644
|
+
|
|
1517
1645
|
:param str code: unified currency code
|
|
1518
1646
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1647
|
+
:param str [params.accountId]: account-id(default to empty string) to refer to(at self moment, only sub-accounts allowed by exchange)
|
|
1519
1648
|
:returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
|
|
1520
1649
|
"""
|
|
1650
|
+
accountId = None
|
|
1651
|
+
accountId, params = self.handle_option_and_params(params, 'createOrder', 'accountId')
|
|
1652
|
+
if accountId is None:
|
|
1653
|
+
raise ArgumentsRequired(self.id + ' fetchDepositAddress() : main account is not allowed to fetch deposit address from api, set params["accountId"] or .options["createOrder"]["accountId"] to the name of your sub-account')
|
|
1521
1654
|
await self.load_markets()
|
|
1655
|
+
networkCode = None
|
|
1656
|
+
networkCode, params = self.handle_network_code_and_params(params)
|
|
1522
1657
|
currency = self.currency(code)
|
|
1523
1658
|
request: dict = {
|
|
1524
|
-
'
|
|
1659
|
+
'accountId': accountId,
|
|
1660
|
+
'currency': currency['id'], # documentation is wrong about self param
|
|
1661
|
+
'blockchain': self.network_code_to_id(networkCode),
|
|
1525
1662
|
}
|
|
1526
|
-
|
|
1527
|
-
# atm, cex doesn't support network in the request
|
|
1528
|
-
response = await self.privatePostGetCryptoAddress(self.extend(request, query))
|
|
1663
|
+
response = await self.privatePostGetDepositAddress(self.extend(request, params))
|
|
1529
1664
|
#
|
|
1530
1665
|
# {
|
|
1531
|
-
#
|
|
1532
|
-
#
|
|
1533
|
-
#
|
|
1534
|
-
#
|
|
1535
|
-
#
|
|
1536
|
-
#
|
|
1537
|
-
#
|
|
1538
|
-
#
|
|
1666
|
+
# "ok": "ok",
|
|
1667
|
+
# "data": {
|
|
1668
|
+
# "address": "TCr..................1AE",
|
|
1669
|
+
# "accountId": "sub1",
|
|
1670
|
+
# "currency": "USDT",
|
|
1671
|
+
# "blockchain": "tron"
|
|
1672
|
+
# }
|
|
1673
|
+
# }
|
|
1539
1674
|
#
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
# }
|
|
1548
|
-
#
|
|
1549
|
-
data = self.safe_value(response, 'data', {})
|
|
1550
|
-
addresses = self.safe_value(data, 'addresses', [])
|
|
1551
|
-
chainsIndexedById = self.index_by(addresses, 'blockchain')
|
|
1552
|
-
selectedNetworkId = self.select_network_id_from_raw_networks(code, networkCode, chainsIndexedById)
|
|
1553
|
-
addressObject = self.safe_value(chainsIndexedById, selectedNetworkId, {})
|
|
1554
|
-
address = self.safe_string_2(addressObject, 'address', 'destination')
|
|
1675
|
+
data = self.safe_dict(response, 'data', {})
|
|
1676
|
+
return self.parse_deposit_address(data, currency)
|
|
1677
|
+
|
|
1678
|
+
def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
|
|
1679
|
+
address = self.safe_string(depositAddress, 'address')
|
|
1680
|
+
currencyId = self.safe_string(depositAddress, 'currency')
|
|
1681
|
+
currency = self.safe_currency(currencyId, currency)
|
|
1555
1682
|
self.check_address(address)
|
|
1556
1683
|
return {
|
|
1557
|
-
'
|
|
1684
|
+
'info': depositAddress,
|
|
1685
|
+
'currency': currency['code'],
|
|
1686
|
+
'network': self.network_id_to_code(self.safe_string(depositAddress, 'blockchain')),
|
|
1558
1687
|
'address': address,
|
|
1559
|
-
'tag':
|
|
1560
|
-
'network': self.network_id_to_code(selectedNetworkId),
|
|
1561
|
-
'info': data,
|
|
1688
|
+
'tag': None,
|
|
1562
1689
|
}
|
|
1563
1690
|
|
|
1564
|
-
def nonce(self):
|
|
1565
|
-
return self.milliseconds()
|
|
1566
|
-
|
|
1567
1691
|
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
|
1568
|
-
url = self.urls['api'][
|
|
1692
|
+
url = self.urls['api'][api] + '/' + self.implode_params(path, params)
|
|
1569
1693
|
query = self.omit(params, self.extract_params(path))
|
|
1570
1694
|
if api == 'public':
|
|
1571
|
-
if
|
|
1572
|
-
|
|
1695
|
+
if method == 'GET':
|
|
1696
|
+
if query:
|
|
1697
|
+
url += '?' + self.urlencode(query)
|
|
1698
|
+
else:
|
|
1699
|
+
body = self.json(query)
|
|
1700
|
+
headers = {
|
|
1701
|
+
'Content-Type': 'application/json',
|
|
1702
|
+
}
|
|
1573
1703
|
else:
|
|
1574
1704
|
self.check_required_credentials()
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
'key': self.apiKey,
|
|
1580
|
-
'signature': signature.upper(),
|
|
1581
|
-
'nonce': nonce,
|
|
1582
|
-
}, query))
|
|
1705
|
+
seconds = str(self.seconds())
|
|
1706
|
+
body = self.json(query)
|
|
1707
|
+
auth = path + seconds + body
|
|
1708
|
+
signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256, 'base64')
|
|
1583
1709
|
headers = {
|
|
1584
1710
|
'Content-Type': 'application/json',
|
|
1711
|
+
'X-AGGR-KEY': self.apiKey,
|
|
1712
|
+
'X-AGGR-TIMESTAMP': seconds,
|
|
1713
|
+
'X-AGGR-SIGNATURE': signature,
|
|
1585
1714
|
}
|
|
1586
1715
|
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
|
1587
1716
|
|
|
1588
1717
|
def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
return None
|
|
1718
|
+
# in some cases, like from createOrder, exchange returns nested escaped JSON string:
|
|
1719
|
+
# {"ok":"ok","data":{"messageType":"executionReport", "orderRejectReason":"{\"code\":405}"}}
|
|
1720
|
+
# and because of `.parseJson` bug, we need extra fix
|
|
1593
1721
|
if response is None:
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1722
|
+
if body is None:
|
|
1723
|
+
raise NullResponse(self.id + ' returned empty response')
|
|
1724
|
+
elif body[0] == '{':
|
|
1725
|
+
fixed = self.fix_stringified_json_members(body)
|
|
1726
|
+
response = self.parse_json(fixed)
|
|
1727
|
+
else:
|
|
1728
|
+
raise NullResponse(self.id + ' returned unparsed response: ' + body)
|
|
1729
|
+
error = self.safe_string(response, 'error')
|
|
1730
|
+
if error is not None:
|
|
1601
1731
|
feedback = self.id + ' ' + body
|
|
1602
|
-
self.throw_exactly_matched_exception(self.exceptions['exact'],
|
|
1603
|
-
self.throw_broadly_matched_exception(self.exceptions['broad'],
|
|
1732
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], error, feedback)
|
|
1733
|
+
self.throw_broadly_matched_exception(self.exceptions['broad'], error, feedback)
|
|
1604
1734
|
raise ExchangeError(feedback)
|
|
1735
|
+
# check errors in order-engine(the responses are not standard, so we parse here)
|
|
1736
|
+
if url.find('do_my_new_order') >= 0:
|
|
1737
|
+
data = self.safe_dict(response, 'data', {})
|
|
1738
|
+
rejectReason = self.safe_string(data, 'rejectReason')
|
|
1739
|
+
if rejectReason is not None:
|
|
1740
|
+
self.throw_broadly_matched_exception(self.exceptions['broad'], rejectReason, rejectReason)
|
|
1741
|
+
raise ExchangeError(self.id + ' createOrder() ' + rejectReason)
|
|
1605
1742
|
return None
|