ccxt 4.2.76__py2.py3-none-any.whl → 4.4.48__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 +36 -14
- ccxt/abstract/alpaca.py +4 -0
- ccxt/abstract/bigone.py +1 -1
- ccxt/abstract/binance.py +112 -48
- ccxt/abstract/binancecoinm.py +112 -48
- ccxt/abstract/binanceus.py +147 -83
- ccxt/abstract/binanceusdm.py +112 -48
- ccxt/abstract/bingx.py +133 -78
- ccxt/abstract/bitbank.py +5 -0
- ccxt/abstract/bitfinex.py +136 -65
- ccxt/abstract/bitfinex1.py +69 -0
- ccxt/abstract/bitflyer.py +1 -0
- ccxt/abstract/bitget.py +8 -1
- ccxt/abstract/bitmart.py +13 -1
- ccxt/abstract/bitopro.py +1 -0
- ccxt/abstract/bitpanda.py +0 -12
- ccxt/abstract/bitrue.py +3 -3
- ccxt/abstract/bitstamp.py +26 -3
- ccxt/abstract/blofin.py +24 -0
- ccxt/abstract/btcbox.py +1 -0
- ccxt/abstract/bybit.py +29 -14
- ccxt/abstract/cex.py +28 -29
- ccxt/abstract/coinbase.py +6 -0
- ccxt/abstract/coinbaseadvanced.py +94 -0
- ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
- ccxt/abstract/coinbaseinternational.py +1 -1
- ccxt/abstract/coincatch.py +94 -0
- ccxt/abstract/coinex.py +233 -123
- ccxt/abstract/coinmetro.py +1 -0
- ccxt/abstract/cryptocom.py +14 -0
- ccxt/abstract/defx.py +69 -0
- ccxt/abstract/deribit.py +1 -0
- ccxt/abstract/digifinex.py +1 -0
- ccxt/abstract/ellipx.py +25 -0
- ccxt/abstract/gate.py +20 -0
- ccxt/abstract/gateio.py +20 -0
- ccxt/abstract/gemini.py +1 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/hyperliquid.py +1 -1
- ccxt/abstract/independentreserve.py +6 -0
- ccxt/abstract/kraken.py +4 -3
- ccxt/abstract/krakenfutures.py +4 -0
- ccxt/abstract/kucoin.py +25 -0
- ccxt/abstract/kucoinfutures.py +35 -0
- ccxt/abstract/luno.py +2 -0
- ccxt/abstract/mexc.py +4 -0
- ccxt/abstract/myokx.py +340 -0
- ccxt/abstract/oceanex.py +5 -0
- ccxt/abstract/okx.py +30 -0
- ccxt/abstract/onetrading.py +0 -12
- ccxt/abstract/oxfun.py +34 -0
- ccxt/abstract/paradex.py +40 -0
- ccxt/abstract/phemex.py +1 -0
- ccxt/abstract/upbit.py +4 -0
- ccxt/abstract/vertex.py +19 -0
- ccxt/abstract/whitebit.py +31 -1
- ccxt/abstract/woo.py +6 -2
- ccxt/abstract/woofipro.py +119 -0
- ccxt/abstract/xt.py +153 -0
- ccxt/abstract/zonda.py +6 -0
- ccxt/ace.py +164 -60
- ccxt/alpaca.py +727 -63
- ccxt/ascendex.py +395 -249
- ccxt/async_support/__init__.py +36 -14
- ccxt/async_support/ace.py +164 -60
- ccxt/async_support/alpaca.py +727 -63
- ccxt/async_support/ascendex.py +396 -249
- ccxt/async_support/base/exchange.py +531 -155
- ccxt/async_support/base/ws/aiohttp_client.py +28 -5
- ccxt/async_support/base/ws/cache.py +3 -2
- ccxt/async_support/base/ws/client.py +26 -5
- ccxt/async_support/base/ws/fast_client.py +4 -3
- ccxt/async_support/base/ws/functions.py +1 -1
- ccxt/async_support/base/ws/future.py +40 -31
- ccxt/async_support/base/ws/order_book_side.py +3 -0
- ccxt/async_support/bequant.py +1 -1
- ccxt/async_support/bigone.py +329 -202
- ccxt/async_support/binance.py +3513 -1511
- ccxt/async_support/binancecoinm.py +2 -1
- ccxt/async_support/binanceus.py +12 -1
- ccxt/async_support/binanceusdm.py +3 -1
- ccxt/async_support/bingx.py +3105 -881
- ccxt/async_support/bit2c.py +119 -38
- ccxt/async_support/bitbank.py +215 -76
- ccxt/async_support/bitbns.py +124 -53
- ccxt/async_support/bitfinex.py +3236 -1078
- ccxt/async_support/bitfinex1.py +1711 -0
- ccxt/async_support/bitflyer.py +239 -50
- ccxt/async_support/bitget.py +1513 -563
- ccxt/async_support/bithumb.py +201 -67
- ccxt/async_support/bitmart.py +1320 -435
- ccxt/async_support/bitmex.py +308 -111
- ccxt/async_support/bitopro.py +256 -96
- ccxt/async_support/bitrue.py +365 -233
- ccxt/async_support/bitso.py +201 -89
- ccxt/async_support/bitstamp.py +438 -269
- ccxt/async_support/bitteam.py +179 -73
- ccxt/async_support/bitvavo.py +180 -70
- ccxt/async_support/bl3p.py +92 -25
- ccxt/async_support/blockchaincom.py +193 -79
- ccxt/async_support/blofin.py +403 -150
- ccxt/async_support/btcalpha.py +161 -55
- ccxt/async_support/btcbox.py +250 -34
- ccxt/async_support/btcmarkets.py +232 -85
- ccxt/async_support/btcturk.py +159 -60
- ccxt/async_support/bybit.py +2326 -1255
- ccxt/async_support/cex.py +1409 -1329
- ccxt/async_support/coinbase.py +1455 -288
- ccxt/async_support/coinbaseadvanced.py +17 -0
- ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/async_support/coinbaseinternational.py +428 -88
- ccxt/async_support/coincatch.py +5152 -0
- ccxt/async_support/coincheck.py +121 -38
- ccxt/async_support/coinex.py +4020 -3339
- ccxt/async_support/coinlist.py +273 -116
- ccxt/async_support/coinmate.py +204 -97
- ccxt/async_support/coinmetro.py +203 -110
- ccxt/async_support/coinone.py +142 -68
- ccxt/async_support/coinsph.py +206 -89
- ccxt/async_support/coinspot.py +137 -62
- ccxt/async_support/cryptocom.py +515 -185
- ccxt/async_support/currencycom.py +203 -85
- ccxt/async_support/defx.py +2066 -0
- ccxt/async_support/delta.py +467 -158
- ccxt/async_support/deribit.py +558 -324
- ccxt/async_support/digifinex.py +340 -223
- ccxt/async_support/ellipx.py +1826 -0
- ccxt/async_support/exmo.py +259 -128
- ccxt/async_support/gate.py +1473 -464
- ccxt/async_support/gemini.py +206 -84
- ccxt/async_support/hashkey.py +4164 -0
- ccxt/async_support/hitbtc.py +334 -178
- ccxt/async_support/hollaex.py +134 -83
- ccxt/async_support/htx.py +1095 -563
- ccxt/async_support/huobijp.py +105 -56
- ccxt/async_support/hyperliquid.py +1634 -269
- ccxt/async_support/idex.py +148 -95
- ccxt/async_support/independentreserve.py +236 -31
- ccxt/async_support/indodax.py +165 -62
- ccxt/async_support/kraken.py +871 -354
- ccxt/async_support/krakenfutures.py +324 -100
- ccxt/async_support/kucoin.py +1050 -355
- ccxt/async_support/kucoinfutures.py +1004 -149
- ccxt/async_support/kuna.py +138 -106
- ccxt/async_support/latoken.py +135 -79
- ccxt/async_support/lbank.py +290 -113
- ccxt/async_support/luno.py +112 -62
- ccxt/async_support/lykke.py +104 -55
- ccxt/async_support/mercado.py +36 -29
- ccxt/async_support/mexc.py +995 -429
- ccxt/async_support/myokx.py +43 -0
- ccxt/async_support/ndax.py +163 -82
- ccxt/async_support/novadax.py +121 -75
- ccxt/async_support/oceanex.py +175 -59
- ccxt/async_support/okcoin.py +222 -163
- ccxt/async_support/okx.py +1777 -455
- ccxt/async_support/onetrading.py +132 -414
- ccxt/async_support/oxfun.py +2832 -0
- ccxt/async_support/p2b.py +79 -51
- ccxt/async_support/paradex.py +2017 -0
- ccxt/async_support/paymium.py +56 -32
- ccxt/async_support/phemex.py +572 -196
- ccxt/async_support/poloniex.py +218 -95
- ccxt/async_support/poloniexfutures.py +260 -92
- ccxt/async_support/probit.py +143 -110
- ccxt/async_support/timex.py +123 -70
- ccxt/async_support/tokocrypto.py +129 -93
- ccxt/async_support/tradeogre.py +39 -25
- ccxt/async_support/upbit.py +322 -113
- ccxt/async_support/vertex.py +2983 -0
- ccxt/async_support/wavesexchange.py +227 -173
- ccxt/async_support/wazirx.py +145 -65
- ccxt/async_support/whitebit.py +533 -138
- ccxt/async_support/woo.py +1155 -295
- ccxt/async_support/woofipro.py +2716 -0
- ccxt/async_support/xt.py +4628 -0
- ccxt/async_support/yobit.py +160 -92
- ccxt/async_support/zaif.py +80 -33
- ccxt/async_support/zonda.py +140 -69
- ccxt/base/errors.py +51 -20
- ccxt/base/exchange.py +1729 -482
- ccxt/base/precise.py +10 -0
- ccxt/base/types.py +223 -4
- ccxt/bequant.py +1 -1
- ccxt/bigone.py +329 -202
- ccxt/binance.py +3513 -1511
- ccxt/binancecoinm.py +2 -1
- ccxt/binanceus.py +12 -1
- ccxt/binanceusdm.py +3 -1
- ccxt/bingx.py +3105 -881
- ccxt/bit2c.py +119 -38
- ccxt/bitbank.py +215 -76
- ccxt/bitbns.py +124 -53
- ccxt/bitfinex.py +3235 -1078
- ccxt/bitfinex1.py +1710 -0
- ccxt/bitflyer.py +239 -50
- ccxt/bitget.py +1513 -563
- ccxt/bithumb.py +200 -67
- ccxt/bitmart.py +1320 -435
- ccxt/bitmex.py +308 -111
- ccxt/bitopro.py +256 -96
- ccxt/bitrue.py +365 -233
- ccxt/bitso.py +201 -89
- ccxt/bitstamp.py +438 -269
- ccxt/bitteam.py +179 -73
- ccxt/bitvavo.py +180 -70
- ccxt/bl3p.py +92 -25
- ccxt/blockchaincom.py +193 -79
- ccxt/blofin.py +403 -150
- ccxt/btcalpha.py +161 -55
- ccxt/btcbox.py +250 -34
- ccxt/btcmarkets.py +232 -85
- ccxt/btcturk.py +159 -60
- ccxt/bybit.py +2326 -1255
- ccxt/cex.py +1408 -1329
- ccxt/coinbase.py +1455 -288
- ccxt/coinbaseadvanced.py +17 -0
- ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/coinbaseinternational.py +428 -88
- ccxt/coincatch.py +5152 -0
- ccxt/coincheck.py +121 -38
- ccxt/coinex.py +4020 -3339
- ccxt/coinlist.py +273 -116
- ccxt/coinmate.py +204 -97
- ccxt/coinmetro.py +203 -110
- ccxt/coinone.py +142 -68
- ccxt/coinsph.py +206 -89
- ccxt/coinspot.py +137 -62
- ccxt/cryptocom.py +515 -185
- ccxt/currencycom.py +203 -85
- ccxt/defx.py +2065 -0
- ccxt/delta.py +467 -158
- ccxt/deribit.py +558 -324
- ccxt/digifinex.py +340 -223
- ccxt/ellipx.py +1826 -0
- ccxt/exmo.py +259 -128
- ccxt/gate.py +1473 -464
- ccxt/gemini.py +206 -84
- ccxt/hashkey.py +4164 -0
- ccxt/hitbtc.py +334 -178
- ccxt/hollaex.py +134 -83
- ccxt/htx.py +1095 -563
- ccxt/huobijp.py +105 -56
- ccxt/hyperliquid.py +1633 -269
- ccxt/idex.py +148 -95
- ccxt/independentreserve.py +235 -31
- ccxt/indodax.py +165 -62
- ccxt/kraken.py +871 -354
- ccxt/krakenfutures.py +324 -100
- ccxt/kucoin.py +1050 -355
- ccxt/kucoinfutures.py +1004 -149
- ccxt/kuna.py +138 -106
- ccxt/latoken.py +135 -79
- ccxt/lbank.py +290 -113
- ccxt/luno.py +112 -62
- ccxt/lykke.py +104 -55
- ccxt/mercado.py +36 -29
- ccxt/mexc.py +994 -429
- ccxt/myokx.py +43 -0
- ccxt/ndax.py +163 -82
- ccxt/novadax.py +121 -75
- ccxt/oceanex.py +175 -59
- ccxt/okcoin.py +222 -163
- ccxt/okx.py +1777 -455
- ccxt/onetrading.py +132 -414
- ccxt/oxfun.py +2831 -0
- ccxt/p2b.py +79 -51
- ccxt/paradex.py +2017 -0
- ccxt/paymium.py +56 -32
- ccxt/phemex.py +572 -196
- ccxt/poloniex.py +218 -95
- ccxt/poloniexfutures.py +260 -92
- ccxt/pro/__init__.py +29 -5
- ccxt/pro/alpaca.py +32 -17
- ccxt/pro/ascendex.py +63 -15
- ccxt/pro/bequant.py +4 -0
- ccxt/pro/binance.py +1596 -329
- ccxt/pro/binancecoinm.py +1 -0
- ccxt/pro/binanceus.py +2 -9
- ccxt/pro/binanceusdm.py +2 -0
- ccxt/pro/bingx.py +527 -134
- ccxt/pro/bitcoincom.py +4 -1
- ccxt/pro/bitfinex.py +731 -266
- ccxt/pro/bitfinex1.py +635 -0
- ccxt/pro/bitget.py +726 -357
- ccxt/pro/bithumb.py +380 -0
- ccxt/pro/bitmart.py +138 -39
- ccxt/pro/bitmex.py +199 -40
- ccxt/pro/bitopro.py +25 -13
- ccxt/pro/bitrue.py +31 -32
- ccxt/pro/bitstamp.py +7 -6
- ccxt/pro/bitvavo.py +204 -82
- ccxt/pro/blockchaincom.py +30 -17
- ccxt/pro/blofin.py +692 -0
- ccxt/pro/bybit.py +791 -82
- ccxt/pro/cex.py +99 -51
- ccxt/pro/coinbase.py +220 -30
- ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
- ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
- ccxt/pro/coinbaseinternational.py +193 -30
- ccxt/pro/coincatch.py +1464 -0
- ccxt/pro/coincheck.py +11 -6
- ccxt/pro/coinex.py +967 -661
- ccxt/pro/coinone.py +17 -10
- ccxt/pro/cryptocom.py +446 -66
- ccxt/pro/currencycom.py +11 -10
- ccxt/pro/defx.py +832 -0
- ccxt/pro/deribit.py +168 -32
- ccxt/pro/exmo.py +253 -21
- ccxt/pro/gate.py +729 -64
- ccxt/pro/gemini.py +44 -26
- ccxt/pro/hashkey.py +802 -0
- ccxt/pro/hitbtc.py +208 -103
- ccxt/pro/hollaex.py +25 -9
- ccxt/pro/htx.py +83 -39
- ccxt/pro/huobijp.py +17 -16
- ccxt/pro/hyperliquid.py +502 -31
- ccxt/pro/idex.py +28 -13
- ccxt/pro/independentreserve.py +21 -16
- ccxt/pro/kraken.py +298 -51
- ccxt/pro/krakenfutures.py +166 -75
- ccxt/pro/kucoin.py +395 -77
- ccxt/pro/kucoinfutures.py +400 -99
- ccxt/pro/lbank.py +52 -31
- ccxt/pro/luno.py +12 -10
- ccxt/pro/mexc.py +400 -50
- ccxt/pro/myokx.py +28 -0
- ccxt/pro/ndax.py +25 -12
- ccxt/pro/okcoin.py +28 -9
- ccxt/pro/okx.py +935 -124
- ccxt/pro/onetrading.py +41 -24
- ccxt/pro/oxfun.py +1054 -0
- ccxt/pro/p2b.py +100 -24
- ccxt/pro/paradex.py +352 -0
- ccxt/pro/phemex.py +93 -34
- ccxt/pro/poloniex.py +129 -50
- ccxt/pro/poloniexfutures.py +53 -32
- ccxt/pro/probit.py +93 -86
- ccxt/pro/upbit.py +401 -8
- ccxt/pro/vertex.py +943 -0
- ccxt/pro/wazirx.py +46 -28
- ccxt/pro/whitebit.py +65 -12
- ccxt/pro/woo.py +486 -70
- ccxt/pro/woofipro.py +1271 -0
- ccxt/pro/xt.py +1067 -0
- ccxt/probit.py +143 -110
- ccxt/static_dependencies/__init__.py +1 -1
- ccxt/static_dependencies/lark/__init__.py +38 -0
- ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- ccxt/static_dependencies/lark/ast_utils.py +59 -0
- ccxt/static_dependencies/lark/common.py +86 -0
- ccxt/static_dependencies/lark/exceptions.py +292 -0
- ccxt/static_dependencies/lark/grammar.py +130 -0
- ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- ccxt/static_dependencies/lark/indenter.py +143 -0
- ccxt/static_dependencies/lark/lark.py +658 -0
- ccxt/static_dependencies/lark/lexer.py +678 -0
- ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- ccxt/static_dependencies/lark/py.typed +0 -0
- ccxt/static_dependencies/lark/reconstruct.py +107 -0
- ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- ccxt/static_dependencies/lark/tree.py +267 -0
- ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- ccxt/static_dependencies/lark/tree_templates.py +180 -0
- ccxt/static_dependencies/lark/utils.py +343 -0
- ccxt/static_dependencies/lark/visitors.py +596 -0
- ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- ccxt/static_dependencies/marshmallow/base.py +65 -0
- ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- ccxt/static_dependencies/marshmallow/py.typed +0 -0
- ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- ccxt/static_dependencies/marshmallow/types.py +12 -0
- ccxt/static_dependencies/marshmallow/utils.py +378 -0
- ccxt/static_dependencies/marshmallow/validate.py +678 -0
- ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- ccxt/static_dependencies/starknet/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- ccxt/static_dependencies/starknet/common.py +15 -0
- ccxt/static_dependencies/starknet/constants.py +39 -0
- ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- ccxt/static_dependencies/starknet/hash/address.py +79 -0
- ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- ccxt/static_dependencies/starkware/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- ccxt/static_dependencies/sympy/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/test/{test_async.py → tests_async.py} +465 -407
- ccxt/test/tests_helpers.py +285 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/{test_sync.py → tests_sync.py} +465 -409
- ccxt/timex.py +123 -70
- ccxt/tokocrypto.py +129 -93
- ccxt/tradeogre.py +39 -25
- ccxt/upbit.py +322 -113
- ccxt/vertex.py +2983 -0
- ccxt/wavesexchange.py +227 -173
- ccxt/wazirx.py +145 -65
- ccxt/whitebit.py +533 -138
- ccxt/woo.py +1155 -295
- ccxt/woofipro.py +2716 -0
- ccxt/xt.py +4627 -0
- ccxt/yobit.py +159 -92
- ccxt/zaif.py +80 -33
- ccxt/zonda.py +140 -69
- ccxt-4.4.48.dist-info/LICENSE.txt +21 -0
- ccxt-4.4.48.dist-info/METADATA +646 -0
- ccxt-4.4.48.dist-info/RECORD +669 -0
- {ccxt-4.2.76.dist-info → ccxt-4.4.48.dist-info}/WHEEL +1 -1
- ccxt/abstract/bitbay.py +0 -47
- ccxt/abstract/bitfinex2.py +0 -139
- ccxt/abstract/hitbtc3.py +0 -115
- ccxt/async_support/bitbay.py +0 -17
- ccxt/async_support/bitfinex2.py +0 -3496
- ccxt/async_support/flowbtc.py +0 -34
- ccxt/bitbay.py +0 -17
- ccxt/bitfinex2.py +0 -3496
- ccxt/flowbtc.py +0 -34
- ccxt/hitbtc3.py +0 -16
- ccxt/pro/bitfinex2.py +0 -1081
- ccxt/test/base/__init__.py +0 -28
- 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 -103
- 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 -32
- 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_margin_mode.py +0 -24
- ccxt/test/base/test_margin_modification.py +0 -35
- ccxt/test/base/test_market.py +0 -190
- ccxt/test/base/test_number.py +0 -411
- ccxt/test/base/test_ohlcv.py +0 -32
- 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 -63
- ccxt/test/base/test_position.py +0 -60
- ccxt/test/base/test_shared_methods.py +0 -345
- ccxt/test/base/test_status.py +0 -24
- ccxt/test/base/test_throttle.py +0 -126
- ccxt/test/base/test_ticker.py +0 -86
- 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-4.2.76.dist-info/METADATA +0 -626
- ccxt-4.2.76.dist-info/RECORD +0 -534
- {ccxt-4.2.76.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
ccxt/async_support/xt.py
ADDED
@@ -0,0 +1,4628 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
4
|
+
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
5
|
+
|
6
|
+
from ccxt.async_support.base.exchange import Exchange
|
7
|
+
from ccxt.abstract.xt import ImplicitAPI
|
8
|
+
import asyncio
|
9
|
+
import hashlib
|
10
|
+
from ccxt.base.types import Currencies, Currency, DepositAddress, Int, LedgerEntry, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderSide, OrderType, Str, Tickers, FundingRate, Transaction, TransferEntry
|
11
|
+
from typing import List
|
12
|
+
from ccxt.base.errors import ExchangeError
|
13
|
+
from ccxt.base.errors import AuthenticationError
|
14
|
+
from ccxt.base.errors import PermissionDenied
|
15
|
+
from ccxt.base.errors import ArgumentsRequired
|
16
|
+
from ccxt.base.errors import BadRequest
|
17
|
+
from ccxt.base.errors import BadSymbol
|
18
|
+
from ccxt.base.errors import InsufficientFunds
|
19
|
+
from ccxt.base.errors import InvalidOrder
|
20
|
+
from ccxt.base.errors import NotSupported
|
21
|
+
from ccxt.base.errors import NetworkError
|
22
|
+
from ccxt.base.errors import RateLimitExceeded
|
23
|
+
from ccxt.base.errors import OnMaintenance
|
24
|
+
from ccxt.base.errors import RequestTimeout
|
25
|
+
from ccxt.base.decimal_to_precision import TICK_SIZE
|
26
|
+
from ccxt.base.precise import Precise
|
27
|
+
|
28
|
+
|
29
|
+
class xt(Exchange, ImplicitAPI):
|
30
|
+
|
31
|
+
def describe(self):
|
32
|
+
return self.deep_extend(super(xt, self).describe(), {
|
33
|
+
'id': 'xt',
|
34
|
+
'name': 'XT',
|
35
|
+
'countries': ['SC'], # Seychelles
|
36
|
+
# spot api ratelimits are None, 10/s/ip, 50/s/ip, 100/s/ip or 200/s/ip
|
37
|
+
# futures 3 requests per second => 1000ms / (100 * 3.33) = 3.003(get assets -> fetchMarkets & fetchCurrencies)
|
38
|
+
# futures 10 requests per second => 1000ms / (100 * 1) = 10(all other)
|
39
|
+
# futures 1000 times per minute for each single IP -> Otherwise account locked for 10min
|
40
|
+
'rateLimit': 100,
|
41
|
+
'version': 'v4',
|
42
|
+
'certified': False,
|
43
|
+
'pro': True,
|
44
|
+
'has': {
|
45
|
+
'CORS': False,
|
46
|
+
'spot': True,
|
47
|
+
'margin': True,
|
48
|
+
'swap': True,
|
49
|
+
'future': True,
|
50
|
+
'option': False,
|
51
|
+
'addMargin': True,
|
52
|
+
'borrowMargin': False,
|
53
|
+
'cancelAllOrders': True,
|
54
|
+
'cancelOrder': True,
|
55
|
+
'cancelOrders': True,
|
56
|
+
'createDepositAddress': False,
|
57
|
+
'createMarketBuyOrderWithCost': True,
|
58
|
+
'createMarketSellOrderWithCost': False,
|
59
|
+
'createOrder': True,
|
60
|
+
'createPostOnlyOrder': False,
|
61
|
+
'createReduceOnlyOrder': True,
|
62
|
+
'editOrder': False,
|
63
|
+
'fetchAccounts': False,
|
64
|
+
'fetchBalance': True,
|
65
|
+
'fetchBidsAsks': True,
|
66
|
+
'fetchBorrowInterest': False,
|
67
|
+
'fetchBorrowRate': False,
|
68
|
+
'fetchBorrowRateHistories': False,
|
69
|
+
'fetchBorrowRateHistory': False,
|
70
|
+
'fetchBorrowRatesPerSymbol': False,
|
71
|
+
'fetchCanceledOrders': True,
|
72
|
+
'fetchClosedOrders': True,
|
73
|
+
'fetchCurrencies': True,
|
74
|
+
'fetchDeposit': False,
|
75
|
+
'fetchDepositAddress': True,
|
76
|
+
'fetchDepositAddresses': False,
|
77
|
+
'fetchDepositAddressesByNetwork': False,
|
78
|
+
'fetchDeposits': True,
|
79
|
+
'fetchDepositWithdrawals': False,
|
80
|
+
'fetchDepositWithdrawFee': False,
|
81
|
+
'fetchDepositWithdrawFees': False,
|
82
|
+
'fetchFundingHistory': True,
|
83
|
+
'fetchFundingInterval': True,
|
84
|
+
'fetchFundingIntervals': False,
|
85
|
+
'fetchFundingRate': True,
|
86
|
+
'fetchFundingRateHistory': True,
|
87
|
+
'fetchFundingRates': False,
|
88
|
+
'fetchIndexOHLCV': False,
|
89
|
+
'fetchL3OrderBook': False,
|
90
|
+
'fetchLedger': True,
|
91
|
+
'fetchLedgerEntry': False,
|
92
|
+
'fetchLeverage': False,
|
93
|
+
'fetchLeverageTiers': True,
|
94
|
+
'fetchMarketLeverageTiers': True,
|
95
|
+
'fetchMarkets': True,
|
96
|
+
'fetchMarkOHLCV': False,
|
97
|
+
'fetchMyTrades': True,
|
98
|
+
'fetchOHLCV': True,
|
99
|
+
'fetchOpenInterest': False,
|
100
|
+
'fetchOpenInterestHistory': False,
|
101
|
+
'fetchOpenOrders': True,
|
102
|
+
'fetchOrder': True,
|
103
|
+
'fetchOrderBook': True,
|
104
|
+
'fetchOrderBooks': False,
|
105
|
+
'fetchOrders': True,
|
106
|
+
'fetchOrdersByStatus': True,
|
107
|
+
'fetchOrderTrades': False,
|
108
|
+
'fetchPosition': True,
|
109
|
+
'fetchPositions': True,
|
110
|
+
'fetchPremiumIndexOHLCV': False,
|
111
|
+
'fetchSettlementHistory': False,
|
112
|
+
'fetchStatus': False,
|
113
|
+
'fetchTicker': True,
|
114
|
+
'fetchTickers': True,
|
115
|
+
'fetchTime': True,
|
116
|
+
'fetchTrades': True,
|
117
|
+
'fetchTradingFee': False,
|
118
|
+
'fetchTradingFees': False,
|
119
|
+
'fetchTradingLimits': False,
|
120
|
+
'fetchTransactionFee': False,
|
121
|
+
'fetchTransactionFees': False,
|
122
|
+
'fetchTransactions': False,
|
123
|
+
'fetchTransfer': False,
|
124
|
+
'fetchTransfers': False,
|
125
|
+
'fetchWithdrawal': False,
|
126
|
+
'fetchWithdrawals': True,
|
127
|
+
'fetchWithdrawalWhitelist': False,
|
128
|
+
'reduceMargin': True,
|
129
|
+
'repayMargin': False,
|
130
|
+
'setLeverage': True,
|
131
|
+
'setMargin': False,
|
132
|
+
'setMarginMode': False,
|
133
|
+
'setPositionMode': False,
|
134
|
+
'signIn': False,
|
135
|
+
'transfer': True,
|
136
|
+
'withdraw': True,
|
137
|
+
},
|
138
|
+
'precisionMode': TICK_SIZE,
|
139
|
+
'urls': {
|
140
|
+
'logo': 'https://user-images.githubusercontent.com/14319357/232636712-466df2fc-560a-4ca4-aab2-b1d954a58e24.jpg',
|
141
|
+
'api': {
|
142
|
+
'spot': 'https://sapi.xt.com',
|
143
|
+
'linear': 'https://fapi.xt.com',
|
144
|
+
'inverse': 'https://dapi.xt.com',
|
145
|
+
'user': 'https://api.xt.com',
|
146
|
+
},
|
147
|
+
'www': 'https://xt.com',
|
148
|
+
'referral': 'https://www.xt.com/en/accounts/register?ref=9PTM9VW',
|
149
|
+
'doc': [
|
150
|
+
'https://doc.xt.com/',
|
151
|
+
'https://github.com/xtpub/api-doc',
|
152
|
+
],
|
153
|
+
'fees': 'https://www.xt.com/en/rate',
|
154
|
+
},
|
155
|
+
'api': {
|
156
|
+
'public': {
|
157
|
+
'spot': {
|
158
|
+
'get': {
|
159
|
+
'currencies': 1,
|
160
|
+
'depth': 10,
|
161
|
+
'kline': 1,
|
162
|
+
'symbol': 1, # 1 for a single symbol
|
163
|
+
'ticker': 1, # 1 for a single symbol
|
164
|
+
'ticker/book': 1, # 1 for a single symbol
|
165
|
+
'ticker/price': 1, # 1 for a single symbol
|
166
|
+
'ticker/24h': 1, # 1 for a single symbol
|
167
|
+
'time': 1,
|
168
|
+
'trade/history': 1,
|
169
|
+
'trade/recent': 1,
|
170
|
+
'wallet/support/currency': 1,
|
171
|
+
},
|
172
|
+
},
|
173
|
+
'linear': {
|
174
|
+
'get': {
|
175
|
+
'future/market/v1/public/contract/risk-balance': 1,
|
176
|
+
'future/market/v1/public/contract/open-interest': 1,
|
177
|
+
'future/market/v1/public/leverage/bracket/detail': 1,
|
178
|
+
'future/market/v1/public/leverage/bracket/list': 1,
|
179
|
+
'future/market/v1/public/q/agg-ticker': 1,
|
180
|
+
'future/market/v1/public/q/agg-tickers': 1,
|
181
|
+
'future/market/v1/public/q/deal': 1,
|
182
|
+
'future/market/v1/public/q/depth': 1,
|
183
|
+
'future/market/v1/public/q/funding-rate': 1,
|
184
|
+
'future/market/v1/public/q/funding-rate-record': 1,
|
185
|
+
'future/market/v1/public/q/index-price': 1,
|
186
|
+
'future/market/v1/public/q/kline': 1,
|
187
|
+
'future/market/v1/public/q/mark-price': 1,
|
188
|
+
'future/market/v1/public/q/symbol-index-price': 1,
|
189
|
+
'future/market/v1/public/q/symbol-mark-price': 1,
|
190
|
+
'future/market/v1/public/q/ticker': 1,
|
191
|
+
'future/market/v1/public/q/tickers': 1,
|
192
|
+
'future/market/v1/public/symbol/coins': 3.33,
|
193
|
+
'future/market/v1/public/symbol/detail': 3.33,
|
194
|
+
'future/market/v1/public/symbol/list': 1,
|
195
|
+
},
|
196
|
+
},
|
197
|
+
'inverse': {
|
198
|
+
'get': {
|
199
|
+
'future/market/v1/public/contract/risk-balance': 1,
|
200
|
+
'future/market/v1/public/contract/open-interest': 1,
|
201
|
+
'future/market/v1/public/leverage/bracket/detail': 1,
|
202
|
+
'future/market/v1/public/leverage/bracket/list': 1,
|
203
|
+
'future/market/v1/public/q/agg-ticker': 1,
|
204
|
+
'future/market/v1/public/q/agg-tickers': 1,
|
205
|
+
'future/market/v1/public/q/deal': 1,
|
206
|
+
'future/market/v1/public/q/depth': 1,
|
207
|
+
'future/market/v1/public/q/funding-rate': 1,
|
208
|
+
'future/market/v1/public/q/funding-rate-record': 1,
|
209
|
+
'future/market/v1/public/q/index-price': 1,
|
210
|
+
'future/market/v1/public/q/kline': 1,
|
211
|
+
'future/market/v1/public/q/mark-price': 1,
|
212
|
+
'future/market/v1/public/q/symbol-index-price': 1,
|
213
|
+
'future/market/v1/public/q/symbol-mark-price': 1,
|
214
|
+
'future/market/v1/public/q/ticker': 1,
|
215
|
+
'future/market/v1/public/q/tickers': 1,
|
216
|
+
'future/market/v1/public/symbol/coins': 3.33,
|
217
|
+
'future/market/v1/public/symbol/detail': 3.33,
|
218
|
+
'future/market/v1/public/symbol/list': 1,
|
219
|
+
},
|
220
|
+
},
|
221
|
+
},
|
222
|
+
'private': {
|
223
|
+
'spot': {
|
224
|
+
'get': {
|
225
|
+
'balance': 1,
|
226
|
+
'balances': 1,
|
227
|
+
'batch-order': 1,
|
228
|
+
'deposit/address': 1,
|
229
|
+
'deposit/history': 1,
|
230
|
+
'history-order': 1,
|
231
|
+
'open-order': 1,
|
232
|
+
'order': 1,
|
233
|
+
'order/{orderId}': 1,
|
234
|
+
'trade': 1,
|
235
|
+
'withdraw/history': 1,
|
236
|
+
},
|
237
|
+
'post': {
|
238
|
+
'order': 0.2,
|
239
|
+
'withdraw': 10,
|
240
|
+
'balance/transfer': 1,
|
241
|
+
'balance/account/transfer': 1,
|
242
|
+
'ws-token': 1,
|
243
|
+
},
|
244
|
+
'delete': {
|
245
|
+
'batch-order': 1,
|
246
|
+
'open-order': 1,
|
247
|
+
'order/{orderId}': 1,
|
248
|
+
},
|
249
|
+
},
|
250
|
+
'linear': {
|
251
|
+
'get': {
|
252
|
+
'future/trade/v1/entrust/plan-detail': 1,
|
253
|
+
'future/trade/v1/entrust/plan-list': 1,
|
254
|
+
'future/trade/v1/entrust/plan-list-history': 1,
|
255
|
+
'future/trade/v1/entrust/profit-detail': 1,
|
256
|
+
'future/trade/v1/entrust/profit-list': 1,
|
257
|
+
'future/trade/v1/order/detail': 1,
|
258
|
+
'future/trade/v1/order/list': 1,
|
259
|
+
'future/trade/v1/order/list-history': 1,
|
260
|
+
'future/trade/v1/order/trade-list': 1,
|
261
|
+
'future/user/v1/account/info': 1,
|
262
|
+
'future/user/v1/balance/bills': 1,
|
263
|
+
'future/user/v1/balance/detail': 1,
|
264
|
+
'future/user/v1/balance/funding-rate-list': 1,
|
265
|
+
'future/user/v1/balance/list': 1,
|
266
|
+
'future/user/v1/position/adl': 1,
|
267
|
+
'future/user/v1/position/list': 1,
|
268
|
+
'future/user/v1/user/collection/list': 1,
|
269
|
+
'future/user/v1/user/listen-key': 1,
|
270
|
+
},
|
271
|
+
'post': {
|
272
|
+
'future/trade/v1/entrust/cancel-all-plan': 1,
|
273
|
+
'future/trade/v1/entrust/cancel-all-profit-stop': 1,
|
274
|
+
'future/trade/v1/entrust/cancel-plan': 1,
|
275
|
+
'future/trade/v1/entrust/cancel-profit-stop': 1,
|
276
|
+
'future/trade/v1/entrust/create-plan': 1,
|
277
|
+
'future/trade/v1/entrust/create-profit': 1,
|
278
|
+
'future/trade/v1/entrust/update-profit-stop': 1,
|
279
|
+
'future/trade/v1/order/cancel': 1,
|
280
|
+
'future/trade/v1/order/cancel-all': 1,
|
281
|
+
'future/trade/v1/order/create': 1,
|
282
|
+
'future/trade/v1/order/create-batch': 1,
|
283
|
+
'future/user/v1/account/open': 1,
|
284
|
+
'future/user/v1/position/adjust-leverage': 1,
|
285
|
+
'future/user/v1/position/auto-margin': 1,
|
286
|
+
'future/user/v1/position/close-all': 1,
|
287
|
+
'future/user/v1/position/margin': 1,
|
288
|
+
'future/user/v1/user/collection/add': 1,
|
289
|
+
'future/user/v1/user/collection/cancel': 1,
|
290
|
+
},
|
291
|
+
},
|
292
|
+
'inverse': {
|
293
|
+
'get': {
|
294
|
+
'future/trade/v1/entrust/plan-detail': 1,
|
295
|
+
'future/trade/v1/entrust/plan-list': 1,
|
296
|
+
'future/trade/v1/entrust/plan-list-history': 1,
|
297
|
+
'future/trade/v1/entrust/profit-detail': 1,
|
298
|
+
'future/trade/v1/entrust/profit-list': 1,
|
299
|
+
'future/trade/v1/order/detail': 1,
|
300
|
+
'future/trade/v1/order/list': 1,
|
301
|
+
'future/trade/v1/order/list-history': 1,
|
302
|
+
'future/trade/v1/order/trade-list': 1,
|
303
|
+
'future/user/v1/account/info': 1,
|
304
|
+
'future/user/v1/balance/bills': 1,
|
305
|
+
'future/user/v1/balance/detail': 1,
|
306
|
+
'future/user/v1/balance/funding-rate-list': 1,
|
307
|
+
'future/user/v1/balance/list': 1,
|
308
|
+
'future/user/v1/position/adl': 1,
|
309
|
+
'future/user/v1/position/list': 1,
|
310
|
+
'future/user/v1/user/collection/list': 1,
|
311
|
+
'future/user/v1/user/listen-key': 1,
|
312
|
+
},
|
313
|
+
'post': {
|
314
|
+
'future/trade/v1/entrust/cancel-all-plan': 1,
|
315
|
+
'future/trade/v1/entrust/cancel-all-profit-stop': 1,
|
316
|
+
'future/trade/v1/entrust/cancel-plan': 1,
|
317
|
+
'future/trade/v1/entrust/cancel-profit-stop': 1,
|
318
|
+
'future/trade/v1/entrust/create-plan': 1,
|
319
|
+
'future/trade/v1/entrust/create-profit': 1,
|
320
|
+
'future/trade/v1/entrust/update-profit-stop': 1,
|
321
|
+
'future/trade/v1/order/cancel': 1,
|
322
|
+
'future/trade/v1/order/cancel-all': 1,
|
323
|
+
'future/trade/v1/order/create': 1,
|
324
|
+
'future/trade/v1/order/create-batch': 1,
|
325
|
+
'future/user/v1/account/open': 1,
|
326
|
+
'future/user/v1/position/adjust-leverage': 1,
|
327
|
+
'future/user/v1/position/auto-margin': 1,
|
328
|
+
'future/user/v1/position/close-all': 1,
|
329
|
+
'future/user/v1/position/margin': 1,
|
330
|
+
'future/user/v1/user/collection/add': 1,
|
331
|
+
'future/user/v1/user/collection/cancel': 1,
|
332
|
+
},
|
333
|
+
},
|
334
|
+
'user': {
|
335
|
+
'get': {
|
336
|
+
'user/account': 1,
|
337
|
+
'user/account/api-key': 1,
|
338
|
+
},
|
339
|
+
'post': {
|
340
|
+
'user/account': 1,
|
341
|
+
'user/account/api-key': 1,
|
342
|
+
},
|
343
|
+
'put': {
|
344
|
+
'user/account/api-key': 1,
|
345
|
+
},
|
346
|
+
'delete': {
|
347
|
+
'user/account/{apikeyId}': 1,
|
348
|
+
},
|
349
|
+
},
|
350
|
+
},
|
351
|
+
},
|
352
|
+
'fees': {
|
353
|
+
'spot': {
|
354
|
+
'tierBased': True,
|
355
|
+
'percentage': True,
|
356
|
+
'maker': self.parse_number('0.002'),
|
357
|
+
'taker': self.parse_number('0.002'),
|
358
|
+
'tiers': {
|
359
|
+
'maker': [
|
360
|
+
[self.parse_number('0'), self.parse_number('0.002')],
|
361
|
+
[self.parse_number('5000'), self.parse_number('0.0018')],
|
362
|
+
[self.parse_number('10000'), self.parse_number('0.0016')],
|
363
|
+
[self.parse_number('20000'), self.parse_number('0.0014')],
|
364
|
+
[self.parse_number('50000'), self.parse_number('0.0012')],
|
365
|
+
[self.parse_number('150000'), self.parse_number('0.0010')],
|
366
|
+
[self.parse_number('300000'), self.parse_number('0.0008')],
|
367
|
+
[self.parse_number('600000'), self.parse_number('0.0007')],
|
368
|
+
[self.parse_number('1200000'), self.parse_number('0.0006')],
|
369
|
+
[self.parse_number('2500000'), self.parse_number('0.0005')],
|
370
|
+
[self.parse_number('6000000'), self.parse_number('0.0004')],
|
371
|
+
[self.parse_number('15000000'), self.parse_number('0.0003')],
|
372
|
+
[self.parse_number('30000000'), self.parse_number('0.0002')],
|
373
|
+
],
|
374
|
+
'taker': [
|
375
|
+
[self.parse_number('0'), self.parse_number('0.002')],
|
376
|
+
[self.parse_number('5000'), self.parse_number('0.0018')],
|
377
|
+
[self.parse_number('10000'), self.parse_number('0.0016')],
|
378
|
+
[self.parse_number('20000'), self.parse_number('0.0014')],
|
379
|
+
[self.parse_number('50000'), self.parse_number('0.0012')],
|
380
|
+
[self.parse_number('150000'), self.parse_number('0.0010')],
|
381
|
+
[self.parse_number('300000'), self.parse_number('0.0008')],
|
382
|
+
[self.parse_number('600000'), self.parse_number('0.0007')],
|
383
|
+
[self.parse_number('1200000'), self.parse_number('0.0006')],
|
384
|
+
[self.parse_number('2500000'), self.parse_number('0.0005')],
|
385
|
+
[self.parse_number('6000000'), self.parse_number('0.0004')],
|
386
|
+
[self.parse_number('15000000'), self.parse_number('0.0003')],
|
387
|
+
[self.parse_number('30000000'), self.parse_number('0.0002')],
|
388
|
+
],
|
389
|
+
},
|
390
|
+
},
|
391
|
+
'contract': {
|
392
|
+
'tierBased': True,
|
393
|
+
'percentage': True,
|
394
|
+
'maker': self.parse_number('0.0004'),
|
395
|
+
'taker': self.parse_number('0.0006'),
|
396
|
+
'tiers': {
|
397
|
+
'maker': [
|
398
|
+
[self.parse_number('0'), self.parse_number('0.0004')],
|
399
|
+
[self.parse_number('200000'), self.parse_number('0.00038')],
|
400
|
+
[self.parse_number('1000000'), self.parse_number('0.00036')],
|
401
|
+
[self.parse_number('5000000'), self.parse_number('0.00034')],
|
402
|
+
[self.parse_number('10000000'), self.parse_number('0.00032')],
|
403
|
+
[self.parse_number('15000000'), self.parse_number('0.00028')],
|
404
|
+
[self.parse_number('30000000'), self.parse_number('0.00024')],
|
405
|
+
[self.parse_number('50000000'), self.parse_number('0.0002')],
|
406
|
+
[self.parse_number('100000000'), self.parse_number('0.00016')],
|
407
|
+
[self.parse_number('300000000'), self.parse_number('0.00012')],
|
408
|
+
[self.parse_number('500000000'), self.parse_number('0.00008')],
|
409
|
+
],
|
410
|
+
'taker': [
|
411
|
+
[self.parse_number('0'), self.parse_number('0.0006')],
|
412
|
+
[self.parse_number('200000'), self.parse_number('0.000588')],
|
413
|
+
[self.parse_number('1000000'), self.parse_number('0.00057')],
|
414
|
+
[self.parse_number('5000000'), self.parse_number('0.00054')],
|
415
|
+
[self.parse_number('10000000'), self.parse_number('0.00051')],
|
416
|
+
[self.parse_number('15000000'), self.parse_number('0.00048')],
|
417
|
+
[self.parse_number('30000000'), self.parse_number('0.00045')],
|
418
|
+
[self.parse_number('50000000'), self.parse_number('0.00045')],
|
419
|
+
[self.parse_number('100000000'), self.parse_number('0.00036')],
|
420
|
+
[self.parse_number('300000000'), self.parse_number('0.00033')],
|
421
|
+
[self.parse_number('500000000'), self.parse_number('0.0003')],
|
422
|
+
],
|
423
|
+
},
|
424
|
+
},
|
425
|
+
},
|
426
|
+
'exceptions': {
|
427
|
+
'exact': {
|
428
|
+
'400': NetworkError, # {"returnCode":1,"msgInfo":"failure","error":{"code":"400","msg":"Connection refused: /10.0.26.71:8080"},"result":null}
|
429
|
+
'404': ExchangeError, # interface does not exist
|
430
|
+
'429': RateLimitExceeded, # The request is too frequent, please control the request rate according to the speed limit requirement
|
431
|
+
'500': ExchangeError, # Service exception
|
432
|
+
'502': ExchangeError, # Gateway exception
|
433
|
+
'503': OnMaintenance, # Service unavailable, please try again later
|
434
|
+
'AUTH_001': AuthenticationError, # missing request header xt-validate-appkey
|
435
|
+
'AUTH_002': AuthenticationError, # missing request header xt-validate-timestamp
|
436
|
+
'AUTH_003': AuthenticationError, # missing request header xt-validate-recvwindow
|
437
|
+
'AUTH_004': AuthenticationError, # bad request header xt-validate-recvwindow
|
438
|
+
'AUTH_005': AuthenticationError, # missing request header xt-validate-algorithms
|
439
|
+
'AUTH_006': AuthenticationError, # bad request header xt-validate-algorithms
|
440
|
+
'AUTH_007': AuthenticationError, # missing request header xt-validate-signature
|
441
|
+
'AUTH_101': AuthenticationError, # ApiKey does not exist
|
442
|
+
'AUTH_102': AuthenticationError, # ApiKey is not activated
|
443
|
+
'AUTH_103': AuthenticationError, # Signature error, {"rc":1,"mc":"AUTH_103","ma":[],"result":null}
|
444
|
+
'AUTH_104': AuthenticationError, # Unbound IP request
|
445
|
+
'AUTH_105': AuthenticationError, # outdated message
|
446
|
+
'AUTH_106': PermissionDenied, # Exceeded apikey permission
|
447
|
+
'SYMBOL_001': BadSymbol, # Symbol not exist
|
448
|
+
'SYMBOL_002': BadSymbol, # Symbol offline
|
449
|
+
'SYMBOL_003': BadSymbol, # Symbol suspend trading
|
450
|
+
'SYMBOL_004': BadSymbol, # Symbol country disallow trading
|
451
|
+
'SYMBOL_005': BadSymbol, # The symbol does not support trading via API
|
452
|
+
'ORDER_001': InvalidOrder, # Platform rejection
|
453
|
+
'ORDER_002': InsufficientFunds, # insufficient funds
|
454
|
+
'ORDER_003': InvalidOrder, # Trading Pair Suspended
|
455
|
+
'ORDER_004': InvalidOrder, # no transaction
|
456
|
+
'ORDER_005': InvalidOrder, # Order not exist
|
457
|
+
'ORDER_006': InvalidOrder, # Too many open orders
|
458
|
+
'ORDER_007': PermissionDenied, # The sub-account has no transaction authority
|
459
|
+
'ORDER_F0101': InvalidOrder, # Trigger Price Filter - Min
|
460
|
+
'ORDER_F0102': InvalidOrder, # Trigger Price Filter - Max
|
461
|
+
'ORDER_F0103': InvalidOrder, # Trigger Price Filter - Step Value
|
462
|
+
'ORDER_F0201': InvalidOrder, # Trigger Quantity Filter - Min
|
463
|
+
'ORDER_F0202': InvalidOrder, # Trigger Quantity Filter - Max
|
464
|
+
'ORDER_F0203': InvalidOrder, # Trigger Quantity Filter - Step Value
|
465
|
+
'ORDER_F0301': InvalidOrder, # Trigger QUOTE_QTY Filter - Min Value
|
466
|
+
'ORDER_F0401': InvalidOrder, # Trigger PROTECTION_ONLINE Filter
|
467
|
+
'ORDER_F0501': InvalidOrder, # Trigger PROTECTION_LIMIT Filter - Buy Max Deviation
|
468
|
+
'ORDER_F0502': InvalidOrder, # Trigger PROTECTION_LIMIT Filter - Sell Max Deviation
|
469
|
+
'ORDER_F0601': InvalidOrder, # Trigger PROTECTION_MARKET Filter
|
470
|
+
'COMMON_001': ExchangeError, # The user does not exist
|
471
|
+
'COMMON_002': ExchangeError, # System busy, please try it later
|
472
|
+
'COMMON_003': BadRequest, # Operation failed, please try it later
|
473
|
+
'CURRENCY_001': BadRequest, # Information of currency is abnormal
|
474
|
+
'DEPOSIT_001': BadRequest, # Deposit is not open
|
475
|
+
'DEPOSIT_002': PermissionDenied, # The current account security level is low, please bind any two security verifications in mobile phone/email/Google Authenticator before deposit
|
476
|
+
'DEPOSIT_003': BadRequest, # The format of address is incorrect, please enter again
|
477
|
+
'DEPOSIT_004': BadRequest, # The address is already exists, please enter again
|
478
|
+
'DEPOSIT_005': BadRequest, # Can not find the address of offline wallet
|
479
|
+
'DEPOSIT_006': BadRequest, # No deposit address, please try it later
|
480
|
+
'DEPOSIT_007': BadRequest, # Address is being generated, please try it later
|
481
|
+
'DEPOSIT_008': BadRequest, # Deposit is not available
|
482
|
+
'WITHDRAW_001': BadRequest, # Withdraw is not open
|
483
|
+
'WITHDRAW_002': BadRequest, # The withdrawal address is invalid
|
484
|
+
'WITHDRAW_003': PermissionDenied, # The current account security level is low, please bind any two security verifications in mobile phone/email/Google Authenticator before withdraw
|
485
|
+
'WITHDRAW_004': BadRequest, # The withdrawal address is not added
|
486
|
+
'WITHDRAW_005': BadRequest, # The withdrawal address cannot be empty
|
487
|
+
'WITHDRAW_006': BadRequest, # Memo cannot be empty
|
488
|
+
'WITHDRAW_008': PermissionDenied, # Risk control is triggered, withdraw of self currency is not currently supported
|
489
|
+
'WITHDRAW_009': PermissionDenied, # Withdraw failed, some hasattr(self, assets) withdraw are restricted by T+1 withdraw
|
490
|
+
'WITHDRAW_010': BadRequest, # The precision of withdrawal is invalid
|
491
|
+
'WITHDRAW_011': InsufficientFunds, # free balance is not enough
|
492
|
+
'WITHDRAW_012': PermissionDenied, # Withdraw failed, your remaining withdrawal limit today is not enough
|
493
|
+
'WITHDRAW_013': PermissionDenied, # Withdraw failed, your remaining withdrawal limit today is not enough, the withdrawal amount can be increased by completing a higher level of real-name authentication
|
494
|
+
'WITHDRAW_014': BadRequest, # This withdrawal address cannot be used in the internal transfer function, please cancel the internal transfer function before submitting
|
495
|
+
'WITHDRAW_015': BadRequest, # The withdrawal amount is not enough to deduct the handling fee
|
496
|
+
'WITHDRAW_016': BadRequest, # This withdrawal address is already exists
|
497
|
+
'WITHDRAW_017': BadRequest, # This withdrawal has been processed and cannot be canceled
|
498
|
+
'WITHDRAW_018': BadRequest, # Memo must be a number
|
499
|
+
'WITHDRAW_019': BadRequest, # Memo is incorrect, please enter again
|
500
|
+
'WITHDRAW_020': PermissionDenied, # Your withdrawal amount has reached the upper limit for today, please try it tomorrow
|
501
|
+
'WITHDRAW_021': PermissionDenied, # Your withdrawal amount has reached the upper limit for today, you can only withdraw up to {0} self time
|
502
|
+
'WITHDRAW_022': BadRequest, # Withdrawal amount must be greater than {0}
|
503
|
+
'WITHDRAW_023': BadRequest, # Withdrawal amount must be less than {0}
|
504
|
+
'WITHDRAW_024': BadRequest, # Withdraw is not supported
|
505
|
+
'WITHDRAW_025': BadRequest, # Please create a FIO address in the deposit page
|
506
|
+
'FUND_001': BadRequest, # Duplicate request(a bizId can only be requested once)
|
507
|
+
'FUND_002': InsufficientFunds, # Insufficient account balance
|
508
|
+
'FUND_003': BadRequest, # Transfer operations are not supported(for example, sub-accounts do not support financial transfers)
|
509
|
+
'FUND_004': ExchangeError, # Unfreeze failed
|
510
|
+
'FUND_005': PermissionDenied, # Transfer prohibited
|
511
|
+
'FUND_014': BadRequest, # The transfer-in account id and transfer-out account ID cannot be the same
|
512
|
+
'FUND_015': BadRequest, # From and to business types cannot be the same
|
513
|
+
'FUND_016': BadRequest, # Leverage transfer, symbol cannot be empty
|
514
|
+
'FUND_017': BadRequest, # Parameter error
|
515
|
+
'FUND_018': BadRequest, # Invalid freeze record
|
516
|
+
'FUND_019': BadRequest, # Freeze users not equal
|
517
|
+
'FUND_020': BadRequest, # Freeze currency are not equal
|
518
|
+
'FUND_021': BadRequest, # Operation not supported
|
519
|
+
'FUND_022': BadRequest, # Freeze record does not exist
|
520
|
+
'FUND_044': BadRequest, # The maximum length of the amount is 113 and cannot exceed the limit
|
521
|
+
'TRANSFER_001': BadRequest, # Duplicate request(a bizId can only be requested once)
|
522
|
+
'TRANSFER_002': InsufficientFunds, # Insufficient account balance
|
523
|
+
'TRANSFER_003': BadRequest, # User not registered
|
524
|
+
'TRANSFER_004': PermissionDenied, # The currency is not allowed to be transferred
|
525
|
+
'TRANSFER_005': PermissionDenied, # The user’s currency is not allowed to be transferred
|
526
|
+
'TRANSFER_006': PermissionDenied, # Transfer prohibited
|
527
|
+
'TRANSFER_007': RequestTimeout, # Request timed out
|
528
|
+
'TRANSFER_008': BadRequest, # Transferring to a leveraged account is abnormal
|
529
|
+
'TRANSFER_009': BadRequest, # Departing from a leveraged account is abnormal
|
530
|
+
'TRANSFER_010': PermissionDenied, # Leverage cleared, transfer prohibited
|
531
|
+
'TRANSFER_011': PermissionDenied, # Leverage with borrowing, transfer prohibited
|
532
|
+
'TRANSFER_012': PermissionDenied, # Currency transfer prohibited
|
533
|
+
'symbol_not_support_trading_via_api': BadSymbol, # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
|
534
|
+
'open_order_min_nominal_value_limit': InvalidOrder, # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
|
535
|
+
},
|
536
|
+
'broad': {
|
537
|
+
'The symbol does not support trading via API': BadSymbol, # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
|
538
|
+
'Exceeds the minimum notional value of a single order': InvalidOrder, # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
|
539
|
+
},
|
540
|
+
},
|
541
|
+
'timeframes': {
|
542
|
+
'1m': '1m',
|
543
|
+
'5m': '5m',
|
544
|
+
'15m': '15m',
|
545
|
+
'30m': '30m',
|
546
|
+
'1h': '1h', # spot only
|
547
|
+
'2h': '2h', # spot only
|
548
|
+
'4h': '4h',
|
549
|
+
'6h': '6h', # spot only
|
550
|
+
'8h': '8h', # spot only
|
551
|
+
'1d': '1d',
|
552
|
+
'3d': '3d', # spot only
|
553
|
+
'1w': '1w',
|
554
|
+
'1M': '1M', # spot only
|
555
|
+
},
|
556
|
+
'commonCurrencies': {},
|
557
|
+
'options': {
|
558
|
+
'adjustForTimeDifference': False,
|
559
|
+
'timeDifference': 0,
|
560
|
+
'accountsById': {
|
561
|
+
'spot': 'SPOT',
|
562
|
+
'leverage': 'LEVER',
|
563
|
+
'finance': 'FINANCE',
|
564
|
+
'swap': 'FUTURES_U',
|
565
|
+
'future': 'FUTURES_U',
|
566
|
+
'linear': 'FUTURES_U',
|
567
|
+
'inverse': 'FUTURES_C',
|
568
|
+
},
|
569
|
+
'networks': {
|
570
|
+
'ERC20': 'Ethereum',
|
571
|
+
'TRC20': 'Tron',
|
572
|
+
'BEP20': 'BNB Smart Chain',
|
573
|
+
'BEP2': 'BNB-BEP2',
|
574
|
+
'ETH': 'Ethereum',
|
575
|
+
'TRON': 'Tron',
|
576
|
+
'BNB': 'BNB Smart Chain',
|
577
|
+
'AVAX': 'AVAX C-Chain',
|
578
|
+
'GAL': 'GAL(FT)',
|
579
|
+
'ALEO': 'ALEO(IOU)',
|
580
|
+
'BTC': 'Bitcoin',
|
581
|
+
'XT': 'XT Smart Chain',
|
582
|
+
'ETC': 'Ethereum Classic',
|
583
|
+
'MATIC': 'Polygon',
|
584
|
+
'LTC': 'Litecoin',
|
585
|
+
'BTS': 'BitShares',
|
586
|
+
'XRP': 'Ripple',
|
587
|
+
'XLM': 'Stellar Network',
|
588
|
+
'ADA': 'Cardano',
|
589
|
+
'XWC': 'XWC-XWC',
|
590
|
+
'DOGE': 'dogecoin',
|
591
|
+
'DCR': 'Decred',
|
592
|
+
'SC': 'Siacoin',
|
593
|
+
'XTZ': 'Tezos',
|
594
|
+
'ZEC': 'Zcash',
|
595
|
+
'XMR': 'Monero',
|
596
|
+
'LSK': 'Lisk',
|
597
|
+
'ATOM': 'Cosmos',
|
598
|
+
'ONT': 'Ontology',
|
599
|
+
'ALGO': 'Algorand',
|
600
|
+
'SOL': 'SOL-SOL',
|
601
|
+
'DOT': 'Polkadot',
|
602
|
+
'ZEN': 'Horizen',
|
603
|
+
'FIL': 'Filecoin',
|
604
|
+
'CHZ': 'chz',
|
605
|
+
'ICP': 'Internet Computer',
|
606
|
+
'KSM': 'Kusama',
|
607
|
+
'LUNA': 'Terra',
|
608
|
+
'THETA': 'Theta Token',
|
609
|
+
'FTM': 'Fantom',
|
610
|
+
'VET': 'VeChain',
|
611
|
+
'NEAR': 'NEAR Protocol',
|
612
|
+
'ONE': 'Harmony',
|
613
|
+
'KLAY': 'Klaytn',
|
614
|
+
'AR': 'Arweave',
|
615
|
+
'CELT': 'OKT',
|
616
|
+
'EGLD': 'Elrond eGold',
|
617
|
+
'CRO': 'CRO-CRONOS',
|
618
|
+
'BCH': 'Bitcoin Cash',
|
619
|
+
'GLMR': 'Moonbeam',
|
620
|
+
'LOOP': 'LOOP-LRC',
|
621
|
+
'REI': 'REI Network',
|
622
|
+
'ASTR': 'Astar Network',
|
623
|
+
'OP': 'OPT',
|
624
|
+
'MMT': 'MMT-MMT',
|
625
|
+
'TBC': 'TBC-TBC',
|
626
|
+
'OMAX': 'OMAX-OMAX CHAIN',
|
627
|
+
'GMMT': 'GMMT chain',
|
628
|
+
'ZIL': 'Zilliqa',
|
629
|
+
},
|
630
|
+
'networksById': {
|
631
|
+
'Ethereum': 'ERC20',
|
632
|
+
'Tron': 'TRC20',
|
633
|
+
'BNB Smart Chain': 'BEP20',
|
634
|
+
'BNB-BEP2': 'BEP2',
|
635
|
+
'Bitcoin': 'BTC',
|
636
|
+
'XT Smart Chain': 'XT',
|
637
|
+
'Ethereum Classic': 'ETC',
|
638
|
+
'Polygon': 'MATIC',
|
639
|
+
'Litecoin': 'LTC',
|
640
|
+
'BitShares': 'BTS',
|
641
|
+
'Ripple': 'XRP',
|
642
|
+
'Stellar Network': 'XLM',
|
643
|
+
'Cardano': 'ADA',
|
644
|
+
'XWC-XWC': 'XWC',
|
645
|
+
'dogecoin': 'DOGE',
|
646
|
+
'Decred': 'DCR',
|
647
|
+
'Siacoin': 'SC',
|
648
|
+
'Tezos': 'XTZ',
|
649
|
+
'Zcash': 'ZEC',
|
650
|
+
'Monero': 'XMR',
|
651
|
+
'Lisk': 'LSK',
|
652
|
+
'Cosmos': 'ATOM',
|
653
|
+
'Ontology': 'ONT',
|
654
|
+
'Algorand': 'ALGO',
|
655
|
+
'SOL-SOL': 'SOL',
|
656
|
+
'Polkadot': 'DOT',
|
657
|
+
'Horizen': 'ZEN',
|
658
|
+
'Filecoin': 'FIL',
|
659
|
+
'chz': 'CHZ',
|
660
|
+
'Internet Computer': 'ICP',
|
661
|
+
'Kusama': 'KSM',
|
662
|
+
'Terra': 'LUNA',
|
663
|
+
'Theta Token': 'THETA',
|
664
|
+
'Fantom': 'FTM',
|
665
|
+
'VeChain': 'VET',
|
666
|
+
'AVAX C-Chain': 'AVAX',
|
667
|
+
'NEAR Protocol': 'NEAR',
|
668
|
+
'Harmony': 'ONE',
|
669
|
+
'Klaytn': 'KLAY',
|
670
|
+
'Arweave': 'AR',
|
671
|
+
'OKT': 'CELT',
|
672
|
+
'Elrond eGold': 'EGLD',
|
673
|
+
'CRO-CRONOS': 'CRO',
|
674
|
+
'Bitcoin Cash': 'BCH',
|
675
|
+
'Moonbeam': 'GLMR',
|
676
|
+
'LOOP-LRC': 'LOOP',
|
677
|
+
'REI Network': 'REI',
|
678
|
+
'Astar Network': 'ASTR',
|
679
|
+
'GAL(FT)': 'GAL',
|
680
|
+
'ALEO(IOU)': 'ALEO',
|
681
|
+
'OPT': 'OP',
|
682
|
+
'MMT-MMT': 'MMT',
|
683
|
+
'TBC-TBC': 'TBC',
|
684
|
+
'OMAX-OMAX CHAIN': 'OMAX',
|
685
|
+
'GMMT chain': 'GMMT',
|
686
|
+
'Zilliqa': 'ZIL',
|
687
|
+
},
|
688
|
+
'createMarketBuyOrderRequiresPrice': True,
|
689
|
+
'recvWindow': '5000', # in milliseconds, spot only
|
690
|
+
},
|
691
|
+
})
|
692
|
+
|
693
|
+
def nonce(self):
|
694
|
+
return self.milliseconds() - self.options['timeDifference']
|
695
|
+
|
696
|
+
async def fetch_time(self, params={}):
|
697
|
+
"""
|
698
|
+
fetches the current integer timestamp in milliseconds from the xt server
|
699
|
+
|
700
|
+
https://doc.xt.com/#market1serverInfo
|
701
|
+
|
702
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
703
|
+
:returns int: the current integer timestamp in milliseconds from the xt server
|
704
|
+
"""
|
705
|
+
response = await self.publicSpotGetTime(params)
|
706
|
+
#
|
707
|
+
# {
|
708
|
+
# "rc": 0,
|
709
|
+
# "mc": "SUCCESS",
|
710
|
+
# "ma": [],
|
711
|
+
# "result": {
|
712
|
+
# "serverTime": 1677823301643
|
713
|
+
# }
|
714
|
+
# }
|
715
|
+
#
|
716
|
+
data = self.safe_value(response, 'result')
|
717
|
+
return self.safe_integer(data, 'serverTime')
|
718
|
+
|
719
|
+
async def fetch_currencies(self, params={}) -> Currencies:
|
720
|
+
"""
|
721
|
+
fetches all available currencies on an exchange
|
722
|
+
|
723
|
+
https://doc.xt.com/#deposit_withdrawalsupportedCurrenciesGet
|
724
|
+
|
725
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
726
|
+
:returns dict: an associative dictionary of currencies
|
727
|
+
"""
|
728
|
+
promisesRaw = [self.publicSpotGetWalletSupportCurrency(params), self.publicSpotGetCurrencies(params)]
|
729
|
+
chainsResponse, currenciesResponse = await asyncio.gather(*promisesRaw)
|
730
|
+
#
|
731
|
+
# currencies
|
732
|
+
#
|
733
|
+
# {
|
734
|
+
# "time": "1686626116145",
|
735
|
+
# "version": "5dbbb2f2527c22b2b2e3b47187ef13d1",
|
736
|
+
# "currencies": [
|
737
|
+
# {
|
738
|
+
# "id": "2",
|
739
|
+
# "currency": "btc",
|
740
|
+
# "fullName": "Bitcoin",
|
741
|
+
# "logo": "https://a.static-global.com/1/currency/btc.png",
|
742
|
+
# "cmcLink": "https://coinmarketcap.com/currencies/bitcoin/",
|
743
|
+
# "weight": "99999",
|
744
|
+
# "maxPrecision": "10",
|
745
|
+
# "depositStatus": "1",
|
746
|
+
# "withdrawStatus": "1",
|
747
|
+
# "convertEnabled": "1",
|
748
|
+
# "transferEnabled": "1",
|
749
|
+
# "isChainExist": "1",
|
750
|
+
# "plates": [152]
|
751
|
+
# },
|
752
|
+
# ],
|
753
|
+
# }
|
754
|
+
#
|
755
|
+
#
|
756
|
+
# chains
|
757
|
+
#
|
758
|
+
# {
|
759
|
+
# "rc": 0,
|
760
|
+
# "mc": "SUCCESS",
|
761
|
+
# "ma": [],
|
762
|
+
# "result": [
|
763
|
+
# {
|
764
|
+
# "currency": "btc",
|
765
|
+
# "supportChains": [
|
766
|
+
# {
|
767
|
+
# "chain": "Bitcoin",
|
768
|
+
# "depositEnabled": True,
|
769
|
+
# "withdrawEnabled": True,
|
770
|
+
# "withdrawFeeAmount": 0.0009,
|
771
|
+
# "withdrawMinAmount": 0.0005,
|
772
|
+
# "depositFeeRate": 0
|
773
|
+
# },
|
774
|
+
# ]
|
775
|
+
# },
|
776
|
+
# ]
|
777
|
+
# }
|
778
|
+
#
|
779
|
+
# note: individual network's full data is available on per-currency endpoint: https://www.xt.com/sapi/v4/balance/public/currency/11
|
780
|
+
#
|
781
|
+
chainsData = self.safe_value(chainsResponse, 'result', [])
|
782
|
+
currenciesResult = self.safe_value(currenciesResponse, 'result', [])
|
783
|
+
currenciesData = self.safe_value(currenciesResult, 'currencies', [])
|
784
|
+
chainsDataIndexed = self.index_by(chainsData, 'currency')
|
785
|
+
result = {}
|
786
|
+
for i in range(0, len(currenciesData)):
|
787
|
+
entry = currenciesData[i]
|
788
|
+
currencyId = self.safe_string(entry, 'currency')
|
789
|
+
code = self.safe_currency_code(currencyId)
|
790
|
+
minPrecision = self.parse_number(self.parse_precision(self.safe_string(entry, 'maxPrecision')))
|
791
|
+
networkEntry = self.safe_value(chainsDataIndexed, currencyId, {})
|
792
|
+
rawNetworks = self.safe_value(networkEntry, 'supportChains', [])
|
793
|
+
networks = {}
|
794
|
+
minWithdrawString = None
|
795
|
+
minWithdrawFeeString = None
|
796
|
+
active = False
|
797
|
+
deposit = False
|
798
|
+
withdraw = False
|
799
|
+
for j in range(0, len(rawNetworks)):
|
800
|
+
rawNetwork = rawNetworks[j]
|
801
|
+
networkId = self.safe_string(rawNetwork, 'chain')
|
802
|
+
network = self.network_id_to_code(networkId)
|
803
|
+
depositEnabled = self.safe_value(rawNetwork, 'depositEnabled')
|
804
|
+
deposit = depositEnabled if (depositEnabled) else deposit
|
805
|
+
withdrawEnabled = self.safe_value(rawNetwork, 'withdrawEnabled')
|
806
|
+
withdraw = withdrawEnabled if (withdrawEnabled) else withdraw
|
807
|
+
networkActive = depositEnabled and withdrawEnabled
|
808
|
+
active = networkActive if (networkActive) else active
|
809
|
+
withdrawFeeString = self.safe_string(rawNetwork, 'withdrawFeeAmount')
|
810
|
+
if withdrawFeeString is not None:
|
811
|
+
minWithdrawFeeString = withdrawFeeString if (minWithdrawFeeString is None) else Precise.string_min(withdrawFeeString, minWithdrawFeeString)
|
812
|
+
minNetworkWithdrawString = self.safe_string(rawNetwork, 'withdrawMinAmount')
|
813
|
+
if minNetworkWithdrawString is not None:
|
814
|
+
minWithdrawString = minNetworkWithdrawString if (minWithdrawString is None) else Precise.string_min(minNetworkWithdrawString, minWithdrawString)
|
815
|
+
networks[network] = {
|
816
|
+
'info': rawNetwork,
|
817
|
+
'id': networkId,
|
818
|
+
'network': network,
|
819
|
+
'name': None,
|
820
|
+
'active': networkActive,
|
821
|
+
'fee': self.parse_number(withdrawFeeString),
|
822
|
+
'precision': minPrecision,
|
823
|
+
'deposit': depositEnabled,
|
824
|
+
'withdraw': withdrawEnabled,
|
825
|
+
'limits': {
|
826
|
+
'amount': {
|
827
|
+
'min': None,
|
828
|
+
'max': None,
|
829
|
+
},
|
830
|
+
'withdraw': {
|
831
|
+
'min': self.parse_number(minNetworkWithdrawString),
|
832
|
+
'max': None,
|
833
|
+
},
|
834
|
+
'deposit': {
|
835
|
+
'min': None,
|
836
|
+
'max': None,
|
837
|
+
},
|
838
|
+
},
|
839
|
+
}
|
840
|
+
result[code] = {
|
841
|
+
'info': entry,
|
842
|
+
'id': currencyId,
|
843
|
+
'code': code,
|
844
|
+
'name': self.safe_string(entry, 'fullName'),
|
845
|
+
'active': active,
|
846
|
+
'fee': self.parse_number(minWithdrawFeeString),
|
847
|
+
'precision': minPrecision,
|
848
|
+
'deposit': deposit,
|
849
|
+
'withdraw': withdraw,
|
850
|
+
'networks': networks,
|
851
|
+
'limits': {
|
852
|
+
'amount': {
|
853
|
+
'min': None,
|
854
|
+
'max': None,
|
855
|
+
},
|
856
|
+
'withdraw': {
|
857
|
+
'min': self.parse_number(minWithdrawString),
|
858
|
+
'max': None,
|
859
|
+
},
|
860
|
+
'deposit': {
|
861
|
+
'min': None,
|
862
|
+
'max': None,
|
863
|
+
},
|
864
|
+
},
|
865
|
+
}
|
866
|
+
return result
|
867
|
+
|
868
|
+
async def fetch_markets(self, params={}) -> List[Market]:
|
869
|
+
"""
|
870
|
+
retrieves data on all markets for xt
|
871
|
+
|
872
|
+
https://doc.xt.com/#market2symbol
|
873
|
+
https://doc.xt.com/#futures_quotesgetSymbols
|
874
|
+
|
875
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
876
|
+
:returns dict[]: an array of objects representing market data
|
877
|
+
"""
|
878
|
+
if self.options['adjustForTimeDifference']:
|
879
|
+
await self.load_time_difference()
|
880
|
+
promisesUnresolved = [
|
881
|
+
self.fetch_spot_markets(params),
|
882
|
+
self.fetch_swap_and_future_markets(params),
|
883
|
+
]
|
884
|
+
promises = await asyncio.gather(*promisesUnresolved)
|
885
|
+
spotMarkets = promises[0]
|
886
|
+
swapAndFutureMarkets = promises[1]
|
887
|
+
return self.array_concat(spotMarkets, swapAndFutureMarkets)
|
888
|
+
|
889
|
+
async def fetch_spot_markets(self, params={}):
|
890
|
+
response = await self.publicSpotGetSymbol(params)
|
891
|
+
#
|
892
|
+
# {
|
893
|
+
# "rc": 0,
|
894
|
+
# "mc": "SUCCESS",
|
895
|
+
# "ma": [],
|
896
|
+
# "result": {
|
897
|
+
# "time": 1677881368812,
|
898
|
+
# "version": "abb101d1543e54bee40687b135411ba0",
|
899
|
+
# "symbols": [
|
900
|
+
# {
|
901
|
+
# "id": 640,
|
902
|
+
# "symbol": "xt_usdt",
|
903
|
+
# "state": "ONLINE",
|
904
|
+
# "stateTime": 1554048000000,
|
905
|
+
# "tradingEnabled": True,
|
906
|
+
# "openapiEnabled": True,
|
907
|
+
# "nextStateTime": null,
|
908
|
+
# "nextState": null,
|
909
|
+
# "depthMergePrecision": 5,
|
910
|
+
# "baseCurrency": "xt",
|
911
|
+
# "baseCurrencyPrecision": 8,
|
912
|
+
# "baseCurrencyId": 128,
|
913
|
+
# "quoteCurrency": "usdt",
|
914
|
+
# "quoteCurrencyPrecision": 8,
|
915
|
+
# "quoteCurrencyId": 11,
|
916
|
+
# "pricePrecision": 4,
|
917
|
+
# "quantityPrecision": 2,
|
918
|
+
# "orderTypes": ["LIMIT","MARKET"],
|
919
|
+
# "timeInForces": ["GTC","IOC"],
|
920
|
+
# "displayWeight": 10002,
|
921
|
+
# "displayLevel": "FULL",
|
922
|
+
# "plates": [],
|
923
|
+
# "filters":[
|
924
|
+
# {
|
925
|
+
# "filter": "QUOTE_QTY",
|
926
|
+
# "min": "1"
|
927
|
+
# },
|
928
|
+
# {
|
929
|
+
# "filter": "PROTECTION_LIMIT",
|
930
|
+
# "buyMaxDeviation": "0.8",
|
931
|
+
# "sellMaxDeviation": "4"
|
932
|
+
# },
|
933
|
+
# {
|
934
|
+
# "filter": "PROTECTION_MARKET",
|
935
|
+
# "maxDeviation": "0.02"
|
936
|
+
# }
|
937
|
+
# ]
|
938
|
+
# },
|
939
|
+
# ]
|
940
|
+
# }
|
941
|
+
# }
|
942
|
+
#
|
943
|
+
data = self.safe_value(response, 'result', {})
|
944
|
+
symbols = self.safe_value(data, 'symbols', [])
|
945
|
+
return self.parse_markets(symbols)
|
946
|
+
|
947
|
+
async def fetch_swap_and_future_markets(self, params={}):
|
948
|
+
markets = await asyncio.gather(*[self.publicLinearGetFutureMarketV1PublicSymbolList(params), self.publicInverseGetFutureMarketV1PublicSymbolList(params)])
|
949
|
+
#
|
950
|
+
# {
|
951
|
+
# "returnCode": 0,
|
952
|
+
# "msgInfo": "success",
|
953
|
+
# "error": null,
|
954
|
+
# "result": [
|
955
|
+
# {
|
956
|
+
# "id": 52,
|
957
|
+
# "symbolGroupId": 71,
|
958
|
+
# "symbol": "xt_usdt",
|
959
|
+
# "pair": "xt_usdt",
|
960
|
+
# "contractType": "PERPETUAL",
|
961
|
+
# "productType": "perpetual",
|
962
|
+
# "predictEventType": null,
|
963
|
+
# "underlyingType": "U_BASED",
|
964
|
+
# "contractSize": "1",
|
965
|
+
# "tradeSwitch": True,
|
966
|
+
# "isDisplay": True,
|
967
|
+
# "isOpenApi": False,
|
968
|
+
# "state": 0,
|
969
|
+
# "initLeverage": 20,
|
970
|
+
# "initPositionType": "CROSSED",
|
971
|
+
# "baseCoin": "xt",
|
972
|
+
# "quoteCoin": "usdt",
|
973
|
+
# "baseCoinPrecision": 8,
|
974
|
+
# "baseCoinDisplayPrecision": 4,
|
975
|
+
# "quoteCoinPrecision": 8,
|
976
|
+
# "quoteCoinDisplayPrecision": 4,
|
977
|
+
# "quantityPrecision": 0,
|
978
|
+
# "pricePrecision": 4,
|
979
|
+
# "supportOrderType": "LIMIT,MARKET",
|
980
|
+
# "supportTimeInForce": "GTC,FOK,IOC,GTX",
|
981
|
+
# "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
|
982
|
+
# "supportPositionType": "CROSSED,ISOLATED",
|
983
|
+
# "minQty": "1",
|
984
|
+
# "minNotional": "5",
|
985
|
+
# "maxNotional": "20000000",
|
986
|
+
# "multiplierDown": "0.1",
|
987
|
+
# "multiplierUp": "0.1",
|
988
|
+
# "maxOpenOrders": 200,
|
989
|
+
# "maxEntrusts": 200,
|
990
|
+
# "makerFee": "0.0004",
|
991
|
+
# "takerFee": "0.0006",
|
992
|
+
# "liquidationFee": "0.01",
|
993
|
+
# "marketTakeBound": "0.1",
|
994
|
+
# "depthPrecisionMerge": 5,
|
995
|
+
# "labels": ["HOT"],
|
996
|
+
# "onboardDate": 1657101601000,
|
997
|
+
# "enName": "XTUSDT ",
|
998
|
+
# "cnName": "XTUSDT",
|
999
|
+
# "minStepPrice": "0.0001",
|
1000
|
+
# "minPrice": null,
|
1001
|
+
# "maxPrice": null,
|
1002
|
+
# "deliveryDate": 1669879634000,
|
1003
|
+
# "deliveryPrice": null,
|
1004
|
+
# "deliveryCompletion": False,
|
1005
|
+
# "cnDesc": null,
|
1006
|
+
# "enDesc": null
|
1007
|
+
# },
|
1008
|
+
# ]
|
1009
|
+
# }
|
1010
|
+
#
|
1011
|
+
swapAndFutureMarkets = self.array_concat(self.safe_value(markets[0], 'result', []), self.safe_value(markets[1], 'result', []))
|
1012
|
+
return self.parse_markets(swapAndFutureMarkets)
|
1013
|
+
|
1014
|
+
def parse_markets(self, markets):
|
1015
|
+
result = []
|
1016
|
+
for i in range(0, len(markets)):
|
1017
|
+
result.append(self.parse_market(markets[i]))
|
1018
|
+
return result
|
1019
|
+
|
1020
|
+
def parse_market(self, market: dict) -> Market:
|
1021
|
+
#
|
1022
|
+
# spot
|
1023
|
+
#
|
1024
|
+
# {
|
1025
|
+
# "id": 640,
|
1026
|
+
# "symbol": "xt_usdt",
|
1027
|
+
# "state": "ONLINE",
|
1028
|
+
# "stateTime": 1554048000000,
|
1029
|
+
# "tradingEnabled": True,
|
1030
|
+
# "openapiEnabled": True,
|
1031
|
+
# "nextStateTime": null,
|
1032
|
+
# "nextState": null,
|
1033
|
+
# "depthMergePrecision": 5,
|
1034
|
+
# "baseCurrency": "xt",
|
1035
|
+
# "baseCurrencyPrecision": 8,
|
1036
|
+
# "baseCurrencyId": 128,
|
1037
|
+
# "quoteCurrency": "usdt",
|
1038
|
+
# "quoteCurrencyPrecision": 8,
|
1039
|
+
# "quoteCurrencyId": 11,
|
1040
|
+
# "pricePrecision": 4,
|
1041
|
+
# "quantityPrecision": 2,
|
1042
|
+
# "orderTypes": ["LIMIT","MARKET"],
|
1043
|
+
# "timeInForces": ["GTC","IOC"],
|
1044
|
+
# "displayWeight": 10002,
|
1045
|
+
# "displayLevel": "FULL",
|
1046
|
+
# "plates": [],
|
1047
|
+
# "filters":[
|
1048
|
+
# {
|
1049
|
+
# "filter": "QUOTE_QTY",
|
1050
|
+
# "min": "1"
|
1051
|
+
# },
|
1052
|
+
# {
|
1053
|
+
# "filter": "PRICE",
|
1054
|
+
# "min": null,
|
1055
|
+
# "max": null,
|
1056
|
+
# "tickSize": null
|
1057
|
+
# },
|
1058
|
+
# {
|
1059
|
+
# "filter": "QUANTITY",
|
1060
|
+
# "min": null,
|
1061
|
+
# "max": null,
|
1062
|
+
# "tickSize": null
|
1063
|
+
# },
|
1064
|
+
# {
|
1065
|
+
# "filter": "PROTECTION_LIMIT",
|
1066
|
+
# "buyMaxDeviation": "0.8",
|
1067
|
+
# "sellMaxDeviation": "4"
|
1068
|
+
# },
|
1069
|
+
# {
|
1070
|
+
# "filter": "PROTECTION_MARKET",
|
1071
|
+
# "maxDeviation": "0.02"
|
1072
|
+
# },
|
1073
|
+
# {
|
1074
|
+
# "filter": "PROTECTION_ONLINE",
|
1075
|
+
# "durationSeconds": "300",
|
1076
|
+
# "maxPriceMultiple": "5"
|
1077
|
+
# },
|
1078
|
+
# ]
|
1079
|
+
# }
|
1080
|
+
#
|
1081
|
+
# swap and future
|
1082
|
+
#
|
1083
|
+
# {
|
1084
|
+
# "id": 52,
|
1085
|
+
# "symbolGroupId": 71,
|
1086
|
+
# "symbol": "xt_usdt",
|
1087
|
+
# "pair": "xt_usdt",
|
1088
|
+
# "contractType": "PERPETUAL",
|
1089
|
+
# "productType": "perpetual",
|
1090
|
+
# "predictEventType": null,
|
1091
|
+
# "underlyingType": "U_BASED",
|
1092
|
+
# "contractSize": "1",
|
1093
|
+
# "tradeSwitch": True,
|
1094
|
+
# "isDisplay": True,
|
1095
|
+
# "isOpenApi": False,
|
1096
|
+
# "state": 0,
|
1097
|
+
# "initLeverage": 20,
|
1098
|
+
# "initPositionType": "CROSSED",
|
1099
|
+
# "baseCoin": "xt",
|
1100
|
+
# "quoteCoin": "usdt",
|
1101
|
+
# "baseCoinPrecision": 8,
|
1102
|
+
# "baseCoinDisplayPrecision": 4,
|
1103
|
+
# "quoteCoinPrecision": 8,
|
1104
|
+
# "quoteCoinDisplayPrecision": 4,
|
1105
|
+
# "quantityPrecision": 0,
|
1106
|
+
# "pricePrecision": 4,
|
1107
|
+
# "supportOrderType": "LIMIT,MARKET",
|
1108
|
+
# "supportTimeInForce": "GTC,FOK,IOC,GTX",
|
1109
|
+
# "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
|
1110
|
+
# "supportPositionType": "CROSSED,ISOLATED",
|
1111
|
+
# "minQty": "1",
|
1112
|
+
# "minNotional": "5",
|
1113
|
+
# "maxNotional": "20000000",
|
1114
|
+
# "multiplierDown": "0.1",
|
1115
|
+
# "multiplierUp": "0.1",
|
1116
|
+
# "maxOpenOrders": 200,
|
1117
|
+
# "maxEntrusts": 200,
|
1118
|
+
# "makerFee": "0.0004",
|
1119
|
+
# "takerFee": "0.0006",
|
1120
|
+
# "liquidationFee": "0.01",
|
1121
|
+
# "marketTakeBound": "0.1",
|
1122
|
+
# "depthPrecisionMerge": 5,
|
1123
|
+
# "labels": ["HOT"],
|
1124
|
+
# "onboardDate": 1657101601000,
|
1125
|
+
# "enName": "XTUSDT ",
|
1126
|
+
# "cnName": "XTUSDT",
|
1127
|
+
# "minStepPrice": "0.0001",
|
1128
|
+
# "minPrice": null,
|
1129
|
+
# "maxPrice": null,
|
1130
|
+
# "deliveryDate": 1669879634000,
|
1131
|
+
# "deliveryPrice": null,
|
1132
|
+
# "deliveryCompletion": False,
|
1133
|
+
# "cnDesc": null,
|
1134
|
+
# "enDesc": null
|
1135
|
+
# }
|
1136
|
+
#
|
1137
|
+
id = self.safe_string(market, 'symbol')
|
1138
|
+
baseId = self.safe_string_2(market, 'baseCurrency', 'baseCoin')
|
1139
|
+
quoteId = self.safe_string_2(market, 'quoteCurrency', 'quoteCoin')
|
1140
|
+
base = self.safe_currency_code(baseId)
|
1141
|
+
quote = self.safe_currency_code(quoteId)
|
1142
|
+
state = self.safe_string(market, 'state')
|
1143
|
+
symbol = base + '/' + quote
|
1144
|
+
filters = self.safe_value(market, 'filters', [])
|
1145
|
+
minAmount = None
|
1146
|
+
maxAmount = None
|
1147
|
+
minCost = None
|
1148
|
+
maxCost = None
|
1149
|
+
minPrice = None
|
1150
|
+
maxPrice = None
|
1151
|
+
amountPrecision = None
|
1152
|
+
for i in range(0, len(filters)):
|
1153
|
+
entry = filters[i]
|
1154
|
+
filter = self.safe_string(entry, 'filter')
|
1155
|
+
if filter == 'QUANTITY':
|
1156
|
+
minAmount = self.safe_number(entry, 'min')
|
1157
|
+
maxAmount = self.safe_number(entry, 'max')
|
1158
|
+
amountPrecision = self.safe_number(entry, 'tickSize')
|
1159
|
+
if filter == 'QUOTE_QTY':
|
1160
|
+
minCost = self.safe_number(entry, 'min')
|
1161
|
+
if filter == 'PRICE':
|
1162
|
+
minPrice = self.safe_number(entry, 'min')
|
1163
|
+
maxPrice = self.safe_number(entry, 'max')
|
1164
|
+
if amountPrecision is None:
|
1165
|
+
amountPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision')))
|
1166
|
+
underlyingType = self.safe_string(market, 'underlyingType')
|
1167
|
+
linear = None
|
1168
|
+
inverse = None
|
1169
|
+
settleId = None
|
1170
|
+
settle = None
|
1171
|
+
expiry = None
|
1172
|
+
future = False
|
1173
|
+
swap = False
|
1174
|
+
contract = False
|
1175
|
+
spot = True
|
1176
|
+
type = 'spot'
|
1177
|
+
if underlyingType == 'U_BASED':
|
1178
|
+
symbol = symbol + ':' + quote
|
1179
|
+
settleId = baseId
|
1180
|
+
settle = quote
|
1181
|
+
linear = True
|
1182
|
+
inverse = False
|
1183
|
+
elif underlyingType == 'COIN_BASED':
|
1184
|
+
symbol = symbol + ':' + base
|
1185
|
+
settleId = baseId
|
1186
|
+
settle = base
|
1187
|
+
linear = False
|
1188
|
+
inverse = True
|
1189
|
+
if underlyingType is not None:
|
1190
|
+
expiry = self.safe_integer(market, 'deliveryDate')
|
1191
|
+
productType = self.safe_string(market, 'productType')
|
1192
|
+
if productType != 'perpetual':
|
1193
|
+
symbol = symbol + '-' + self.yymmdd(expiry)
|
1194
|
+
type = 'future'
|
1195
|
+
future = True
|
1196
|
+
else:
|
1197
|
+
type = 'swap'
|
1198
|
+
swap = True
|
1199
|
+
minAmount = self.safe_number(market, 'minQty')
|
1200
|
+
minCost = self.safe_number(market, 'minNotional')
|
1201
|
+
maxCost = self.safe_number(market, 'maxNotional')
|
1202
|
+
minPrice = self.safe_number(market, 'minPrice')
|
1203
|
+
maxPrice = self.safe_number(market, 'maxPrice')
|
1204
|
+
contract = True
|
1205
|
+
spot = False
|
1206
|
+
isActive = False
|
1207
|
+
if contract:
|
1208
|
+
isActive = self.safe_value(market, 'isOpenApi', False)
|
1209
|
+
else:
|
1210
|
+
if (state == 'ONLINE') and (self.safe_value(market, 'tradingEnabled')) and (self.safe_value(market, 'openapiEnabled')):
|
1211
|
+
isActive = True
|
1212
|
+
return self.safe_market_structure({
|
1213
|
+
'id': id,
|
1214
|
+
'symbol': symbol,
|
1215
|
+
'base': base,
|
1216
|
+
'quote': quote,
|
1217
|
+
'settle': settle,
|
1218
|
+
'baseId': baseId,
|
1219
|
+
'quoteId': quoteId,
|
1220
|
+
'settleId': settleId,
|
1221
|
+
'type': type,
|
1222
|
+
'spot': spot,
|
1223
|
+
'margin': None,
|
1224
|
+
'swap': swap,
|
1225
|
+
'future': future,
|
1226
|
+
'option': False,
|
1227
|
+
'active': isActive,
|
1228
|
+
'contract': contract,
|
1229
|
+
'linear': linear,
|
1230
|
+
'inverse': inverse,
|
1231
|
+
'taker': self.safe_number(market, 'takerFee'),
|
1232
|
+
'maker': self.safe_number(market, 'makerFee'),
|
1233
|
+
'contractSize': self.safe_number(market, 'contractSize'),
|
1234
|
+
'expiry': expiry,
|
1235
|
+
'expiryDatetime': self.iso8601(expiry),
|
1236
|
+
'strike': None,
|
1237
|
+
'optionType': None,
|
1238
|
+
'precision': {
|
1239
|
+
'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision'))),
|
1240
|
+
'amount': amountPrecision,
|
1241
|
+
'base': self.parse_number(self.parse_precision(self.safe_string(market, 'baseCoinPrecision'))),
|
1242
|
+
'quote': self.parse_number(self.parse_precision(self.safe_string(market, 'quoteCoinPrecision'))),
|
1243
|
+
},
|
1244
|
+
'limits': {
|
1245
|
+
'leverage': {
|
1246
|
+
'min': self.parse_number('1'),
|
1247
|
+
'max': None,
|
1248
|
+
},
|
1249
|
+
'amount': {
|
1250
|
+
'min': minAmount,
|
1251
|
+
'max': maxAmount,
|
1252
|
+
},
|
1253
|
+
'price': {
|
1254
|
+
'min': minPrice,
|
1255
|
+
'max': maxPrice,
|
1256
|
+
},
|
1257
|
+
'cost': {
|
1258
|
+
'min': minCost,
|
1259
|
+
'max': maxCost,
|
1260
|
+
},
|
1261
|
+
},
|
1262
|
+
'info': market,
|
1263
|
+
})
|
1264
|
+
|
1265
|
+
async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
1266
|
+
"""
|
1267
|
+
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
1268
|
+
|
1269
|
+
https://doc.xt.com/#market4kline
|
1270
|
+
https://doc.xt.com/#futures_quotesgetKLine
|
1271
|
+
|
1272
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
1273
|
+
:param str timeframe: the length of time each candle represents
|
1274
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
1275
|
+
:param int [limit]: the maximum amount of candles to fetch
|
1276
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
1277
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
1278
|
+
"""
|
1279
|
+
await self.load_markets()
|
1280
|
+
market = self.market(symbol)
|
1281
|
+
request = {
|
1282
|
+
'symbol': market['id'],
|
1283
|
+
'interval': self.safe_string(self.timeframes, timeframe, timeframe),
|
1284
|
+
}
|
1285
|
+
if since is not None:
|
1286
|
+
request['startTime'] = since
|
1287
|
+
if limit is not None:
|
1288
|
+
request['limit'] = limit
|
1289
|
+
response = None
|
1290
|
+
if market['linear']:
|
1291
|
+
response = await self.publicLinearGetFutureMarketV1PublicQKline(self.extend(request, params))
|
1292
|
+
elif market['inverse']:
|
1293
|
+
response = await self.publicInverseGetFutureMarketV1PublicQKline(self.extend(request, params))
|
1294
|
+
else:
|
1295
|
+
response = await self.publicSpotGetKline(self.extend(request, params))
|
1296
|
+
#
|
1297
|
+
# spot
|
1298
|
+
#
|
1299
|
+
# {
|
1300
|
+
# "rc": 0,
|
1301
|
+
# "mc": "SUCCESS",
|
1302
|
+
# "ma": [],
|
1303
|
+
# "result": [
|
1304
|
+
# {
|
1305
|
+
# "t": 1678167720000,
|
1306
|
+
# "o": "22467.85",
|
1307
|
+
# "c": "22465.87",
|
1308
|
+
# "h": "22468.86",
|
1309
|
+
# "l": "22465.21",
|
1310
|
+
# "q": "1.316656",
|
1311
|
+
# "v": "29582.73018498"
|
1312
|
+
# },
|
1313
|
+
# ]
|
1314
|
+
# }
|
1315
|
+
#
|
1316
|
+
# swap and future
|
1317
|
+
#
|
1318
|
+
# {
|
1319
|
+
# "returnCode": 0,
|
1320
|
+
# "msgInfo": "success",
|
1321
|
+
# "error": null,
|
1322
|
+
# "result": [
|
1323
|
+
# {
|
1324
|
+
# "s": "btc_usdt",
|
1325
|
+
# "p": "btc_usdt",
|
1326
|
+
# "t": 1678168020000,
|
1327
|
+
# "o": "22450.0",
|
1328
|
+
# "c": "22441.5",
|
1329
|
+
# "h": "22450.0",
|
1330
|
+
# "l": "22441.5",
|
1331
|
+
# "a": "312931",
|
1332
|
+
# "v": "702461.58895"
|
1333
|
+
# },
|
1334
|
+
# ]
|
1335
|
+
# }
|
1336
|
+
#
|
1337
|
+
ohlcvs = self.safe_value(response, 'result', [])
|
1338
|
+
return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
|
1339
|
+
|
1340
|
+
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
1341
|
+
#
|
1342
|
+
# spot
|
1343
|
+
#
|
1344
|
+
# {
|
1345
|
+
# "t": 1678167720000,
|
1346
|
+
# "o": "22467.85",
|
1347
|
+
# "c": "22465.87",
|
1348
|
+
# "h": "22468.86",
|
1349
|
+
# "l": "22465.21",
|
1350
|
+
# "q": "1.316656",
|
1351
|
+
# "v": "29582.73018498"
|
1352
|
+
# }
|
1353
|
+
#
|
1354
|
+
# swap and future
|
1355
|
+
#
|
1356
|
+
# {
|
1357
|
+
# "s": "btc_usdt",
|
1358
|
+
# "p": "btc_usdt",
|
1359
|
+
# "t": 1678168020000,
|
1360
|
+
# "o": "22450.0",
|
1361
|
+
# "c": "22441.5",
|
1362
|
+
# "h": "22450.0",
|
1363
|
+
# "l": "22441.5",
|
1364
|
+
# "a": "312931",
|
1365
|
+
# "v": "702461.58895"
|
1366
|
+
# }
|
1367
|
+
#
|
1368
|
+
volumeIndex = 'v' if (market['inverse']) else 'a'
|
1369
|
+
return [
|
1370
|
+
self.safe_integer(ohlcv, 't'),
|
1371
|
+
self.safe_number(ohlcv, 'o'),
|
1372
|
+
self.safe_number(ohlcv, 'h'),
|
1373
|
+
self.safe_number(ohlcv, 'l'),
|
1374
|
+
self.safe_number(ohlcv, 'c'),
|
1375
|
+
self.safe_number_2(ohlcv, 'q', volumeIndex),
|
1376
|
+
]
|
1377
|
+
|
1378
|
+
async def fetch_order_book(self, symbol: str, limit: Int = None, params={}):
|
1379
|
+
"""
|
1380
|
+
|
1381
|
+
https://doc.xt.com/#market3depth
|
1382
|
+
https://doc.xt.com/#futures_quotesgetDepth
|
1383
|
+
|
1384
|
+
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
1385
|
+
:param str symbol: unified market symbol to fetch the order book for
|
1386
|
+
:param int [limit]: the maximum amount of order book entries to return
|
1387
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
1388
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/en/latest/manual.html#order-book-structure>` indexed by market symbols
|
1389
|
+
"""
|
1390
|
+
await self.load_markets()
|
1391
|
+
market = self.market(symbol)
|
1392
|
+
request = {
|
1393
|
+
'symbol': market['id'],
|
1394
|
+
}
|
1395
|
+
response = None
|
1396
|
+
if market['spot']:
|
1397
|
+
if limit is not None:
|
1398
|
+
request['limit'] = min(limit, 500)
|
1399
|
+
response = await self.publicSpotGetDepth(self.extend(request, params))
|
1400
|
+
else:
|
1401
|
+
if limit is not None:
|
1402
|
+
request['level'] = min(limit, 50)
|
1403
|
+
else:
|
1404
|
+
request['level'] = 50
|
1405
|
+
if market['linear']:
|
1406
|
+
response = await self.publicLinearGetFutureMarketV1PublicQDepth(self.extend(request, params))
|
1407
|
+
elif market['inverse']:
|
1408
|
+
response = await self.publicInverseGetFutureMarketV1PublicQDepth(self.extend(request, params))
|
1409
|
+
#
|
1410
|
+
# spot
|
1411
|
+
#
|
1412
|
+
# {
|
1413
|
+
# "rc": 0,
|
1414
|
+
# "mc": "SUCCESS",
|
1415
|
+
# "ma": [],
|
1416
|
+
# "result": {
|
1417
|
+
# "timestamp": 1678169975184,
|
1418
|
+
# "lastUpdateId": 1675333221812,
|
1419
|
+
# "bids": [
|
1420
|
+
# ["22444.51", "0.129887"],
|
1421
|
+
# ["22444.49", "0.114245"],
|
1422
|
+
# ["22444.30", "0.225956"]
|
1423
|
+
# ],
|
1424
|
+
# "asks": [
|
1425
|
+
# ["22446.19", "0.095330"],
|
1426
|
+
# ["22446.24", "0.224413"],
|
1427
|
+
# ["22446.28", "0.329095"]
|
1428
|
+
# ]
|
1429
|
+
# }
|
1430
|
+
# }
|
1431
|
+
#
|
1432
|
+
# swap and future
|
1433
|
+
#
|
1434
|
+
# {
|
1435
|
+
# "returnCode": 0,
|
1436
|
+
# "msgInfo": "success",
|
1437
|
+
# "error": null,
|
1438
|
+
# "result": {
|
1439
|
+
# "t": 1678170311005,
|
1440
|
+
# "s": "btc_usdt",
|
1441
|
+
# "u": 471694545627,
|
1442
|
+
# "b": [
|
1443
|
+
# ["22426", "198623"],
|
1444
|
+
# ["22423.5", "80295"],
|
1445
|
+
# ["22423", "163580"]
|
1446
|
+
# ],
|
1447
|
+
# "a": [
|
1448
|
+
# ["22427", "3417"],
|
1449
|
+
# ["22428.5", "43532"],
|
1450
|
+
# ["22429", "119"]
|
1451
|
+
# ]
|
1452
|
+
# }
|
1453
|
+
# }
|
1454
|
+
#
|
1455
|
+
orderBook = self.safe_value(response, 'result', {})
|
1456
|
+
timestamp = self.safe_integer_2(orderBook, 'timestamp', 't')
|
1457
|
+
if market['spot']:
|
1458
|
+
ob = self.parse_order_book(orderBook, symbol, timestamp)
|
1459
|
+
ob['nonce'] = self.safe_integer(orderBook, 'lastUpdateId')
|
1460
|
+
return ob
|
1461
|
+
swapOb = self.parse_order_book(orderBook, symbol, timestamp, 'b', 'a')
|
1462
|
+
swapOb['nonce'] = self.safe_integer_2(orderBook, 'u', 'lastUpdateId')
|
1463
|
+
return swapOb
|
1464
|
+
|
1465
|
+
async def fetch_ticker(self, symbol: str, params={}):
|
1466
|
+
"""
|
1467
|
+
fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
1468
|
+
|
1469
|
+
https://doc.xt.com/#market10ticker24h
|
1470
|
+
https://doc.xt.com/#futures_quotesgetAggTicker
|
1471
|
+
|
1472
|
+
:param str symbol: unified market symbol to fetch the ticker for
|
1473
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
1474
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
|
1475
|
+
"""
|
1476
|
+
await self.load_markets()
|
1477
|
+
market = self.market(symbol)
|
1478
|
+
request = {
|
1479
|
+
'symbol': market['id'],
|
1480
|
+
}
|
1481
|
+
response = None
|
1482
|
+
if market['linear']:
|
1483
|
+
response = await self.publicLinearGetFutureMarketV1PublicQAggTicker(self.extend(request, params))
|
1484
|
+
elif market['inverse']:
|
1485
|
+
response = await self.publicInverseGetFutureMarketV1PublicQAggTicker(self.extend(request, params))
|
1486
|
+
else:
|
1487
|
+
response = await self.publicSpotGetTicker24h(self.extend(request, params))
|
1488
|
+
#
|
1489
|
+
# spot
|
1490
|
+
#
|
1491
|
+
# {
|
1492
|
+
# "rc": 0,
|
1493
|
+
# "mc": "SUCCESS",
|
1494
|
+
# "ma": [],
|
1495
|
+
# "result": [
|
1496
|
+
# {
|
1497
|
+
# "s": "btc_usdt",
|
1498
|
+
# "t": 1678172693931,
|
1499
|
+
# "cv": "34.00",
|
1500
|
+
# "cr": "0.0015",
|
1501
|
+
# "o": "22398.05",
|
1502
|
+
# "l": "22323.72",
|
1503
|
+
# "h": "22600.50",
|
1504
|
+
# "c": "22432.05",
|
1505
|
+
# "q": "7962.256931",
|
1506
|
+
# "v": "178675209.47416856"
|
1507
|
+
# }
|
1508
|
+
# ]
|
1509
|
+
# }
|
1510
|
+
#
|
1511
|
+
# swap and future
|
1512
|
+
#
|
1513
|
+
# {
|
1514
|
+
# "returnCode": 0,
|
1515
|
+
# "msgInfo": "success",
|
1516
|
+
# "error": null,
|
1517
|
+
# "result": {
|
1518
|
+
# "t": 1678172848572,
|
1519
|
+
# "s": "btc_usdt",
|
1520
|
+
# "c": "22415.5",
|
1521
|
+
# "h": "22590.0",
|
1522
|
+
# "l": "22310.0",
|
1523
|
+
# "a": "623654031",
|
1524
|
+
# "v": "1399166074.31675",
|
1525
|
+
# "o": "22381.5",
|
1526
|
+
# "r": "0.0015",
|
1527
|
+
# "i": "22424.5",
|
1528
|
+
# "m": "22416.5",
|
1529
|
+
# "bp": "22415",
|
1530
|
+
# "ap": "22415.5"
|
1531
|
+
# }
|
1532
|
+
# }
|
1533
|
+
#
|
1534
|
+
ticker = self.safe_value(response, 'result')
|
1535
|
+
if market['spot']:
|
1536
|
+
return self.parse_ticker(ticker[0], market)
|
1537
|
+
return self.parse_ticker(ticker, market)
|
1538
|
+
|
1539
|
+
async def fetch_tickers(self, symbols: List[str] = None, params={}) -> Tickers:
|
1540
|
+
"""
|
1541
|
+
fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
|
1542
|
+
|
1543
|
+
https://doc.xt.com/#market10ticker24h
|
1544
|
+
https://doc.xt.com/#futures_quotesgetAggTickers
|
1545
|
+
|
1546
|
+
:param str [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
1547
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
1548
|
+
:returns dict: an array of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
|
1549
|
+
"""
|
1550
|
+
await self.load_markets()
|
1551
|
+
market = None
|
1552
|
+
if symbols is not None:
|
1553
|
+
symbols = self.market_symbols(symbols)
|
1554
|
+
market = self.market(symbols[0])
|
1555
|
+
request = {}
|
1556
|
+
type = None
|
1557
|
+
subType = None
|
1558
|
+
response = None
|
1559
|
+
type, params = self.handle_market_type_and_params('fetchTickers', market, params)
|
1560
|
+
subType, params = self.handle_sub_type_and_params('fetchTickers', market, params)
|
1561
|
+
if subType == 'inverse':
|
1562
|
+
response = await self.publicInverseGetFutureMarketV1PublicQAggTickers(self.extend(request, params))
|
1563
|
+
elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
|
1564
|
+
response = await self.publicLinearGetFutureMarketV1PublicQAggTickers(self.extend(request, params))
|
1565
|
+
else:
|
1566
|
+
response = await self.publicSpotGetTicker24h(self.extend(request, params))
|
1567
|
+
#
|
1568
|
+
# spot
|
1569
|
+
#
|
1570
|
+
# {
|
1571
|
+
# "rc": 0,
|
1572
|
+
# "mc": "SUCCESS",
|
1573
|
+
# "ma": [],
|
1574
|
+
# "result": [
|
1575
|
+
# {
|
1576
|
+
# "s": "btc_usdt",
|
1577
|
+
# "t": 1678172693931,
|
1578
|
+
# "cv": "34.00",
|
1579
|
+
# "cr": "0.0015",
|
1580
|
+
# "o": "22398.05",
|
1581
|
+
# "l": "22323.72",
|
1582
|
+
# "h": "22600.50",
|
1583
|
+
# "c": "22432.05",
|
1584
|
+
# "q": "7962.256931",
|
1585
|
+
# "v": "178675209.47416856"
|
1586
|
+
# }
|
1587
|
+
# ]
|
1588
|
+
# }
|
1589
|
+
#
|
1590
|
+
# swap and future
|
1591
|
+
#
|
1592
|
+
# {
|
1593
|
+
# "returnCode": 0,
|
1594
|
+
# "msgInfo": "success",
|
1595
|
+
# "error": null,
|
1596
|
+
# "result": [
|
1597
|
+
# {
|
1598
|
+
# "t": 1680738775108,
|
1599
|
+
# "s": "badger_usdt",
|
1600
|
+
# "c": "2.7176",
|
1601
|
+
# "h": "2.7917",
|
1602
|
+
# "l": "2.6818",
|
1603
|
+
# "a": "88332",
|
1604
|
+
# "v": "242286.3520",
|
1605
|
+
# "o": "2.7422",
|
1606
|
+
# "r": "-0.0089",
|
1607
|
+
# "i": "2.7155",
|
1608
|
+
# "m": "2.7161",
|
1609
|
+
# "bp": "2.7152",
|
1610
|
+
# "ap": "2.7176"
|
1611
|
+
# },
|
1612
|
+
# ]
|
1613
|
+
# }
|
1614
|
+
#
|
1615
|
+
tickers = self.safe_value(response, 'result', [])
|
1616
|
+
result = {}
|
1617
|
+
for i in range(0, len(tickers)):
|
1618
|
+
ticker = self.parse_ticker(tickers[i], market)
|
1619
|
+
symbol = ticker['symbol']
|
1620
|
+
result[symbol] = ticker
|
1621
|
+
return self.filter_by_array(result, 'symbol', symbols)
|
1622
|
+
|
1623
|
+
async def fetch_bids_asks(self, symbols: List[str] = None, params={}):
|
1624
|
+
"""
|
1625
|
+
fetches the bid and ask price and volume for multiple markets
|
1626
|
+
|
1627
|
+
https://doc.xt.com/#market9tickerBook
|
1628
|
+
|
1629
|
+
:param str [symbols]: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
|
1630
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
1631
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
|
1632
|
+
"""
|
1633
|
+
await self.load_markets()
|
1634
|
+
symbols = self.market_symbols(symbols)
|
1635
|
+
request = {}
|
1636
|
+
market = None
|
1637
|
+
if symbols is not None:
|
1638
|
+
market = self.market(symbols[0])
|
1639
|
+
subType = None
|
1640
|
+
subType, params = self.handle_sub_type_and_params('fetchBidsAsks', market, params)
|
1641
|
+
if subType is not None:
|
1642
|
+
raise NotSupported(self.id + ' fetchBidsAsks() is not available for swap and future markets, only spot markets are supported')
|
1643
|
+
response = await self.publicSpotGetTickerBook(self.extend(request, params))
|
1644
|
+
#
|
1645
|
+
# {
|
1646
|
+
# "rc": 0,
|
1647
|
+
# "mc": "SUCCESS",
|
1648
|
+
# "ma": [],
|
1649
|
+
# "result": [
|
1650
|
+
# {
|
1651
|
+
# "s": "kas_usdt",
|
1652
|
+
# "t": 1679539891853,
|
1653
|
+
# "ap": "0.016298",
|
1654
|
+
# "aq": "5119.09",
|
1655
|
+
# "bp": "0.016290",
|
1656
|
+
# "bq": "135.37"
|
1657
|
+
# },
|
1658
|
+
# ]
|
1659
|
+
# }
|
1660
|
+
#
|
1661
|
+
tickers = self.safe_value(response, 'result', [])
|
1662
|
+
return self.parse_tickers(tickers, symbols)
|
1663
|
+
|
1664
|
+
def parse_ticker(self, ticker, market=None):
|
1665
|
+
#
|
1666
|
+
# spot: fetchTicker, fetchTickers
|
1667
|
+
#
|
1668
|
+
# {
|
1669
|
+
# "s": "btc_usdt",
|
1670
|
+
# "t": 1678172693931,
|
1671
|
+
# "cv": "34.00",
|
1672
|
+
# "cr": "0.0015",
|
1673
|
+
# "o": "22398.05",
|
1674
|
+
# "l": "22323.72",
|
1675
|
+
# "h": "22600.50",
|
1676
|
+
# "c": "22432.05",
|
1677
|
+
# "q": "7962.256931",
|
1678
|
+
# "v": "178675209.47416856"
|
1679
|
+
# }
|
1680
|
+
#
|
1681
|
+
# swap and future: fetchTicker, fetchTickers
|
1682
|
+
#
|
1683
|
+
# {
|
1684
|
+
# "t": 1678172848572,
|
1685
|
+
# "s": "btc_usdt",
|
1686
|
+
# "c": "22415.5",
|
1687
|
+
# "h": "22590.0",
|
1688
|
+
# "l": "22310.0",
|
1689
|
+
# "a": "623654031",
|
1690
|
+
# "v": "1399166074.31675",
|
1691
|
+
# "o": "22381.5",
|
1692
|
+
# "r": "0.0015",
|
1693
|
+
# "i": "22424.5",
|
1694
|
+
# "m": "22416.5",
|
1695
|
+
# "bp": "22415",
|
1696
|
+
# "ap": "22415.5"
|
1697
|
+
# }
|
1698
|
+
#
|
1699
|
+
# fetchBidsAsks
|
1700
|
+
#
|
1701
|
+
# {
|
1702
|
+
# "s": "kas_usdt",
|
1703
|
+
# "t": 1679539891853,
|
1704
|
+
# "ap": "0.016298",
|
1705
|
+
# "aq": "5119.09",
|
1706
|
+
# "bp": "0.016290",
|
1707
|
+
# "bq": "135.37"
|
1708
|
+
# }
|
1709
|
+
#
|
1710
|
+
marketId = self.safe_string(ticker, 's')
|
1711
|
+
marketType = market['type'] if (market is not None) else None
|
1712
|
+
hasSpotKeys = ('cv' in ticker) or ('aq' in ticker)
|
1713
|
+
if marketType is None:
|
1714
|
+
marketType = 'spot' if hasSpotKeys else 'contract'
|
1715
|
+
market = self.safe_market(marketId, market, '_', marketType)
|
1716
|
+
symbol = market['symbol']
|
1717
|
+
timestamp = self.safe_integer(ticker, 't')
|
1718
|
+
percentage = self.safe_string_2(ticker, 'cr', 'r')
|
1719
|
+
if percentage is not None:
|
1720
|
+
percentage = Precise.string_mul(percentage, '100')
|
1721
|
+
return self.safe_ticker({
|
1722
|
+
'symbol': symbol,
|
1723
|
+
'timestamp': timestamp,
|
1724
|
+
'datetime': self.iso8601(timestamp),
|
1725
|
+
'high': self.safe_number(ticker, 'h'),
|
1726
|
+
'low': self.safe_number(ticker, 'l'),
|
1727
|
+
'bid': self.safe_number(ticker, 'bp'),
|
1728
|
+
'bidVolume': self.safe_number(ticker, 'bq'),
|
1729
|
+
'ask': self.safe_number(ticker, 'ap'),
|
1730
|
+
'askVolume': self.safe_number(ticker, 'aq'),
|
1731
|
+
'vwap': None,
|
1732
|
+
'open': self.safe_string(ticker, 'o'),
|
1733
|
+
'close': self.safe_string(ticker, 'c'),
|
1734
|
+
'last': self.safe_string(ticker, 'c'),
|
1735
|
+
'previousClose': None,
|
1736
|
+
'change': self.safe_number(ticker, 'cv'),
|
1737
|
+
'percentage': self.parse_number(percentage),
|
1738
|
+
'average': None,
|
1739
|
+
'baseVolume': None,
|
1740
|
+
'quoteVolume': self.safe_number_2(ticker, 'a', 'v'),
|
1741
|
+
'info': ticker,
|
1742
|
+
}, market)
|
1743
|
+
|
1744
|
+
async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}):
|
1745
|
+
"""
|
1746
|
+
get the list of most recent trades for a particular symbol
|
1747
|
+
|
1748
|
+
https://doc.xt.com/#market5tradeRecent
|
1749
|
+
https://doc.xt.com/#futures_quotesgetDeal
|
1750
|
+
|
1751
|
+
:param str symbol: unified market symbol to fetch trades for
|
1752
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
1753
|
+
:param int [limit]: the maximum amount of trades to fetch
|
1754
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
1755
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
|
1756
|
+
"""
|
1757
|
+
await self.load_markets()
|
1758
|
+
market = self.market(symbol)
|
1759
|
+
request = {
|
1760
|
+
'symbol': market['id'],
|
1761
|
+
}
|
1762
|
+
response = None
|
1763
|
+
if market['spot']:
|
1764
|
+
if limit is not None:
|
1765
|
+
request['limit'] = limit
|
1766
|
+
response = await self.publicSpotGetTradeRecent(self.extend(request, params))
|
1767
|
+
else:
|
1768
|
+
if limit is not None:
|
1769
|
+
request['num'] = limit
|
1770
|
+
if market['linear']:
|
1771
|
+
response = await self.publicLinearGetFutureMarketV1PublicQDeal(self.extend(request, params))
|
1772
|
+
elif market['inverse']:
|
1773
|
+
response = await self.publicInverseGetFutureMarketV1PublicQDeal(self.extend(request, params))
|
1774
|
+
#
|
1775
|
+
# spot
|
1776
|
+
#
|
1777
|
+
# {
|
1778
|
+
# "rc": 0,
|
1779
|
+
# "mc": "SUCCESS",
|
1780
|
+
# "ma": [],
|
1781
|
+
# "result": [
|
1782
|
+
# {
|
1783
|
+
# "i": 203530723141917063,
|
1784
|
+
# "t": 1678227505815,
|
1785
|
+
# "p": "22038.81",
|
1786
|
+
# "q": "0.000978",
|
1787
|
+
# "v": "21.55395618",
|
1788
|
+
# "b": True
|
1789
|
+
# },
|
1790
|
+
# ]
|
1791
|
+
# }
|
1792
|
+
#
|
1793
|
+
# swap and future
|
1794
|
+
#
|
1795
|
+
# {
|
1796
|
+
# "returnCode": 0,
|
1797
|
+
# "msgInfo": "success",
|
1798
|
+
# "error": null,
|
1799
|
+
# "result": [
|
1800
|
+
# {
|
1801
|
+
# "t": 1678227683897,
|
1802
|
+
# "s": "btc_usdt",
|
1803
|
+
# "p": "22031",
|
1804
|
+
# "a": "1067",
|
1805
|
+
# "m": "BID"
|
1806
|
+
# },
|
1807
|
+
# ]
|
1808
|
+
# }
|
1809
|
+
#
|
1810
|
+
trades = self.safe_value(response, 'result', [])
|
1811
|
+
return self.parse_trades(trades, market)
|
1812
|
+
|
1813
|
+
async def fetch_my_trades(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
|
1814
|
+
"""
|
1815
|
+
fetch all trades made by the user
|
1816
|
+
|
1817
|
+
https://doc.xt.com/#tradetradeGet
|
1818
|
+
https://doc.xt.com/#futures_ordergetTrades
|
1819
|
+
|
1820
|
+
:param str [symbol]: unified market symbol to fetch trades for
|
1821
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
1822
|
+
:param int [limit]: the maximum amount of trades to fetch
|
1823
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
1824
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
|
1825
|
+
"""
|
1826
|
+
await self.load_markets()
|
1827
|
+
request = {}
|
1828
|
+
market = None
|
1829
|
+
if symbol is not None:
|
1830
|
+
market = self.market(symbol)
|
1831
|
+
request['symbol'] = market['id']
|
1832
|
+
if since is not None:
|
1833
|
+
request['startTime'] = since
|
1834
|
+
type = None
|
1835
|
+
subType = None
|
1836
|
+
response = None
|
1837
|
+
type, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
|
1838
|
+
subType, params = self.handle_sub_type_and_params('fetchMyTrades', market, params)
|
1839
|
+
if (subType is not None) or (type == 'swap') or (type == 'future'):
|
1840
|
+
if limit is not None:
|
1841
|
+
request['size'] = limit
|
1842
|
+
if subType == 'inverse':
|
1843
|
+
response = await self.privateInverseGetFutureTradeV1OrderTradeList(self.extend(request, params))
|
1844
|
+
else:
|
1845
|
+
response = await self.privateLinearGetFutureTradeV1OrderTradeList(self.extend(request, params))
|
1846
|
+
else:
|
1847
|
+
marginMode = None
|
1848
|
+
marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
|
1849
|
+
marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
|
1850
|
+
request['bizType'] = marginOrSpotRequest
|
1851
|
+
if limit is not None:
|
1852
|
+
request['limit'] = limit
|
1853
|
+
response = await self.privateSpotGetTrade(self.extend(request, params))
|
1854
|
+
#
|
1855
|
+
# spot and margin
|
1856
|
+
#
|
1857
|
+
# {
|
1858
|
+
# "rc": 0,
|
1859
|
+
# "mc": "SUCCESS",
|
1860
|
+
# "ma": [],
|
1861
|
+
# "result": {
|
1862
|
+
# "hasPrev": False,
|
1863
|
+
# "hasNext": False,
|
1864
|
+
# "items": [
|
1865
|
+
# {
|
1866
|
+
# "symbol": "btc_usdt",
|
1867
|
+
# "tradeId": "206906233569974658",
|
1868
|
+
# "orderId": "206906233178463488",
|
1869
|
+
# "orderSide": "SELL",
|
1870
|
+
# "orderType": "MARKET",
|
1871
|
+
# "bizType": "SPOT",
|
1872
|
+
# "time": 1679032290215,
|
1873
|
+
# "price": "25703.46",
|
1874
|
+
# "quantity": "0.000099",
|
1875
|
+
# "quoteQty": "2.54464254",
|
1876
|
+
# "baseCurrency": "btc",
|
1877
|
+
# "quoteCurrency": "usdt",
|
1878
|
+
# "fee": "0.00508929",
|
1879
|
+
# "feeCurrency": "usdt",
|
1880
|
+
# "takerMaker": "TAKER"
|
1881
|
+
# },
|
1882
|
+
# ]
|
1883
|
+
# }
|
1884
|
+
# }
|
1885
|
+
#
|
1886
|
+
# swap and future
|
1887
|
+
#
|
1888
|
+
# {
|
1889
|
+
# "returnCode": 0,
|
1890
|
+
# "msgInfo": "success",
|
1891
|
+
# "error": null,
|
1892
|
+
# "result": {
|
1893
|
+
# "page": 1,
|
1894
|
+
# "ps": 10,
|
1895
|
+
# "total": 2,
|
1896
|
+
# "items": [
|
1897
|
+
# {
|
1898
|
+
# "orderId": "207260566170987200",
|
1899
|
+
# "execId": "207260566790603265",
|
1900
|
+
# "symbol": "btc_usdt",
|
1901
|
+
# "quantity": "13",
|
1902
|
+
# "price": "27368",
|
1903
|
+
# "fee": "0.02134704",
|
1904
|
+
# "feeCoin": "usdt",
|
1905
|
+
# "timestamp": 1679116769838,
|
1906
|
+
# "takerMaker": "TAKER"
|
1907
|
+
# },
|
1908
|
+
# ]
|
1909
|
+
# }
|
1910
|
+
# }
|
1911
|
+
#
|
1912
|
+
data = self.safe_value(response, 'result', {})
|
1913
|
+
trades = self.safe_value(data, 'items', [])
|
1914
|
+
return self.parse_trades(trades, market, since, limit)
|
1915
|
+
|
1916
|
+
def parse_trade(self, trade, market=None):
|
1917
|
+
#
|
1918
|
+
# spot: fetchTrades
|
1919
|
+
#
|
1920
|
+
# {
|
1921
|
+
# "i": 203530723141917063,
|
1922
|
+
# "t": 1678227505815,
|
1923
|
+
# "p": "22038.81",
|
1924
|
+
# "q": "0.000978",
|
1925
|
+
# "v": "21.55395618",
|
1926
|
+
# "b": True
|
1927
|
+
# }
|
1928
|
+
#
|
1929
|
+
# spot: watchTrades
|
1930
|
+
#
|
1931
|
+
# {
|
1932
|
+
# s: 'btc_usdt',
|
1933
|
+
# i: '228825383103928709',
|
1934
|
+
# t: 1684258222702,
|
1935
|
+
# p: '27003.65',
|
1936
|
+
# q: '0.000796',
|
1937
|
+
# b: True
|
1938
|
+
# }
|
1939
|
+
#
|
1940
|
+
# spot: watchMyTrades
|
1941
|
+
#
|
1942
|
+
# {
|
1943
|
+
# "s": "btc_usdt", # symbol
|
1944
|
+
# "t": 1656043204763, # time
|
1945
|
+
# "i": "6316559590087251233", # tradeId
|
1946
|
+
# "oi": "6216559590087220004", # orderId
|
1947
|
+
# "p": "30000", # trade price
|
1948
|
+
# "q": "3", # qty quantity
|
1949
|
+
# "v": "90000" # volume trade amount
|
1950
|
+
# }
|
1951
|
+
#
|
1952
|
+
# swap and future: fetchTrades
|
1953
|
+
#
|
1954
|
+
# {
|
1955
|
+
# "t": 1678227683897,
|
1956
|
+
# "s": "btc_usdt",
|
1957
|
+
# "p": "22031",
|
1958
|
+
# "a": "1067",
|
1959
|
+
# "m": "BID"
|
1960
|
+
# }
|
1961
|
+
#
|
1962
|
+
# spot: fetchMyTrades
|
1963
|
+
#
|
1964
|
+
# {
|
1965
|
+
# "symbol": "btc_usdt",
|
1966
|
+
# "tradeId": "206906233569974658",
|
1967
|
+
# "orderId": "206906233178463488",
|
1968
|
+
# "orderSide": "SELL",
|
1969
|
+
# "orderType": "MARKET",
|
1970
|
+
# "bizType": "SPOT",
|
1971
|
+
# "time": 1679032290215,
|
1972
|
+
# "price": "25703.46",
|
1973
|
+
# "quantity": "0.000099",
|
1974
|
+
# "quoteQty": "2.54464254",
|
1975
|
+
# "baseCurrency": "btc",
|
1976
|
+
# "quoteCurrency": "usdt",
|
1977
|
+
# "fee": "0.00508929",
|
1978
|
+
# "feeCurrency": "usdt",
|
1979
|
+
# "takerMaker": "TAKER"
|
1980
|
+
# }
|
1981
|
+
#
|
1982
|
+
# swap and future: fetchMyTrades
|
1983
|
+
#
|
1984
|
+
# {
|
1985
|
+
# "orderId": "207260566170987200",
|
1986
|
+
# "execId": "207260566790603265",
|
1987
|
+
# "symbol": "btc_usdt",
|
1988
|
+
# "quantity": "13",
|
1989
|
+
# "price": "27368",
|
1990
|
+
# "fee": "0.02134704",
|
1991
|
+
# "feeCoin": "usdt",
|
1992
|
+
# "timestamp": 1679116769838,
|
1993
|
+
# "takerMaker": "TAKER"
|
1994
|
+
# }
|
1995
|
+
#
|
1996
|
+
# contract watchMyTrades
|
1997
|
+
#
|
1998
|
+
# {
|
1999
|
+
# "symbol": 'btc_usdt',
|
2000
|
+
# "orderSide": 'SELL',
|
2001
|
+
# "positionSide": 'LONG',
|
2002
|
+
# "orderId": '231485367663419328',
|
2003
|
+
# "price": '27152.7',
|
2004
|
+
# "quantity": '33',
|
2005
|
+
# "marginUnfrozen": '2.85318000',
|
2006
|
+
# "timestamp": 1684892412565
|
2007
|
+
# }
|
2008
|
+
#
|
2009
|
+
# watchMyTrades(ws, swap)
|
2010
|
+
#
|
2011
|
+
# {
|
2012
|
+
# 'fee': '0.04080840',
|
2013
|
+
# 'isMaker': False,
|
2014
|
+
# 'marginUnfrozen': '0.75711984',
|
2015
|
+
# 'orderId': '376172779053188416',
|
2016
|
+
# 'orderSide': 'BUY',
|
2017
|
+
# 'positionSide': 'LONG',
|
2018
|
+
# 'price': '3400.70',
|
2019
|
+
# 'quantity': '2',
|
2020
|
+
# 'symbol': 'eth_usdt',
|
2021
|
+
# 'timestamp': 1719388579622
|
2022
|
+
# }
|
2023
|
+
#
|
2024
|
+
marketId = self.safe_string_2(trade, 's', 'symbol')
|
2025
|
+
marketType = market['type'] if (market is not None) else None
|
2026
|
+
hasSpotKeys = ('b' in trade) or ('bizType' in trade) or ('oi' in trade)
|
2027
|
+
if marketType is None:
|
2028
|
+
marketType = 'spot' if hasSpotKeys else 'contract'
|
2029
|
+
market = self.safe_market(marketId, market, '_', marketType)
|
2030
|
+
side = None
|
2031
|
+
takerOrMaker = None
|
2032
|
+
isBuyerMaker = self.safe_bool(trade, 'b')
|
2033
|
+
if isBuyerMaker is not None:
|
2034
|
+
side = 'sell' if isBuyerMaker else 'buy'
|
2035
|
+
takerOrMaker = 'taker' # public trades always taker
|
2036
|
+
else:
|
2037
|
+
takerMaker = self.safe_string_lower(trade, 'takerMaker')
|
2038
|
+
if takerMaker is not None:
|
2039
|
+
takerOrMaker = takerMaker
|
2040
|
+
else:
|
2041
|
+
isMaker = self.safe_bool(trade, 'isMaker')
|
2042
|
+
if isMaker is not None:
|
2043
|
+
takerOrMaker = 'maker' if isMaker else 'taker'
|
2044
|
+
orderSide = self.safe_string_lower(trade, 'orderSide')
|
2045
|
+
if orderSide is not None:
|
2046
|
+
side = orderSide
|
2047
|
+
else:
|
2048
|
+
bidOrAsk = self.safe_string(trade, 'm')
|
2049
|
+
if bidOrAsk is not None:
|
2050
|
+
side = 'buy' if (bidOrAsk == 'BID') else 'sell'
|
2051
|
+
timestamp = self.safe_integer_n(trade, ['t', 'time', 'timestamp'])
|
2052
|
+
quantity = self.safe_string_2(trade, 'q', 'quantity')
|
2053
|
+
amount = None
|
2054
|
+
if marketType == 'spot':
|
2055
|
+
amount = quantity
|
2056
|
+
else:
|
2057
|
+
if quantity is None:
|
2058
|
+
amount = Precise.string_mul(self.safe_string(trade, 'a'), self.number_to_string(market['contractSize']))
|
2059
|
+
else:
|
2060
|
+
amount = Precise.string_mul(quantity, self.number_to_string(market['contractSize']))
|
2061
|
+
return self.safe_trade({
|
2062
|
+
'info': trade,
|
2063
|
+
'id': self.safe_string_n(trade, ['i', 'tradeId', 'execId']),
|
2064
|
+
'timestamp': timestamp,
|
2065
|
+
'datetime': self.iso8601(timestamp),
|
2066
|
+
'symbol': market['symbol'],
|
2067
|
+
'order': self.safe_string_2(trade, 'orderId', 'oi'),
|
2068
|
+
'type': self.safe_string_lower(trade, 'orderType'),
|
2069
|
+
'side': side,
|
2070
|
+
'takerOrMaker': takerOrMaker,
|
2071
|
+
'price': self.safe_string_2(trade, 'p', 'price'),
|
2072
|
+
'amount': amount,
|
2073
|
+
'cost': None,
|
2074
|
+
'fee': {
|
2075
|
+
'currency': self.safe_currency_code(self.safe_string_2(trade, 'feeCurrency', 'feeCoin')),
|
2076
|
+
'cost': self.safe_string(trade, 'fee'),
|
2077
|
+
},
|
2078
|
+
}, market)
|
2079
|
+
|
2080
|
+
async def fetch_balance(self, params={}):
|
2081
|
+
"""
|
2082
|
+
query for balance and get the amount of funds available for trading or funds locked in orders
|
2083
|
+
|
2084
|
+
https://doc.xt.com/#balancebalancesGet
|
2085
|
+
https://doc.xt.com/#futures_usergetBalances
|
2086
|
+
|
2087
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
2088
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
|
2089
|
+
"""
|
2090
|
+
await self.load_markets()
|
2091
|
+
type = None
|
2092
|
+
subType = None
|
2093
|
+
response = None
|
2094
|
+
type, params = self.handle_market_type_and_params('fetchBalance', None, params)
|
2095
|
+
subType, params = self.handle_sub_type_and_params('fetchBalance', None, params)
|
2096
|
+
isContractWallet = ((type == 'swap') or (type == 'future'))
|
2097
|
+
if subType == 'inverse':
|
2098
|
+
response = await self.privateInverseGetFutureUserV1BalanceList(params)
|
2099
|
+
elif (subType == 'linear') or isContractWallet:
|
2100
|
+
response = await self.privateLinearGetFutureUserV1BalanceList(params)
|
2101
|
+
else:
|
2102
|
+
response = await self.privateSpotGetBalances(params)
|
2103
|
+
#
|
2104
|
+
# spot
|
2105
|
+
#
|
2106
|
+
# {
|
2107
|
+
# "rc": 0,
|
2108
|
+
# "mc": "SUCCESS",
|
2109
|
+
# "ma": [],
|
2110
|
+
# "result": {
|
2111
|
+
# "totalUsdtAmount": "31.75931133",
|
2112
|
+
# "totalBtcAmount": "0.00115951",
|
2113
|
+
# "assets": [
|
2114
|
+
# {
|
2115
|
+
# "currency": "usdt",
|
2116
|
+
# "currencyId": 11,
|
2117
|
+
# "frozenAmount": "0.03834082",
|
2118
|
+
# "availableAmount": "31.70995965",
|
2119
|
+
# "totalAmount": "31.74830047",
|
2120
|
+
# "convertBtcAmount": "0.00115911",
|
2121
|
+
# "convertUsdtAmount": "31.74830047"
|
2122
|
+
# },
|
2123
|
+
# ]
|
2124
|
+
# }
|
2125
|
+
# }
|
2126
|
+
#
|
2127
|
+
# swap and future
|
2128
|
+
#
|
2129
|
+
# {
|
2130
|
+
# "returnCode": 0,
|
2131
|
+
# "msgInfo": "success",
|
2132
|
+
# "error": null,
|
2133
|
+
# "result": [
|
2134
|
+
# {
|
2135
|
+
# "coin": "usdt",
|
2136
|
+
# "walletBalance": "19.29849875",
|
2137
|
+
# "openOrderMarginFrozen": "0",
|
2138
|
+
# "isolatedMargin": "0.709475",
|
2139
|
+
# "crossedMargin": "0",
|
2140
|
+
# "availableBalance": "18.58902375",
|
2141
|
+
# "bonus": "0",
|
2142
|
+
# "coupon":"0"
|
2143
|
+
# }
|
2144
|
+
# ]
|
2145
|
+
# }
|
2146
|
+
#
|
2147
|
+
balances = None
|
2148
|
+
if (subType is not None) or isContractWallet:
|
2149
|
+
balances = self.safe_value(response, 'result', [])
|
2150
|
+
else:
|
2151
|
+
data = self.safe_value(response, 'result', {})
|
2152
|
+
balances = self.safe_value(data, 'assets', [])
|
2153
|
+
return self.parse_balance(balances)
|
2154
|
+
|
2155
|
+
def parse_balance(self, response):
|
2156
|
+
#
|
2157
|
+
# spot
|
2158
|
+
#
|
2159
|
+
# {
|
2160
|
+
# "currency": "usdt",
|
2161
|
+
# "currencyId": 11,
|
2162
|
+
# "frozenAmount": "0.03834082",
|
2163
|
+
# "availableAmount": "31.70995965",
|
2164
|
+
# "totalAmount": "31.74830047",
|
2165
|
+
# "convertBtcAmount": "0.00115911",
|
2166
|
+
# "convertUsdtAmount": "31.74830047"
|
2167
|
+
# }
|
2168
|
+
#
|
2169
|
+
# swap and future
|
2170
|
+
#
|
2171
|
+
# {
|
2172
|
+
# "coin": "usdt",
|
2173
|
+
# "walletBalance": "19.29849875",
|
2174
|
+
# "openOrderMarginFrozen": "0",
|
2175
|
+
# "isolatedMargin": "0.709475",
|
2176
|
+
# "crossedMargin": "0",
|
2177
|
+
# "availableBalance": "18.58902375",
|
2178
|
+
# "bonus": "0",
|
2179
|
+
# "coupon":"0"
|
2180
|
+
# }
|
2181
|
+
#
|
2182
|
+
result = {'info': response}
|
2183
|
+
for i in range(0, len(response)):
|
2184
|
+
balance = response[i]
|
2185
|
+
currencyId = self.safe_string_2(balance, 'currency', 'coin')
|
2186
|
+
code = self.safe_currency_code(currencyId)
|
2187
|
+
account = self.account()
|
2188
|
+
free = self.safe_string_2(balance, 'availableAmount', 'availableBalance')
|
2189
|
+
used = self.safe_string(balance, 'frozenAmount')
|
2190
|
+
total = self.safe_string_2(balance, 'totalAmount', 'walletBalance')
|
2191
|
+
if used is None:
|
2192
|
+
crossedAndIsolatedMargin = Precise.string_add(self.safe_string(balance, 'crossedMargin'), self.safe_string(balance, 'isolatedMargin'))
|
2193
|
+
used = Precise.string_add(self.safe_string(balance, 'openOrderMarginFrozen'), crossedAndIsolatedMargin)
|
2194
|
+
account['free'] = free
|
2195
|
+
account['used'] = used
|
2196
|
+
account['total'] = total
|
2197
|
+
result[code] = account
|
2198
|
+
return self.safe_balance(result)
|
2199
|
+
|
2200
|
+
async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
|
2201
|
+
"""
|
2202
|
+
|
2203
|
+
https://doc.xt.com/#orderorderPost
|
2204
|
+
|
2205
|
+
create a market buy order by providing the symbol and cost
|
2206
|
+
:param str symbol: unified symbol of the market to create an order in
|
2207
|
+
:param float cost: how much you want to trade in units of the quote currency
|
2208
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2209
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
2210
|
+
"""
|
2211
|
+
await self.load_markets()
|
2212
|
+
market = self.market(symbol)
|
2213
|
+
if not market['spot']:
|
2214
|
+
raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
|
2215
|
+
return await self.create_order(symbol, 'market', 'buy', cost, 1, params)
|
2216
|
+
|
2217
|
+
async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
2218
|
+
"""
|
2219
|
+
create a trade order
|
2220
|
+
|
2221
|
+
https://doc.xt.com/#orderorderPost
|
2222
|
+
https://doc.xt.com/#futures_ordercreate
|
2223
|
+
https://doc.xt.com/#futures_entrustcreatePlan
|
2224
|
+
https://doc.xt.com/#futures_entrustcreateProfit
|
2225
|
+
|
2226
|
+
:param str symbol: unified symbol of the market to create an order in
|
2227
|
+
:param str type: 'market' or 'limit'
|
2228
|
+
:param str side: 'buy' or 'sell'
|
2229
|
+
:param float amount: how much you want to trade in units of the base currency
|
2230
|
+
:param float [price]: the price to fulfill the order, in units of the quote currency, can be ignored in market orders
|
2231
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
2232
|
+
:param str [params.timeInForce]: 'GTC', 'IOC', 'FOK' or 'GTX'
|
2233
|
+
:param str [params.entrustType]: 'TAKE_PROFIT', 'STOP', 'TAKE_PROFIT_MARKET', 'STOP_MARKET', 'TRAILING_STOP_MARKET', required if stopPrice is defined, currently isn't functioning on xt's side
|
2234
|
+
:param str [params.triggerPriceType]: 'INDEX_PRICE', 'MARK_PRICE', 'LATEST_PRICE', required if stopPrice is defined
|
2235
|
+
:param float [params.triggerPrice]: price to trigger a stop order
|
2236
|
+
:param float [params.stopPrice]: alias for triggerPrice
|
2237
|
+
:param float [params.stopLoss]: price to set a stop-loss on an open position
|
2238
|
+
:param float [params.takeProfit]: price to set a take-profit on an open position
|
2239
|
+
:returns dict: an `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
2240
|
+
"""
|
2241
|
+
await self.load_markets()
|
2242
|
+
market = self.market(symbol)
|
2243
|
+
symbol = market['symbol']
|
2244
|
+
if market['spot']:
|
2245
|
+
return await self.create_spot_order(symbol, type, side, amount, price, params)
|
2246
|
+
else:
|
2247
|
+
return await self.create_contract_order(symbol, type, side, amount, price, params)
|
2248
|
+
|
2249
|
+
async def create_spot_order(self, symbol: str, type, side, amount, price=None, params={}):
|
2250
|
+
await self.load_markets()
|
2251
|
+
market = self.market(symbol)
|
2252
|
+
request = {
|
2253
|
+
'symbol': market['id'],
|
2254
|
+
'side': side.upper(),
|
2255
|
+
'type': type.upper(),
|
2256
|
+
}
|
2257
|
+
timeInForce = None
|
2258
|
+
marginMode = None
|
2259
|
+
marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
|
2260
|
+
marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
|
2261
|
+
request['bizType'] = marginOrSpotRequest
|
2262
|
+
if type == 'market':
|
2263
|
+
timeInForce = self.safe_string_upper(params, 'timeInForce', 'FOK')
|
2264
|
+
if side == 'buy':
|
2265
|
+
cost = self.safe_string(params, 'cost')
|
2266
|
+
params = self.omit(params, 'cost')
|
2267
|
+
createMarketBuyOrderRequiresPrice = self.safe_bool(self.options, 'createMarketBuyOrderRequiresPrice', True)
|
2268
|
+
if createMarketBuyOrderRequiresPrice:
|
2269
|
+
if price is None and (cost is None):
|
2270
|
+
raise InvalidOrder(self.id + ' createOrder() requires a price argument or cost in params for market buy orders on spot markets to calculate the total amount to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option to False and pass in the cost to spend into the amount parameter')
|
2271
|
+
else:
|
2272
|
+
amountString = self.number_to_string(amount)
|
2273
|
+
priceString = self.number_to_string(price)
|
2274
|
+
costCalculated: Str = None
|
2275
|
+
if price is not None:
|
2276
|
+
costCalculated = Precise.string_mul(amountString, priceString)
|
2277
|
+
else:
|
2278
|
+
costCalculated = cost
|
2279
|
+
request['quoteQty'] = self.cost_to_precision(symbol, costCalculated)
|
2280
|
+
else:
|
2281
|
+
amountCost = cost if (cost is not None) else amount
|
2282
|
+
request['quoteQty'] = self.cost_to_precision(symbol, amountCost)
|
2283
|
+
else:
|
2284
|
+
timeInForce = self.safe_string_upper(params, 'timeInForce', 'GTC')
|
2285
|
+
request['price'] = self.price_to_precision(symbol, price)
|
2286
|
+
if (side == 'sell') or (type == 'limit'):
|
2287
|
+
request['quantity'] = self.amount_to_precision(symbol, amount)
|
2288
|
+
request['timeInForce'] = timeInForce
|
2289
|
+
response = await self.privateSpotPostOrder(self.extend(request, params))
|
2290
|
+
#
|
2291
|
+
# {
|
2292
|
+
# "rc": 0,
|
2293
|
+
# "mc": "SUCCESS",
|
2294
|
+
# "ma": [],
|
2295
|
+
# "result": {
|
2296
|
+
# "orderId": "204371980095156544"
|
2297
|
+
# }
|
2298
|
+
# }
|
2299
|
+
#
|
2300
|
+
order = self.safe_value(response, 'result', {})
|
2301
|
+
return self.parse_order(order, market)
|
2302
|
+
|
2303
|
+
async def create_contract_order(self, symbol: str, type, side, amount, price=None, params={}):
|
2304
|
+
await self.load_markets()
|
2305
|
+
market = self.market(symbol)
|
2306
|
+
request = {
|
2307
|
+
'symbol': market['id'],
|
2308
|
+
'origQty': self.amount_to_precision(symbol, amount),
|
2309
|
+
}
|
2310
|
+
timeInForce = self.safe_string_upper(params, 'timeInForce')
|
2311
|
+
if timeInForce is not None:
|
2312
|
+
request['timeInForce'] = timeInForce
|
2313
|
+
reduceOnly = self.safe_value(params, 'reduceOnly', False)
|
2314
|
+
if side == 'buy':
|
2315
|
+
requestType = 'SHORT' if (reduceOnly) else 'LONG'
|
2316
|
+
request['positionSide'] = requestType
|
2317
|
+
else:
|
2318
|
+
requestType = 'LONG' if (reduceOnly) else 'SHORT'
|
2319
|
+
request['positionSide'] = requestType
|
2320
|
+
response = None
|
2321
|
+
triggerPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
|
2322
|
+
stopLoss = self.safe_number_2(params, 'stopLoss', 'triggerStopPrice')
|
2323
|
+
takeProfit = self.safe_number_2(params, 'takeProfit', 'triggerProfitPrice')
|
2324
|
+
isTrigger = (triggerPrice is not None)
|
2325
|
+
isStopLoss = (stopLoss is not None)
|
2326
|
+
isTakeProfit = (takeProfit is not None)
|
2327
|
+
if price is not None:
|
2328
|
+
if not (isStopLoss) and not (isTakeProfit):
|
2329
|
+
request['price'] = self.price_to_precision(symbol, price)
|
2330
|
+
if isTrigger:
|
2331
|
+
request['timeInForce'] = self.safe_string_upper(params, 'timeInForce', 'GTC')
|
2332
|
+
request['triggerPriceType'] = self.safe_string(params, 'triggerPriceType', 'LATEST_PRICE')
|
2333
|
+
request['orderSide'] = side.upper()
|
2334
|
+
request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
|
2335
|
+
entrustType = 'STOP_MARKET' if (type == 'market') else 'STOP'
|
2336
|
+
request['entrustType'] = entrustType
|
2337
|
+
params = self.omit(params, 'triggerPrice')
|
2338
|
+
if market['linear']:
|
2339
|
+
response = await self.privateLinearPostFutureTradeV1EntrustCreatePlan(self.extend(request, params))
|
2340
|
+
elif market['inverse']:
|
2341
|
+
response = await self.privateInversePostFutureTradeV1EntrustCreatePlan(self.extend(request, params))
|
2342
|
+
elif isStopLoss or isTakeProfit:
|
2343
|
+
if isStopLoss:
|
2344
|
+
request['triggerStopPrice'] = self.price_to_precision(symbol, stopLoss)
|
2345
|
+
else:
|
2346
|
+
request['triggerProfitPrice'] = self.price_to_precision(symbol, takeProfit)
|
2347
|
+
params = self.omit(params, ['stopLoss', 'takeProfit'])
|
2348
|
+
if market['linear']:
|
2349
|
+
response = await self.privateLinearPostFutureTradeV1EntrustCreateProfit(self.extend(request, params))
|
2350
|
+
elif market['inverse']:
|
2351
|
+
response = await self.privateInversePostFutureTradeV1EntrustCreateProfit(self.extend(request, params))
|
2352
|
+
else:
|
2353
|
+
request['orderSide'] = side.upper()
|
2354
|
+
request['orderType'] = type.upper()
|
2355
|
+
if market['linear']:
|
2356
|
+
response = await self.privateLinearPostFutureTradeV1OrderCreate(self.extend(request, params))
|
2357
|
+
elif market['inverse']:
|
2358
|
+
response = await self.privateInversePostFutureTradeV1OrderCreate(self.extend(request, params))
|
2359
|
+
#
|
2360
|
+
# {
|
2361
|
+
# "returnCode": 0,
|
2362
|
+
# "msgInfo": "success",
|
2363
|
+
# "error": null,
|
2364
|
+
# "result": "206410760006650176"
|
2365
|
+
# }
|
2366
|
+
#
|
2367
|
+
return self.parse_order(response, market)
|
2368
|
+
|
2369
|
+
async def fetch_order(self, id: str, symbol: str = None, params={}):
|
2370
|
+
"""
|
2371
|
+
fetches information on an order made by the user
|
2372
|
+
|
2373
|
+
https://doc.xt.com/#orderorderGet
|
2374
|
+
https://doc.xt.com/#futures_ordergetById
|
2375
|
+
https://doc.xt.com/#futures_entrustgetPlanById
|
2376
|
+
https://doc.xt.com/#futures_entrustgetProfitById
|
2377
|
+
|
2378
|
+
:param str id: order id
|
2379
|
+
:param str [symbol]: unified symbol of the market the order was made in
|
2380
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
2381
|
+
:param bool [params.trigger]: if the order is a trigger order or not
|
2382
|
+
:param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
|
2383
|
+
:returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
2384
|
+
"""
|
2385
|
+
await self.load_markets()
|
2386
|
+
market = None
|
2387
|
+
if symbol is not None:
|
2388
|
+
market = self.market(symbol)
|
2389
|
+
request = {}
|
2390
|
+
type = None
|
2391
|
+
subType = None
|
2392
|
+
response = None
|
2393
|
+
type, params = self.handle_market_type_and_params('fetchOrder', market, params)
|
2394
|
+
subType, params = self.handle_sub_type_and_params('fetchOrder', market, params)
|
2395
|
+
trigger = self.safe_value(params, 'stop')
|
2396
|
+
stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
|
2397
|
+
if trigger:
|
2398
|
+
request['entrustId'] = id
|
2399
|
+
elif stopLossTakeProfit:
|
2400
|
+
request['profitId'] = id
|
2401
|
+
else:
|
2402
|
+
request['orderId'] = id
|
2403
|
+
if trigger:
|
2404
|
+
params = self.omit(params, 'stop')
|
2405
|
+
if subType == 'inverse':
|
2406
|
+
response = await self.privateInverseGetFutureTradeV1EntrustPlanDetail(self.extend(request, params))
|
2407
|
+
else:
|
2408
|
+
response = await self.privateLinearGetFutureTradeV1EntrustPlanDetail(self.extend(request, params))
|
2409
|
+
elif stopLossTakeProfit:
|
2410
|
+
params = self.omit(params, 'stopLossTakeProfit')
|
2411
|
+
if subType == 'inverse':
|
2412
|
+
response = await self.privateInverseGetFutureTradeV1EntrustProfitDetail(self.extend(request, params))
|
2413
|
+
else:
|
2414
|
+
response = await self.privateLinearGetFutureTradeV1EntrustProfitDetail(self.extend(request, params))
|
2415
|
+
elif subType == 'inverse':
|
2416
|
+
response = await self.privateInverseGetFutureTradeV1OrderDetail(self.extend(request, params))
|
2417
|
+
elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
|
2418
|
+
response = await self.privateLinearGetFutureTradeV1OrderDetail(self.extend(request, params))
|
2419
|
+
else:
|
2420
|
+
response = await self.privateSpotGetOrderOrderId(self.extend(request, params))
|
2421
|
+
#
|
2422
|
+
# spot
|
2423
|
+
#
|
2424
|
+
# {
|
2425
|
+
# "rc": 0,
|
2426
|
+
# "mc": "SUCCESS",
|
2427
|
+
# "ma": [],
|
2428
|
+
# "result": {
|
2429
|
+
# "symbol": "btc_usdt",
|
2430
|
+
# "orderId": "207505997850909952",
|
2431
|
+
# "clientOrderId": null,
|
2432
|
+
# "baseCurrency": "btc",
|
2433
|
+
# "quoteCurrency": "usdt",
|
2434
|
+
# "side": "BUY",
|
2435
|
+
# "type": "LIMIT",
|
2436
|
+
# "timeInForce": "GTC",
|
2437
|
+
# "price": "20000.00",
|
2438
|
+
# "origQty": "0.001000",
|
2439
|
+
# "origQuoteQty": "20.00",
|
2440
|
+
# "executedQty": "0.000000",
|
2441
|
+
# "leavingQty": "0.001000",
|
2442
|
+
# "tradeBase": "0.000000",
|
2443
|
+
# "tradeQuote": "0.00",
|
2444
|
+
# "avgPrice": null,
|
2445
|
+
# "fee": null,
|
2446
|
+
# "feeCurrency": null,
|
2447
|
+
# "closed": False,
|
2448
|
+
# "state": "NEW",
|
2449
|
+
# "time": 1679175285162,
|
2450
|
+
# "updatedTime": 1679175285255
|
2451
|
+
# }
|
2452
|
+
# }
|
2453
|
+
#
|
2454
|
+
# swap and future
|
2455
|
+
#
|
2456
|
+
# {
|
2457
|
+
# "returnCode": 0,
|
2458
|
+
# "msgInfo": "success",
|
2459
|
+
# "error": null,
|
2460
|
+
# "result": {
|
2461
|
+
# "orderId": "211451874783183936",
|
2462
|
+
# "clientOrderId": null,
|
2463
|
+
# "symbol": "btc_usdt",
|
2464
|
+
# "orderType": "LIMIT",
|
2465
|
+
# "orderSide": "BUY",
|
2466
|
+
# "positionSide": "LONG",
|
2467
|
+
# "timeInForce": "GTC",
|
2468
|
+
# "closePosition": False,
|
2469
|
+
# "price": "20000",
|
2470
|
+
# "origQty": "10",
|
2471
|
+
# "avgPrice": "0",
|
2472
|
+
# "executedQty": "0",
|
2473
|
+
# "marginFrozen": "1.34533334",
|
2474
|
+
# "remark": null,
|
2475
|
+
# "triggerProfitPrice": null,
|
2476
|
+
# "triggerStopPrice": null,
|
2477
|
+
# "sourceId": null,
|
2478
|
+
# "sourceType": "DEFAULT",
|
2479
|
+
# "forceClose": False,
|
2480
|
+
# "closeProfit": null,
|
2481
|
+
# "state": "NEW",
|
2482
|
+
# "createdTime": 1680116055693,
|
2483
|
+
# "updatedTime": 1680116055693
|
2484
|
+
# }
|
2485
|
+
# }
|
2486
|
+
#
|
2487
|
+
# trigger
|
2488
|
+
#
|
2489
|
+
# {
|
2490
|
+
# "returnCode": 0,
|
2491
|
+
# "msgInfo": "success",
|
2492
|
+
# "error": null,
|
2493
|
+
# "result": {
|
2494
|
+
# "entrustId": "216300248132756992",
|
2495
|
+
# "symbol": "btc_usdt",
|
2496
|
+
# "entrustType": "STOP",
|
2497
|
+
# "orderSide": "SELL",
|
2498
|
+
# "positionSide": "SHORT",
|
2499
|
+
# "timeInForce": "GTC",
|
2500
|
+
# "closePosition": null,
|
2501
|
+
# "price": "20000",
|
2502
|
+
# "origQty": "1",
|
2503
|
+
# "stopPrice": "19000",
|
2504
|
+
# "triggerPriceType": "LATEST_PRICE",
|
2505
|
+
# "state": "NOT_TRIGGERED",
|
2506
|
+
# "marketOrderLevel": null,
|
2507
|
+
# "createdTime": 1681271998064,
|
2508
|
+
# "updatedTime": 1681271998064,
|
2509
|
+
# "ordinary": False
|
2510
|
+
# }
|
2511
|
+
# }
|
2512
|
+
#
|
2513
|
+
# stop-loss and take-profit
|
2514
|
+
#
|
2515
|
+
# {
|
2516
|
+
# "returnCode": 0,
|
2517
|
+
# "msgInfo": "success",
|
2518
|
+
# "error": null,
|
2519
|
+
# "result": {
|
2520
|
+
# "profitId": "216306213226230400",
|
2521
|
+
# "symbol": "btc_usdt",
|
2522
|
+
# "positionSide": "LONG",
|
2523
|
+
# "origQty": "1",
|
2524
|
+
# "triggerPriceType": "LATEST_PRICE",
|
2525
|
+
# "triggerProfitPrice": null,
|
2526
|
+
# "triggerStopPrice": "20000",
|
2527
|
+
# "entryPrice": null,
|
2528
|
+
# "positionSize": null,
|
2529
|
+
# "isolatedMargin": null,
|
2530
|
+
# "executedQty": null,
|
2531
|
+
# "avgPrice": null,
|
2532
|
+
# "positionType": "ISOLATED",
|
2533
|
+
# "state": "NOT_TRIGGERED",
|
2534
|
+
# "createdTime": 1681273420039
|
2535
|
+
# }
|
2536
|
+
# }
|
2537
|
+
#
|
2538
|
+
order = self.safe_value(response, 'result', {})
|
2539
|
+
return self.parse_order(order, market)
|
2540
|
+
|
2541
|
+
async def fetch_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
|
2542
|
+
"""
|
2543
|
+
fetches information on multiple orders made by the user
|
2544
|
+
|
2545
|
+
https://doc.xt.com/#orderhistoryOrderGet
|
2546
|
+
https://doc.xt.com/#futures_ordergetHistory
|
2547
|
+
https://doc.xt.com/#futures_entrustgetPlanHistory
|
2548
|
+
|
2549
|
+
:param str [symbol]: unified market symbol of the market the orders were made in
|
2550
|
+
:param int [since]: timestamp in ms of the earliest order
|
2551
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
2552
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
2553
|
+
:param bool [params.trigger]: if the order is a trigger order or not
|
2554
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
2555
|
+
"""
|
2556
|
+
await self.load_markets()
|
2557
|
+
request = {}
|
2558
|
+
market = None
|
2559
|
+
if symbol is not None:
|
2560
|
+
market = self.market(symbol)
|
2561
|
+
request['symbol'] = market['id']
|
2562
|
+
if since is not None:
|
2563
|
+
request['startTime'] = since
|
2564
|
+
if limit is not None:
|
2565
|
+
request['limit'] = limit
|
2566
|
+
type = None
|
2567
|
+
subType = None
|
2568
|
+
response = None
|
2569
|
+
type, params = self.handle_market_type_and_params('fetchOrders', market, params)
|
2570
|
+
subType, params = self.handle_sub_type_and_params('fetchOrders', market, params)
|
2571
|
+
trigger = self.safe_value_2(params, 'trigger', 'stop')
|
2572
|
+
if trigger:
|
2573
|
+
params = self.omit(params, ['trigger', 'stop'])
|
2574
|
+
if subType == 'inverse':
|
2575
|
+
response = await self.privateInverseGetFutureTradeV1EntrustPlanListHistory(self.extend(request, params))
|
2576
|
+
else:
|
2577
|
+
response = await self.privateLinearGetFutureTradeV1EntrustPlanListHistory(self.extend(request, params))
|
2578
|
+
elif subType == 'inverse':
|
2579
|
+
response = await self.privateInverseGetFutureTradeV1OrderListHistory(self.extend(request, params))
|
2580
|
+
elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
|
2581
|
+
response = await self.privateLinearGetFutureTradeV1OrderListHistory(self.extend(request, params))
|
2582
|
+
else:
|
2583
|
+
marginMode = None
|
2584
|
+
marginMode, params = self.handle_margin_mode_and_params('fetchOrders', params)
|
2585
|
+
marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
|
2586
|
+
request['bizType'] = marginOrSpotRequest
|
2587
|
+
response = await self.privateSpotGetHistoryOrder(self.extend(request, params))
|
2588
|
+
#
|
2589
|
+
# spot and margin
|
2590
|
+
#
|
2591
|
+
# {
|
2592
|
+
# "rc": 0,
|
2593
|
+
# "mc": "SUCCESS",
|
2594
|
+
# "ma": [],
|
2595
|
+
# "result": {
|
2596
|
+
# "hasPrev": False,
|
2597
|
+
# "hasNext": True,
|
2598
|
+
# "items": [
|
2599
|
+
# {
|
2600
|
+
# "symbol": "btc_usdt",
|
2601
|
+
# "orderId": "207505997850909952",
|
2602
|
+
# "clientOrderId": null,
|
2603
|
+
# "baseCurrency": "btc",
|
2604
|
+
# "quoteCurrency": "usdt",
|
2605
|
+
# "side": "BUY",
|
2606
|
+
# "type": "LIMIT",
|
2607
|
+
# "timeInForce": "GTC",
|
2608
|
+
# "price": "20000.00",
|
2609
|
+
# "origQty": "0.001000",
|
2610
|
+
# "origQuoteQty": "20.00",
|
2611
|
+
# "executedQty": "0.000000",
|
2612
|
+
# "leavingQty": "0.000000",
|
2613
|
+
# "tradeBase": "0.000000",
|
2614
|
+
# "tradeQuote": "0.00",
|
2615
|
+
# "avgPrice": null,
|
2616
|
+
# "fee": null,
|
2617
|
+
# "feeCurrency": null,
|
2618
|
+
# "closed": True,
|
2619
|
+
# "state": "CANCELED",
|
2620
|
+
# "time": 1679175285162,
|
2621
|
+
# "updatedTime": 1679175488492
|
2622
|
+
# },
|
2623
|
+
# ]
|
2624
|
+
# }
|
2625
|
+
# }
|
2626
|
+
#
|
2627
|
+
# swap and future
|
2628
|
+
#
|
2629
|
+
# {
|
2630
|
+
# "returnCode": 0,
|
2631
|
+
# "msgInfo": "success",
|
2632
|
+
# "error": null,
|
2633
|
+
# "result": {
|
2634
|
+
# "hasPrev": False,
|
2635
|
+
# "hasNext": True,
|
2636
|
+
# "items": [
|
2637
|
+
# {
|
2638
|
+
# "orderId": "207519546930995456",
|
2639
|
+
# "clientOrderId": null,
|
2640
|
+
# "symbol": "btc_usdt",
|
2641
|
+
# "orderType": "LIMIT",
|
2642
|
+
# "orderSide": "BUY",
|
2643
|
+
# "positionSide": "LONG",
|
2644
|
+
# "timeInForce": "GTC",
|
2645
|
+
# "closePosition": False,
|
2646
|
+
# "price": "20000",
|
2647
|
+
# "origQty": "100",
|
2648
|
+
# "avgPrice": "0",
|
2649
|
+
# "executedQty": "0",
|
2650
|
+
# "marginFrozen": "4.12",
|
2651
|
+
# "remark": null,
|
2652
|
+
# "triggerProfitPrice": null,
|
2653
|
+
# "triggerStopPrice": null,
|
2654
|
+
# "sourceId": null,
|
2655
|
+
# "sourceType": "DEFAULT",
|
2656
|
+
# "forceClose": False,
|
2657
|
+
# "closeProfit": null,
|
2658
|
+
# "state": "CANCELED",
|
2659
|
+
# "createdTime": 1679178515689,
|
2660
|
+
# "updatedTime": 1679180096172
|
2661
|
+
# },
|
2662
|
+
# ]
|
2663
|
+
# }
|
2664
|
+
# }
|
2665
|
+
#
|
2666
|
+
# stop
|
2667
|
+
#
|
2668
|
+
# {
|
2669
|
+
# "returnCode": 0,
|
2670
|
+
# "msgInfo": "success",
|
2671
|
+
# "error": null,
|
2672
|
+
# "result": {
|
2673
|
+
# "hasPrev": False,
|
2674
|
+
# "hasNext": False,
|
2675
|
+
# "items": [
|
2676
|
+
# {
|
2677
|
+
# "entrustId": "216300248132756992",
|
2678
|
+
# "symbol": "btc_usdt",
|
2679
|
+
# "entrustType": "STOP",
|
2680
|
+
# "orderSide": "SELL",
|
2681
|
+
# "positionSide": "SHORT",
|
2682
|
+
# "timeInForce": "GTC",
|
2683
|
+
# "closePosition": null,
|
2684
|
+
# "price": "20000",
|
2685
|
+
# "origQty": "1",
|
2686
|
+
# "stopPrice": "19000",
|
2687
|
+
# "triggerPriceType": "LATEST_PRICE",
|
2688
|
+
# "state": "USER_REVOCATION",
|
2689
|
+
# "marketOrderLevel": null,
|
2690
|
+
# "createdTime": 1681271998064,
|
2691
|
+
# "updatedTime": 1681273188674,
|
2692
|
+
# "ordinary": False
|
2693
|
+
# },
|
2694
|
+
# ]
|
2695
|
+
# }
|
2696
|
+
# }
|
2697
|
+
#
|
2698
|
+
data = self.safe_value(response, 'result', {})
|
2699
|
+
orders = self.safe_value(data, 'items', [])
|
2700
|
+
return self.parse_orders(orders, market, since, limit)
|
2701
|
+
|
2702
|
+
async def fetch_orders_by_status(self, status, symbol: str = None, since: Int = None, limit: Int = None, params={}):
|
2703
|
+
await self.load_markets()
|
2704
|
+
request = {}
|
2705
|
+
market = None
|
2706
|
+
if symbol is not None:
|
2707
|
+
market = self.market(symbol)
|
2708
|
+
request['symbol'] = market['id']
|
2709
|
+
type = None
|
2710
|
+
subType = None
|
2711
|
+
response = None
|
2712
|
+
type, params = self.handle_market_type_and_params('fetchOrdersByStatus', market, params)
|
2713
|
+
subType, params = self.handle_sub_type_and_params('fetchOrdersByStatus', market, params)
|
2714
|
+
trigger = self.safe_value(params, 'stop')
|
2715
|
+
stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
|
2716
|
+
if status == 'open':
|
2717
|
+
if trigger or stopLossTakeProfit:
|
2718
|
+
request['state'] = 'NOT_TRIGGERED'
|
2719
|
+
elif subType is not None:
|
2720
|
+
request['state'] = 'NEW'
|
2721
|
+
elif status == 'closed':
|
2722
|
+
if trigger or stopLossTakeProfit:
|
2723
|
+
request['state'] = 'TRIGGERED'
|
2724
|
+
else:
|
2725
|
+
request['state'] = 'FILLED'
|
2726
|
+
elif status == 'canceled':
|
2727
|
+
if trigger or stopLossTakeProfit:
|
2728
|
+
request['state'] = 'USER_REVOCATION'
|
2729
|
+
else:
|
2730
|
+
request['state'] = 'CANCELED'
|
2731
|
+
else:
|
2732
|
+
request['state'] = status
|
2733
|
+
if trigger or stopLossTakeProfit or (subType is not None) or (type == 'swap') or (type == 'future'):
|
2734
|
+
if since is not None:
|
2735
|
+
request['startTime'] = since
|
2736
|
+
if limit is not None:
|
2737
|
+
request['size'] = limit
|
2738
|
+
if trigger:
|
2739
|
+
params = self.omit(params, 'stop')
|
2740
|
+
if subType == 'inverse':
|
2741
|
+
response = await self.privateInverseGetFutureTradeV1EntrustPlanList(self.extend(request, params))
|
2742
|
+
else:
|
2743
|
+
response = await self.privateLinearGetFutureTradeV1EntrustPlanList(self.extend(request, params))
|
2744
|
+
elif stopLossTakeProfit:
|
2745
|
+
params = self.omit(params, 'stopLossTakeProfit')
|
2746
|
+
if subType == 'inverse':
|
2747
|
+
response = await self.privateInverseGetFutureTradeV1EntrustProfitList(self.extend(request, params))
|
2748
|
+
else:
|
2749
|
+
response = await self.privateLinearGetFutureTradeV1EntrustProfitList(self.extend(request, params))
|
2750
|
+
elif (subType is not None) or (type == 'swap') or (type == 'future'):
|
2751
|
+
if subType == 'inverse':
|
2752
|
+
response = await self.privateInverseGetFutureTradeV1OrderList(self.extend(request, params))
|
2753
|
+
else:
|
2754
|
+
response = await self.privateLinearGetFutureTradeV1OrderList(self.extend(request, params))
|
2755
|
+
else:
|
2756
|
+
marginMode = None
|
2757
|
+
marginMode, params = self.handle_margin_mode_and_params('fetchOrdersByStatus', params)
|
2758
|
+
marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
|
2759
|
+
request['bizType'] = marginOrSpotRequest
|
2760
|
+
if status != 'open':
|
2761
|
+
if since is not None:
|
2762
|
+
request['startTime'] = since
|
2763
|
+
if limit is not None:
|
2764
|
+
request['limit'] = limit
|
2765
|
+
response = await self.privateSpotGetHistoryOrder(self.extend(request, params))
|
2766
|
+
else:
|
2767
|
+
response = await self.privateSpotGetOpenOrder(self.extend(request, params))
|
2768
|
+
#
|
2769
|
+
# spot and margin
|
2770
|
+
#
|
2771
|
+
# {
|
2772
|
+
# "rc": 0,
|
2773
|
+
# "mc": "SUCCESS",
|
2774
|
+
# "ma": [],
|
2775
|
+
# "result": {
|
2776
|
+
# "hasPrev": False,
|
2777
|
+
# "hasNext": True,
|
2778
|
+
# "items": [
|
2779
|
+
# {
|
2780
|
+
# "symbol": "btc_usdt",
|
2781
|
+
# "orderId": "207505997850909952",
|
2782
|
+
# "clientOrderId": null,
|
2783
|
+
# "baseCurrency": "btc",
|
2784
|
+
# "quoteCurrency": "usdt",
|
2785
|
+
# "side": "BUY",
|
2786
|
+
# "type": "LIMIT",
|
2787
|
+
# "timeInForce": "GTC",
|
2788
|
+
# "price": "20000.00",
|
2789
|
+
# "origQty": "0.001000",
|
2790
|
+
# "origQuoteQty": "20.00",
|
2791
|
+
# "executedQty": "0.000000",
|
2792
|
+
# "leavingQty": "0.000000",
|
2793
|
+
# "tradeBase": "0.000000",
|
2794
|
+
# "tradeQuote": "0.00",
|
2795
|
+
# "avgPrice": null,
|
2796
|
+
# "fee": null,
|
2797
|
+
# "feeCurrency": null,
|
2798
|
+
# "closed": True,
|
2799
|
+
# "state": "CANCELED",
|
2800
|
+
# "time": 1679175285162,
|
2801
|
+
# "updatedTime": 1679175488492
|
2802
|
+
# },
|
2803
|
+
# ]
|
2804
|
+
# }
|
2805
|
+
# }
|
2806
|
+
#
|
2807
|
+
# spot and margin: fetchOpenOrders
|
2808
|
+
#
|
2809
|
+
# {
|
2810
|
+
# "rc": 0,
|
2811
|
+
# "mc": "SUCCESS",
|
2812
|
+
# "ma": [],
|
2813
|
+
# "result": [
|
2814
|
+
# {
|
2815
|
+
# "symbol": "eth_usdt",
|
2816
|
+
# "orderId": "208249323222264320",
|
2817
|
+
# "clientOrderId": null,
|
2818
|
+
# "baseCurrency": "eth",
|
2819
|
+
# "quoteCurrency": "usdt",
|
2820
|
+
# "side": "BUY",
|
2821
|
+
# "type": "LIMIT",
|
2822
|
+
# "timeInForce": "GTC",
|
2823
|
+
# "price": "1300.00",
|
2824
|
+
# "origQty": "0.0032",
|
2825
|
+
# "origQuoteQty": "4.16",
|
2826
|
+
# "executedQty": "0.0000",
|
2827
|
+
# "leavingQty": "0.0032",
|
2828
|
+
# "tradeBase": "0.0000",
|
2829
|
+
# "tradeQuote": "0.00",
|
2830
|
+
# "avgPrice": null,
|
2831
|
+
# "fee": null,
|
2832
|
+
# "feeCurrency": null,
|
2833
|
+
# "closed": False,
|
2834
|
+
# "state": "NEW",
|
2835
|
+
# "time": 1679352507741,
|
2836
|
+
# "updatedTime": 1679352507869
|
2837
|
+
# },
|
2838
|
+
# ]
|
2839
|
+
# }
|
2840
|
+
#
|
2841
|
+
# swap and future
|
2842
|
+
#
|
2843
|
+
# {
|
2844
|
+
# "returnCode": 0,
|
2845
|
+
# "msgInfo": "success",
|
2846
|
+
# "error": null,
|
2847
|
+
# "result": {
|
2848
|
+
# "page": 1,
|
2849
|
+
# "ps": 10,
|
2850
|
+
# "total": 25,
|
2851
|
+
# "items": [
|
2852
|
+
# {
|
2853
|
+
# "orderId": "207519546930995456",
|
2854
|
+
# "clientOrderId": null,
|
2855
|
+
# "symbol": "btc_usdt",
|
2856
|
+
# "orderType": "LIMIT",
|
2857
|
+
# "orderSide": "BUY",
|
2858
|
+
# "positionSide": "LONG",
|
2859
|
+
# "timeInForce": "GTC",
|
2860
|
+
# "closePosition": False,
|
2861
|
+
# "price": "20000",
|
2862
|
+
# "origQty": "100",
|
2863
|
+
# "avgPrice": "0",
|
2864
|
+
# "executedQty": "0",
|
2865
|
+
# "marginFrozen": "4.12",
|
2866
|
+
# "remark": null,
|
2867
|
+
# "triggerProfitPrice": null,
|
2868
|
+
# "triggerStopPrice": null,
|
2869
|
+
# "sourceId": null,
|
2870
|
+
# "sourceType": "DEFAULT",
|
2871
|
+
# "forceClose": False,
|
2872
|
+
# "closeProfit": null,
|
2873
|
+
# "state": "CANCELED",
|
2874
|
+
# "createdTime": 1679178515689,
|
2875
|
+
# "updatedTime": 1679180096172
|
2876
|
+
# },
|
2877
|
+
# ]
|
2878
|
+
# }
|
2879
|
+
# }
|
2880
|
+
#
|
2881
|
+
# stop
|
2882
|
+
#
|
2883
|
+
# {
|
2884
|
+
# "returnCode": 0,
|
2885
|
+
# "msgInfo": "success",
|
2886
|
+
# "error": null,
|
2887
|
+
# "result": {
|
2888
|
+
# "page": 1,
|
2889
|
+
# "ps": 3,
|
2890
|
+
# "total": 8,
|
2891
|
+
# "items": [
|
2892
|
+
# {
|
2893
|
+
# "entrustId": "216300248132756992",
|
2894
|
+
# "symbol": "btc_usdt",
|
2895
|
+
# "entrustType": "STOP",
|
2896
|
+
# "orderSide": "SELL",
|
2897
|
+
# "positionSide": "SHORT",
|
2898
|
+
# "timeInForce": "GTC",
|
2899
|
+
# "closePosition": null,
|
2900
|
+
# "price": "20000",
|
2901
|
+
# "origQty": "1",
|
2902
|
+
# "stopPrice": "19000",
|
2903
|
+
# "triggerPriceType": "LATEST_PRICE",
|
2904
|
+
# "state": "USER_REVOCATION",
|
2905
|
+
# "marketOrderLevel": null,
|
2906
|
+
# "createdTime": 1681271998064,
|
2907
|
+
# "updatedTime": 1681273188674,
|
2908
|
+
# "ordinary": False
|
2909
|
+
# },
|
2910
|
+
# ]
|
2911
|
+
# }
|
2912
|
+
# }
|
2913
|
+
#
|
2914
|
+
# stop-loss and take-profit
|
2915
|
+
#
|
2916
|
+
# {
|
2917
|
+
# "returnCode": 0,
|
2918
|
+
# "msgInfo": "success",
|
2919
|
+
# "error": null,
|
2920
|
+
# "result": {
|
2921
|
+
# "page": 1,
|
2922
|
+
# "ps": 3,
|
2923
|
+
# "total": 2,
|
2924
|
+
# "items": [
|
2925
|
+
# {
|
2926
|
+
# "profitId": "216306213226230400",
|
2927
|
+
# "symbol": "btc_usdt",
|
2928
|
+
# "positionSide": "LONG",
|
2929
|
+
# "origQty": "1",
|
2930
|
+
# "triggerPriceType": "LATEST_PRICE",
|
2931
|
+
# "triggerProfitPrice": null,
|
2932
|
+
# "triggerStopPrice": "20000",
|
2933
|
+
# "entryPrice": "0",
|
2934
|
+
# "positionSize": "0",
|
2935
|
+
# "isolatedMargin": "0",
|
2936
|
+
# "executedQty": "0",
|
2937
|
+
# "avgPrice": null,
|
2938
|
+
# "positionType": "ISOLATED",
|
2939
|
+
# "state": "USER_REVOCATION",
|
2940
|
+
# "createdTime": 1681273420039
|
2941
|
+
# },
|
2942
|
+
# ]
|
2943
|
+
# }
|
2944
|
+
# }
|
2945
|
+
#
|
2946
|
+
isSpotOpenOrders = ((status == 'open') and (subType is None))
|
2947
|
+
data = self.safe_value(response, 'result', {})
|
2948
|
+
orders = self.safe_value(response, 'result', []) if isSpotOpenOrders else self.safe_value(data, 'items', [])
|
2949
|
+
return self.parse_orders(orders, market, since, limit)
|
2950
|
+
|
2951
|
+
async def fetch_open_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
|
2952
|
+
"""
|
2953
|
+
fetch all unfilled currently open orders
|
2954
|
+
|
2955
|
+
https://doc.xt.com/#orderopenOrderGet
|
2956
|
+
https://doc.xt.com/#futures_ordergetOrders
|
2957
|
+
https://doc.xt.com/#futures_entrustgetPlan
|
2958
|
+
https://doc.xt.com/#futures_entrustgetProfit
|
2959
|
+
|
2960
|
+
:param str [symbol]: unified market symbol of the market the orders were made in
|
2961
|
+
:param int [since]: timestamp in ms of the earliest order
|
2962
|
+
:param int [limit]: the maximum number of open order structures to retrieve
|
2963
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
2964
|
+
:param bool [params.trigger]: if the order is a trigger order or not
|
2965
|
+
:param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
|
2966
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
2967
|
+
"""
|
2968
|
+
return await self.fetch_orders_by_status('open', symbol, since, limit, params)
|
2969
|
+
|
2970
|
+
async def fetch_closed_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
|
2971
|
+
"""
|
2972
|
+
fetches information on multiple closed orders made by the user
|
2973
|
+
|
2974
|
+
https://doc.xt.com/#orderhistoryOrderGet
|
2975
|
+
https://doc.xt.com/#futures_ordergetOrders
|
2976
|
+
https://doc.xt.com/#futures_entrustgetPlan
|
2977
|
+
https://doc.xt.com/#futures_entrustgetProfit
|
2978
|
+
|
2979
|
+
:param str [symbol]: unified market symbol of the market the orders were made in
|
2980
|
+
:param int [since]: timestamp in ms of the earliest order
|
2981
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
2982
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
2983
|
+
:param bool [params.trigger]: if the order is a trigger order or not
|
2984
|
+
:param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
|
2985
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
2986
|
+
"""
|
2987
|
+
return await self.fetch_orders_by_status('closed', symbol, since, limit, params)
|
2988
|
+
|
2989
|
+
async def fetch_canceled_orders(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
|
2990
|
+
"""
|
2991
|
+
fetches information on multiple canceled orders made by the user
|
2992
|
+
|
2993
|
+
https://doc.xt.com/#orderhistoryOrderGet
|
2994
|
+
https://doc.xt.com/#futures_ordergetOrders
|
2995
|
+
https://doc.xt.com/#futures_entrustgetPlan
|
2996
|
+
https://doc.xt.com/#futures_entrustgetProfit
|
2997
|
+
|
2998
|
+
:param str [symbol]: unified market symbol of the market the orders were made in
|
2999
|
+
:param int [since]: timestamp in ms of the earliest order
|
3000
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
3001
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3002
|
+
:param bool [params.trigger]: if the order is a trigger order or not
|
3003
|
+
:param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
|
3004
|
+
:returns dict: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
3005
|
+
"""
|
3006
|
+
return await self.fetch_orders_by_status('canceled', symbol, since, limit, params)
|
3007
|
+
|
3008
|
+
async def cancel_order(self, id: str, symbol: str = None, params={}):
|
3009
|
+
"""
|
3010
|
+
cancels an open order
|
3011
|
+
|
3012
|
+
https://doc.xt.com/#orderorderDel
|
3013
|
+
https://doc.xt.com/#futures_ordercancel
|
3014
|
+
https://doc.xt.com/#futures_entrustcancelPlan
|
3015
|
+
https://doc.xt.com/#futures_entrustcancelProfit
|
3016
|
+
|
3017
|
+
:param str id: order id
|
3018
|
+
:param str [symbol]: unified symbol of the market the order was made in
|
3019
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3020
|
+
:param bool [params.trigger]: if the order is a trigger order or not
|
3021
|
+
:param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
|
3022
|
+
:returns dict: An `order structure <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
3023
|
+
"""
|
3024
|
+
await self.load_markets()
|
3025
|
+
market = None
|
3026
|
+
if symbol is not None:
|
3027
|
+
market = self.market(symbol)
|
3028
|
+
request = {}
|
3029
|
+
type = None
|
3030
|
+
subType = None
|
3031
|
+
response = None
|
3032
|
+
type, params = self.handle_market_type_and_params('cancelOrder', market, params)
|
3033
|
+
subType, params = self.handle_sub_type_and_params('cancelOrder', market, params)
|
3034
|
+
trigger = self.safe_value_2(params, 'trigger', 'stop')
|
3035
|
+
stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
|
3036
|
+
if trigger:
|
3037
|
+
request['entrustId'] = id
|
3038
|
+
elif stopLossTakeProfit:
|
3039
|
+
request['profitId'] = id
|
3040
|
+
else:
|
3041
|
+
request['orderId'] = id
|
3042
|
+
if trigger:
|
3043
|
+
params = self.omit(params, ['trigger', 'stop'])
|
3044
|
+
if subType == 'inverse':
|
3045
|
+
response = await self.privateInversePostFutureTradeV1EntrustCancelPlan(self.extend(request, params))
|
3046
|
+
else:
|
3047
|
+
response = await self.privateLinearPostFutureTradeV1EntrustCancelPlan(self.extend(request, params))
|
3048
|
+
elif stopLossTakeProfit:
|
3049
|
+
params = self.omit(params, 'stopLossTakeProfit')
|
3050
|
+
if subType == 'inverse':
|
3051
|
+
response = await self.privateInversePostFutureTradeV1EntrustCancelProfitStop(self.extend(request, params))
|
3052
|
+
else:
|
3053
|
+
response = await self.privateLinearPostFutureTradeV1EntrustCancelProfitStop(self.extend(request, params))
|
3054
|
+
elif subType == 'inverse':
|
3055
|
+
response = await self.privateInversePostFutureTradeV1OrderCancel(self.extend(request, params))
|
3056
|
+
elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
|
3057
|
+
response = await self.privateLinearPostFutureTradeV1OrderCancel(self.extend(request, params))
|
3058
|
+
else:
|
3059
|
+
response = await self.privateSpotDeleteOrderOrderId(self.extend(request, params))
|
3060
|
+
#
|
3061
|
+
# spot
|
3062
|
+
#
|
3063
|
+
# {
|
3064
|
+
# "rc": 0,
|
3065
|
+
# "mc": "SUCCESS",
|
3066
|
+
# "ma": [],
|
3067
|
+
# "result": {
|
3068
|
+
# "cancelId": "208322474307982720"
|
3069
|
+
# }
|
3070
|
+
# }
|
3071
|
+
#
|
3072
|
+
# swap and future
|
3073
|
+
#
|
3074
|
+
# {
|
3075
|
+
# "returnCode": 0,
|
3076
|
+
# "msgInfo": "success",
|
3077
|
+
# "error": null,
|
3078
|
+
# "result": "208319789679471616"
|
3079
|
+
# }
|
3080
|
+
#
|
3081
|
+
isContractResponse = ((subType is not None) or (type == 'swap') or (type == 'future'))
|
3082
|
+
order = response if isContractResponse else self.safe_value(response, 'result', {})
|
3083
|
+
return self.parse_order(order, market)
|
3084
|
+
|
3085
|
+
async def cancel_all_orders(self, symbol: str = None, params={}):
|
3086
|
+
"""
|
3087
|
+
cancel all open orders in a market
|
3088
|
+
|
3089
|
+
https://doc.xt.com/#orderopenOrderDel
|
3090
|
+
https://doc.xt.com/#futures_ordercancelBatch
|
3091
|
+
https://doc.xt.com/#futures_entrustcancelPlanBatch
|
3092
|
+
https://doc.xt.com/#futures_entrustcancelProfitBatch
|
3093
|
+
|
3094
|
+
:param str [symbol]: unified market symbol of the market to cancel orders in
|
3095
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3096
|
+
:param bool [params.trigger]: if the order is a trigger order or not
|
3097
|
+
:param bool [params.stopLossTakeProfit]: if the order is a stop-loss or take-profit order
|
3098
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
3099
|
+
"""
|
3100
|
+
await self.load_markets()
|
3101
|
+
request = {}
|
3102
|
+
market = None
|
3103
|
+
if symbol is not None:
|
3104
|
+
market = self.market(symbol)
|
3105
|
+
request['symbol'] = market['id']
|
3106
|
+
type = None
|
3107
|
+
subType = None
|
3108
|
+
response = None
|
3109
|
+
type, params = self.handle_market_type_and_params('cancelAllOrders', market, params)
|
3110
|
+
subType, params = self.handle_sub_type_and_params('cancelAllOrders', market, params)
|
3111
|
+
trigger = self.safe_value_2(params, 'trigger', 'stop')
|
3112
|
+
stopLossTakeProfit = self.safe_value(params, 'stopLossTakeProfit')
|
3113
|
+
if trigger:
|
3114
|
+
params = self.omit(params, ['trigger', 'stop'])
|
3115
|
+
if subType == 'inverse':
|
3116
|
+
response = await self.privateInversePostFutureTradeV1EntrustCancelAllPlan(self.extend(request, params))
|
3117
|
+
else:
|
3118
|
+
response = await self.privateLinearPostFutureTradeV1EntrustCancelAllPlan(self.extend(request, params))
|
3119
|
+
elif stopLossTakeProfit:
|
3120
|
+
params = self.omit(params, 'stopLossTakeProfit')
|
3121
|
+
if subType == 'inverse':
|
3122
|
+
response = await self.privateInversePostFutureTradeV1EntrustCancelAllProfitStop(self.extend(request, params))
|
3123
|
+
else:
|
3124
|
+
response = await self.privateLinearPostFutureTradeV1EntrustCancelAllProfitStop(self.extend(request, params))
|
3125
|
+
elif subType == 'inverse':
|
3126
|
+
response = await self.privateInversePostFutureTradeV1OrderCancelAll(self.extend(request, params))
|
3127
|
+
elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
|
3128
|
+
response = await self.privateLinearPostFutureTradeV1OrderCancelAll(self.extend(request, params))
|
3129
|
+
else:
|
3130
|
+
marginMode = None
|
3131
|
+
marginMode, params = self.handle_margin_mode_and_params('cancelAllOrders', params)
|
3132
|
+
marginOrSpotRequest = 'LEVER' if (marginMode is not None) else 'SPOT'
|
3133
|
+
request['bizType'] = marginOrSpotRequest
|
3134
|
+
response = await self.privateSpotDeleteOpenOrder(self.extend(request, params))
|
3135
|
+
#
|
3136
|
+
# spot and margin
|
3137
|
+
#
|
3138
|
+
# {
|
3139
|
+
# "rc": 0,
|
3140
|
+
# "mc": "SUCCESS",
|
3141
|
+
# "ma": [],
|
3142
|
+
# "result": null
|
3143
|
+
# }
|
3144
|
+
#
|
3145
|
+
# swap and future
|
3146
|
+
#
|
3147
|
+
# {
|
3148
|
+
# "returnCode": 0,
|
3149
|
+
# "msgInfo": "success",
|
3150
|
+
# "error": null,
|
3151
|
+
# "result": True
|
3152
|
+
# }
|
3153
|
+
#
|
3154
|
+
return [
|
3155
|
+
self.safe_order(response),
|
3156
|
+
]
|
3157
|
+
|
3158
|
+
async def cancel_orders(self, ids: List[str], symbol: str = None, params={}) -> List[Order]:
|
3159
|
+
"""
|
3160
|
+
cancel multiple orders
|
3161
|
+
|
3162
|
+
https://doc.xt.com/#orderbatchOrderDel
|
3163
|
+
|
3164
|
+
:param str[] ids: order ids
|
3165
|
+
:param str [symbol]: unified market symbol of the market to cancel orders in
|
3166
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3167
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/en/latest/manual.html#order-structure>`
|
3168
|
+
"""
|
3169
|
+
await self.load_markets()
|
3170
|
+
request = {
|
3171
|
+
'orderIds': ids,
|
3172
|
+
}
|
3173
|
+
market = None
|
3174
|
+
if symbol is not None:
|
3175
|
+
market = self.market(symbol)
|
3176
|
+
subType = None
|
3177
|
+
subType, params = self.handle_sub_type_and_params('cancelOrders', market, params)
|
3178
|
+
if subType is not None:
|
3179
|
+
raise NotSupported(self.id + ' cancelOrders() does not support swap and future orders, only spot orders are accepted')
|
3180
|
+
response = await self.privateSpotDeleteBatchOrder(self.extend(request, params))
|
3181
|
+
#
|
3182
|
+
# spot
|
3183
|
+
#
|
3184
|
+
# {
|
3185
|
+
# "rc": 0,
|
3186
|
+
# "mc": "SUCCESS",
|
3187
|
+
# "ma": [],
|
3188
|
+
# "result": null
|
3189
|
+
# }
|
3190
|
+
#
|
3191
|
+
return [
|
3192
|
+
self.safe_order(response),
|
3193
|
+
]
|
3194
|
+
|
3195
|
+
def parse_order(self, order, market=None):
|
3196
|
+
#
|
3197
|
+
# spot: createOrder
|
3198
|
+
#
|
3199
|
+
# {
|
3200
|
+
# "orderId": "204371980095156544"
|
3201
|
+
# }
|
3202
|
+
#
|
3203
|
+
# spot: cancelOrder
|
3204
|
+
#
|
3205
|
+
# {
|
3206
|
+
# "cancelId": "208322474307982720"
|
3207
|
+
# }
|
3208
|
+
#
|
3209
|
+
# swap and future: createOrder, cancelOrder
|
3210
|
+
#
|
3211
|
+
# {
|
3212
|
+
# "returnCode": 0,
|
3213
|
+
# "msgInfo": "success",
|
3214
|
+
# "error": null,
|
3215
|
+
# "result": "206410760006650176"
|
3216
|
+
# }
|
3217
|
+
#
|
3218
|
+
# spot: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
|
3219
|
+
#
|
3220
|
+
# {
|
3221
|
+
# "symbol": "btc_usdt",
|
3222
|
+
# "orderId": "207505997850909952",
|
3223
|
+
# "clientOrderId": null,
|
3224
|
+
# "baseCurrency": "btc",
|
3225
|
+
# "quoteCurrency": "usdt",
|
3226
|
+
# "side": "BUY",
|
3227
|
+
# "type": "LIMIT",
|
3228
|
+
# "timeInForce": "GTC",
|
3229
|
+
# "price": "20000.00",
|
3230
|
+
# "origQty": "0.001000",
|
3231
|
+
# "origQuoteQty": "20.00",
|
3232
|
+
# "executedQty": "0.000000",
|
3233
|
+
# "leavingQty": "0.001000",
|
3234
|
+
# "tradeBase": "0.000000",
|
3235
|
+
# "tradeQuote": "0.00",
|
3236
|
+
# "avgPrice": null,
|
3237
|
+
# "fee": null,
|
3238
|
+
# "feeCurrency": null,
|
3239
|
+
# "closed": False,
|
3240
|
+
# "state": "NEW",
|
3241
|
+
# "time": 1679175285162,
|
3242
|
+
# "updatedTime": 1679175285255
|
3243
|
+
# }
|
3244
|
+
#
|
3245
|
+
# swap and future: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
|
3246
|
+
#
|
3247
|
+
# {
|
3248
|
+
# "orderId": "207519546930995456",
|
3249
|
+
# "clientOrderId": null,
|
3250
|
+
# "symbol": "btc_usdt",
|
3251
|
+
# "orderType": "LIMIT",
|
3252
|
+
# "orderSide": "BUY",
|
3253
|
+
# "positionSide": "LONG",
|
3254
|
+
# "timeInForce": "GTC",
|
3255
|
+
# "closePosition": False,
|
3256
|
+
# "price": "20000",
|
3257
|
+
# "origQty": "100",
|
3258
|
+
# "avgPrice": "0",
|
3259
|
+
# "executedQty": "0",
|
3260
|
+
# "marginFrozen": "4.12",
|
3261
|
+
# "remark": null,
|
3262
|
+
# "triggerProfitPrice": null,
|
3263
|
+
# "triggerStopPrice": null,
|
3264
|
+
# "sourceId": null,
|
3265
|
+
# "sourceType": "DEFAULT",
|
3266
|
+
# "forceClose": False,
|
3267
|
+
# "closeProfit": null,
|
3268
|
+
# "state": "CANCELED",
|
3269
|
+
# "createdTime": 1679178515689,
|
3270
|
+
# "updatedTime": 1679180096172
|
3271
|
+
# }
|
3272
|
+
#
|
3273
|
+
# trigger: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
|
3274
|
+
#
|
3275
|
+
# {
|
3276
|
+
# "entrustId": "216300248132756992",
|
3277
|
+
# "symbol": "btc_usdt",
|
3278
|
+
# "entrustType": "STOP",
|
3279
|
+
# "orderSide": "SELL",
|
3280
|
+
# "positionSide": "SHORT",
|
3281
|
+
# "timeInForce": "GTC",
|
3282
|
+
# "closePosition": null,
|
3283
|
+
# "price": "20000",
|
3284
|
+
# "origQty": "1",
|
3285
|
+
# "stopPrice": "19000",
|
3286
|
+
# "triggerPriceType": "LATEST_PRICE",
|
3287
|
+
# "state": "NOT_TRIGGERED",
|
3288
|
+
# "marketOrderLevel": null,
|
3289
|
+
# "createdTime": 1681271998064,
|
3290
|
+
# "updatedTime": 1681271998064,
|
3291
|
+
# "ordinary": False
|
3292
|
+
# }
|
3293
|
+
#
|
3294
|
+
# stop-loss and take-profit: fetchOrder, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
|
3295
|
+
#
|
3296
|
+
# {
|
3297
|
+
# "profitId": "216306213226230400",
|
3298
|
+
# "symbol": "btc_usdt",
|
3299
|
+
# "positionSide": "LONG",
|
3300
|
+
# "origQty": "1",
|
3301
|
+
# "triggerPriceType": "LATEST_PRICE",
|
3302
|
+
# "triggerProfitPrice": null,
|
3303
|
+
# "triggerStopPrice": "20000",
|
3304
|
+
# "entryPrice": null,
|
3305
|
+
# "positionSize": null,
|
3306
|
+
# "isolatedMargin": null,
|
3307
|
+
# "executedQty": null,
|
3308
|
+
# "avgPrice": null,
|
3309
|
+
# "positionType": "ISOLATED",
|
3310
|
+
# "state": "NOT_TRIGGERED",
|
3311
|
+
# "createdTime": 1681273420039
|
3312
|
+
# }
|
3313
|
+
#
|
3314
|
+
marketId = self.safe_string(order, 'symbol')
|
3315
|
+
marketType = ('result' in order) or 'contract' if ('positionSide' in order) else 'spot'
|
3316
|
+
market = self.safe_market(marketId, market, None, marketType)
|
3317
|
+
symbol = self.safe_symbol(marketId, market, None, marketType)
|
3318
|
+
timestamp = self.safe_integer_2(order, 'time', 'createdTime')
|
3319
|
+
quantity = self.safe_number(order, 'origQty')
|
3320
|
+
amount = quantity if (marketType == 'spot') else Precise.string_mul(self.number_to_string(quantity), self.number_to_string(market['contractSize']))
|
3321
|
+
filledQuantity = self.safe_number(order, 'executedQty')
|
3322
|
+
filled = filledQuantity if (marketType == 'spot') else Precise.string_mul(self.number_to_string(filledQuantity), self.number_to_string(market['contractSize']))
|
3323
|
+
lastUpdatedTimestamp = self.safe_integer(order, 'updatedTime')
|
3324
|
+
return self.safe_order({
|
3325
|
+
'info': order,
|
3326
|
+
'id': self.safe_string_n(order, ['orderId', 'result', 'cancelId', 'entrustId', 'profitId']),
|
3327
|
+
'clientOrderId': self.safe_string(order, 'clientOrderId'),
|
3328
|
+
'timestamp': timestamp,
|
3329
|
+
'datetime': self.iso8601(timestamp),
|
3330
|
+
'lastTradeTimestamp': lastUpdatedTimestamp,
|
3331
|
+
'lastUpdateTimestamp': lastUpdatedTimestamp,
|
3332
|
+
'symbol': symbol,
|
3333
|
+
'type': self.safe_string_lower_2(order, 'type', 'orderType'),
|
3334
|
+
'timeInForce': self.safe_string(order, 'timeInForce'),
|
3335
|
+
'postOnly': None,
|
3336
|
+
'side': self.safe_string_lower_2(order, 'side', 'orderSide'),
|
3337
|
+
'price': self.safe_number(order, 'price'),
|
3338
|
+
'triggerPrice': self.safe_number(order, 'stopPrice'),
|
3339
|
+
'stopLoss': self.safe_number(order, 'triggerStopPrice'),
|
3340
|
+
'takeProfit': self.safe_number(order, 'triggerProfitPrice'),
|
3341
|
+
'amount': amount,
|
3342
|
+
'filled': filled,
|
3343
|
+
'remaining': self.safe_number(order, 'leavingQty'),
|
3344
|
+
'cost': None,
|
3345
|
+
'average': self.safe_number(order, 'avgPrice'),
|
3346
|
+
'status': self.parse_order_status(self.safe_string(order, 'state')),
|
3347
|
+
'fee': {
|
3348
|
+
'currency': self.safe_currency_code(self.safe_string(order, 'feeCurrency')),
|
3349
|
+
'cost': self.safe_number(order, 'fee'),
|
3350
|
+
},
|
3351
|
+
'trades': None,
|
3352
|
+
}, market)
|
3353
|
+
|
3354
|
+
def parse_order_status(self, status):
|
3355
|
+
statuses = {
|
3356
|
+
'NEW': 'open',
|
3357
|
+
'PARTIALLY_FILLED': 'open',
|
3358
|
+
'FILLED': 'closed',
|
3359
|
+
'CANCELED': 'canceled',
|
3360
|
+
'REJECTED': 'rejected',
|
3361
|
+
'EXPIRED': 'expired',
|
3362
|
+
'UNFINISHED': 'open',
|
3363
|
+
'NOT_TRIGGERED': 'open',
|
3364
|
+
'TRIGGERING': 'open',
|
3365
|
+
'TRIGGERED': 'closed',
|
3366
|
+
'USER_REVOCATION': 'canceled',
|
3367
|
+
'PLATFORM_REVOCATION': 'rejected',
|
3368
|
+
'HISTORY': 'expired',
|
3369
|
+
}
|
3370
|
+
return self.safe_string(statuses, status, status)
|
3371
|
+
|
3372
|
+
async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
|
3373
|
+
"""
|
3374
|
+
fetch the history of changes, actions done by the user or operations that altered the balance of the user
|
3375
|
+
|
3376
|
+
https://doc.xt.com/#futures_usergetBalanceBill
|
3377
|
+
|
3378
|
+
:param str [code]: unified currency code
|
3379
|
+
:param int [since]: timestamp in ms of the earliest ledger entry
|
3380
|
+
:param int [limit]: max number of ledger entries to return
|
3381
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3382
|
+
:returns dict: a `ledger structure <https://docs.ccxt.com/en/latest/manual.html#ledger-structure>`
|
3383
|
+
"""
|
3384
|
+
await self.load_markets()
|
3385
|
+
request = {}
|
3386
|
+
currency = None
|
3387
|
+
if code is not None:
|
3388
|
+
currency = self.currency(code)
|
3389
|
+
if since is not None:
|
3390
|
+
request['startTime'] = since
|
3391
|
+
if limit is not None:
|
3392
|
+
request['limit'] = limit
|
3393
|
+
type = None
|
3394
|
+
subType = None
|
3395
|
+
response = None
|
3396
|
+
type, params = self.handle_market_type_and_params('fetchLedger', None, params)
|
3397
|
+
subType, params = self.handle_sub_type_and_params('fetchLedger', None, params)
|
3398
|
+
if subType == 'inverse':
|
3399
|
+
response = await self.privateInverseGetFutureUserV1BalanceBills(self.extend(request, params))
|
3400
|
+
elif (subType == 'linear') or (type == 'swap') or (type == 'future'):
|
3401
|
+
response = await self.privateLinearGetFutureUserV1BalanceBills(self.extend(request, params))
|
3402
|
+
else:
|
3403
|
+
raise NotSupported(self.id + ' fetchLedger() does not support spot transactions, only swap and future wallet transactions are supported')
|
3404
|
+
#
|
3405
|
+
# {
|
3406
|
+
# "returnCode": 0,
|
3407
|
+
# "msgInfo": "success",
|
3408
|
+
# "error": null,
|
3409
|
+
# "result": {
|
3410
|
+
# "hasPrev": False,
|
3411
|
+
# "hasNext": False,
|
3412
|
+
# "items": [
|
3413
|
+
# {
|
3414
|
+
# "id": "207260567109387524",
|
3415
|
+
# "coin": "usdt",
|
3416
|
+
# "symbol": "btc_usdt",
|
3417
|
+
# "type": "FEE",
|
3418
|
+
# "amount": "-0.0213",
|
3419
|
+
# "side": "SUB",
|
3420
|
+
# "afterAmount": null,
|
3421
|
+
# "createdTime": 1679116769914
|
3422
|
+
# },
|
3423
|
+
# ]
|
3424
|
+
# }
|
3425
|
+
# }
|
3426
|
+
#
|
3427
|
+
data = self.safe_value(response, 'result', {})
|
3428
|
+
ledger = self.safe_value(data, 'items', [])
|
3429
|
+
return self.parse_ledger(ledger, currency, since, limit)
|
3430
|
+
|
3431
|
+
def parse_ledger_entry(self, item, currency=None) -> LedgerEntry:
|
3432
|
+
#
|
3433
|
+
# {
|
3434
|
+
# "id": "207260567109387524",
|
3435
|
+
# "coin": "usdt",
|
3436
|
+
# "symbol": "btc_usdt",
|
3437
|
+
# "type": "FEE",
|
3438
|
+
# "amount": "-0.0213",
|
3439
|
+
# "side": "SUB",
|
3440
|
+
# "afterAmount": null,
|
3441
|
+
# "createdTime": 1679116769914
|
3442
|
+
# }
|
3443
|
+
#
|
3444
|
+
side = self.safe_string(item, 'side')
|
3445
|
+
direction = 'in' if (side == 'ADD') else 'out'
|
3446
|
+
currencyId = self.safe_string(item, 'coin')
|
3447
|
+
currency = self.safe_currency(currencyId, currency)
|
3448
|
+
timestamp = self.safe_integer(item, 'createdTime')
|
3449
|
+
return self.safe_ledger_entry({
|
3450
|
+
'info': item,
|
3451
|
+
'id': self.safe_string(item, 'id'),
|
3452
|
+
'direction': direction,
|
3453
|
+
'account': None,
|
3454
|
+
'referenceId': None,
|
3455
|
+
'referenceAccount': None,
|
3456
|
+
'type': self.parse_ledger_entry_type(self.safe_string(item, 'type')),
|
3457
|
+
'currency': self.safe_currency_code(currencyId, currency),
|
3458
|
+
'amount': self.safe_number(item, 'amount'),
|
3459
|
+
'timestamp': timestamp,
|
3460
|
+
'datetime': self.iso8601(timestamp),
|
3461
|
+
'before': None,
|
3462
|
+
'after': self.safe_number(item, 'afterAmount'),
|
3463
|
+
'status': None,
|
3464
|
+
'fee': {
|
3465
|
+
'currency': None,
|
3466
|
+
'cost': None,
|
3467
|
+
},
|
3468
|
+
}, currency)
|
3469
|
+
|
3470
|
+
def parse_ledger_entry_type(self, type):
|
3471
|
+
ledgerType = {
|
3472
|
+
'EXCHANGE': 'transfer',
|
3473
|
+
'CLOSE_POSITION': 'trade',
|
3474
|
+
'TAKE_OVER': 'trade',
|
3475
|
+
'MERGE': 'trade',
|
3476
|
+
'QIANG_PING_MANAGER': 'fee',
|
3477
|
+
'FUND': 'fee',
|
3478
|
+
'FEE': 'fee',
|
3479
|
+
'ADL': 'auto-deleveraging',
|
3480
|
+
}
|
3481
|
+
return self.safe_string(ledgerType, type, type)
|
3482
|
+
|
3483
|
+
async def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
|
3484
|
+
"""
|
3485
|
+
fetch the deposit address for a currency associated with self account
|
3486
|
+
|
3487
|
+
https://doc.xt.com/#deposit_withdrawaldepositAddressGet
|
3488
|
+
|
3489
|
+
:param str code: unified currency code
|
3490
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3491
|
+
:param str params['network']: required network id
|
3492
|
+
:returns dict: an `address structure <https://docs.ccxt.com/en/latest/manual.html#address-structure>`
|
3493
|
+
"""
|
3494
|
+
await self.load_markets()
|
3495
|
+
networkCode = None
|
3496
|
+
networkCode, params = self.handle_network_code_and_params(params)
|
3497
|
+
currency = self.currency(code)
|
3498
|
+
networkId = self.network_code_to_id(networkCode, code)
|
3499
|
+
self.check_required_argument('fetchDepositAddress', networkId, 'network')
|
3500
|
+
request = {
|
3501
|
+
'currency': currency['id'],
|
3502
|
+
'chain': networkId,
|
3503
|
+
}
|
3504
|
+
response = await self.privateSpotGetDepositAddress(self.extend(request, params))
|
3505
|
+
#
|
3506
|
+
# {
|
3507
|
+
# "rc": 0,
|
3508
|
+
# "mc": "SUCCESS",
|
3509
|
+
# "ma": [],
|
3510
|
+
# "result": {
|
3511
|
+
# "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
|
3512
|
+
# "memo": ""
|
3513
|
+
# }
|
3514
|
+
# }
|
3515
|
+
#
|
3516
|
+
result = self.safe_value(response, 'result', {})
|
3517
|
+
return self.parse_deposit_address(result, currency)
|
3518
|
+
|
3519
|
+
def parse_deposit_address(self, depositAddress, currency=None) -> DepositAddress:
|
3520
|
+
#
|
3521
|
+
# {
|
3522
|
+
# "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
|
3523
|
+
# "memo": ""
|
3524
|
+
# }
|
3525
|
+
#
|
3526
|
+
address = self.safe_string(depositAddress, 'address')
|
3527
|
+
self.check_address(address)
|
3528
|
+
return {
|
3529
|
+
'info': depositAddress,
|
3530
|
+
'currency': self.safe_currency_code(None, currency),
|
3531
|
+
'network': None,
|
3532
|
+
'address': address,
|
3533
|
+
'tag': self.safe_string(depositAddress, 'memo'),
|
3534
|
+
}
|
3535
|
+
|
3536
|
+
async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
3537
|
+
"""
|
3538
|
+
fetch all deposits made to an account
|
3539
|
+
|
3540
|
+
https://doc.xt.com/#deposit_withdrawalhistoryDepositGet
|
3541
|
+
|
3542
|
+
:param str [code]: unified currency code
|
3543
|
+
:param int [since]: the earliest time in ms to fetch deposits for
|
3544
|
+
:param int [limit]: the maximum number of transaction structures to retrieve
|
3545
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3546
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
|
3547
|
+
"""
|
3548
|
+
await self.load_markets()
|
3549
|
+
request = {}
|
3550
|
+
currency = None
|
3551
|
+
if code is not None:
|
3552
|
+
currency = self.currency(code)
|
3553
|
+
request['currency'] = currency['id']
|
3554
|
+
if since is not None:
|
3555
|
+
request['startTime'] = since
|
3556
|
+
if limit is not None:
|
3557
|
+
request['limit'] = limit # default 10, max 200
|
3558
|
+
response = await self.privateSpotGetDepositHistory(self.extend(request, params))
|
3559
|
+
#
|
3560
|
+
# {
|
3561
|
+
# "rc": 0,
|
3562
|
+
# "mc": "SUCCESS",
|
3563
|
+
# "ma": [],
|
3564
|
+
# "result": {
|
3565
|
+
# "hasPrev": False,
|
3566
|
+
# "hasNext": False,
|
3567
|
+
# "items": [
|
3568
|
+
# {
|
3569
|
+
# "id": 170368702,
|
3570
|
+
# "currency": "usdt",
|
3571
|
+
# "chain": "Ethereum",
|
3572
|
+
# "memo": "",
|
3573
|
+
# "status": "SUCCESS",
|
3574
|
+
# "amount": "31.792528",
|
3575
|
+
# "confirmations": 12,
|
3576
|
+
# "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
|
3577
|
+
# "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
|
3578
|
+
# "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
|
3579
|
+
# "createdTime": 1678491442000
|
3580
|
+
# },
|
3581
|
+
# ]
|
3582
|
+
# }
|
3583
|
+
# }
|
3584
|
+
#
|
3585
|
+
data = self.safe_value(response, 'result', {})
|
3586
|
+
deposits = self.safe_value(data, 'items', [])
|
3587
|
+
return self.parse_transactions(deposits, currency, since, limit, params)
|
3588
|
+
|
3589
|
+
async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
3590
|
+
"""
|
3591
|
+
fetch all withdrawals made from an account
|
3592
|
+
|
3593
|
+
https://doc.xt.com/#deposit_withdrawalwithdrawHistory
|
3594
|
+
|
3595
|
+
:param str [code]: unified currency code
|
3596
|
+
:param int [since]: the earliest time in ms to fetch withdrawals for
|
3597
|
+
:param int [limit]: the maximum number of transaction structures to retrieve
|
3598
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3599
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
|
3600
|
+
"""
|
3601
|
+
await self.load_markets()
|
3602
|
+
request = {}
|
3603
|
+
currency = None
|
3604
|
+
if code is not None:
|
3605
|
+
currency = self.currency(code)
|
3606
|
+
request['currency'] = currency['id']
|
3607
|
+
if since is not None:
|
3608
|
+
request['startTime'] = since
|
3609
|
+
if limit is not None:
|
3610
|
+
request['limit'] = limit # default 10, max 200
|
3611
|
+
response = await self.privateSpotGetWithdrawHistory(self.extend(request, params))
|
3612
|
+
#
|
3613
|
+
# {
|
3614
|
+
# "rc": 0,
|
3615
|
+
# "mc": "SUCCESS",
|
3616
|
+
# "ma": [],
|
3617
|
+
# "result": {
|
3618
|
+
# "hasPrev": False,
|
3619
|
+
# "hasNext": False,
|
3620
|
+
# "items": [
|
3621
|
+
# {
|
3622
|
+
# "id": 950898,
|
3623
|
+
# "currency": "usdt",
|
3624
|
+
# "chain": "Tron",
|
3625
|
+
# "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
|
3626
|
+
# "memo": "",
|
3627
|
+
# "status": "SUCCESS",
|
3628
|
+
# "amount": "5",
|
3629
|
+
# "fee": "2",
|
3630
|
+
# "confirmations": 6,
|
3631
|
+
# "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
|
3632
|
+
# "createdTime": 1680049062000
|
3633
|
+
# }
|
3634
|
+
# ]
|
3635
|
+
# }
|
3636
|
+
# }
|
3637
|
+
#
|
3638
|
+
data = self.safe_value(response, 'result', {})
|
3639
|
+
withdrawals = self.safe_value(data, 'items', [])
|
3640
|
+
return self.parse_transactions(withdrawals, currency, since, limit, params)
|
3641
|
+
|
3642
|
+
async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
|
3643
|
+
"""
|
3644
|
+
make a withdrawal
|
3645
|
+
|
3646
|
+
https://doc.xt.com/#deposit_withdrawalwithdraw
|
3647
|
+
|
3648
|
+
:param str code: unified currency code
|
3649
|
+
:param float amount: the amount to withdraw
|
3650
|
+
:param str address: the address to withdraw to
|
3651
|
+
:param str [tag]:
|
3652
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3653
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/en/latest/manual.html#transaction-structure>`
|
3654
|
+
"""
|
3655
|
+
self.check_address(address)
|
3656
|
+
await self.load_markets()
|
3657
|
+
currency = self.currency(code)
|
3658
|
+
tag, params = self.handle_withdraw_tag_and_params(tag, params)
|
3659
|
+
networkCode = None
|
3660
|
+
networkCode, params = self.handle_network_code_and_params(params)
|
3661
|
+
networkIdsByCodes = self.safe_value(self.options, 'networks', {})
|
3662
|
+
networkId = self.safe_string_2(networkIdsByCodes, networkCode, code, code)
|
3663
|
+
request = {
|
3664
|
+
'currency': currency['id'],
|
3665
|
+
'chain': networkId,
|
3666
|
+
'amount': self.currency_to_precision(code, amount),
|
3667
|
+
'address': address,
|
3668
|
+
}
|
3669
|
+
if tag is not None:
|
3670
|
+
request['memo'] = tag
|
3671
|
+
response = await self.privateSpotPostWithdraw(self.extend(request, params))
|
3672
|
+
#
|
3673
|
+
# {
|
3674
|
+
# "rc": 0,
|
3675
|
+
# "mc": "SUCCESS",
|
3676
|
+
# "ma": [],
|
3677
|
+
# "result": {
|
3678
|
+
# "id": 950898
|
3679
|
+
# }
|
3680
|
+
# }
|
3681
|
+
#
|
3682
|
+
result = self.safe_value(response, 'result', {})
|
3683
|
+
return self.parse_transaction(result, currency)
|
3684
|
+
|
3685
|
+
def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
|
3686
|
+
#
|
3687
|
+
# fetchDeposits
|
3688
|
+
#
|
3689
|
+
# {
|
3690
|
+
# "id": 170368702,
|
3691
|
+
# "currency": "usdt",
|
3692
|
+
# "chain": "Ethereum",
|
3693
|
+
# "memo": "",
|
3694
|
+
# "status": "SUCCESS",
|
3695
|
+
# "amount": "31.792528",
|
3696
|
+
# "confirmations": 12,
|
3697
|
+
# "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
|
3698
|
+
# "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
|
3699
|
+
# "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
|
3700
|
+
# "createdTime": 1678491442000
|
3701
|
+
# }
|
3702
|
+
#
|
3703
|
+
# fetchWithdrawals
|
3704
|
+
#
|
3705
|
+
# {
|
3706
|
+
# "id": 950898,
|
3707
|
+
# "currency": "usdt",
|
3708
|
+
# "chain": "Tron",
|
3709
|
+
# "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
|
3710
|
+
# "memo": "",
|
3711
|
+
# "status": "SUCCESS",
|
3712
|
+
# "amount": "5",
|
3713
|
+
# "fee": "2",
|
3714
|
+
# "confirmations": 6,
|
3715
|
+
# "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
|
3716
|
+
# "createdTime": 1680049062000
|
3717
|
+
# }
|
3718
|
+
#
|
3719
|
+
# withdraw
|
3720
|
+
#
|
3721
|
+
# {
|
3722
|
+
# "id": 950898
|
3723
|
+
# }
|
3724
|
+
#
|
3725
|
+
type = 'deposit' if ('fromAddr' in transaction) else 'withdraw'
|
3726
|
+
timestamp = self.safe_integer(transaction, 'createdTime')
|
3727
|
+
address = self.safe_string(transaction, 'address')
|
3728
|
+
memo = self.safe_string(transaction, 'memo')
|
3729
|
+
currencyCode = self.safe_currency_code(self.safe_string(transaction, 'currency'), currency)
|
3730
|
+
fee = self.safe_number(transaction, 'fee')
|
3731
|
+
feeCurrency = currencyCode if (fee is not None) else None
|
3732
|
+
networkId = self.safe_string(transaction, 'chain')
|
3733
|
+
return {
|
3734
|
+
'info': transaction,
|
3735
|
+
'id': self.safe_string(transaction, 'id'),
|
3736
|
+
'txid': self.safe_string(transaction, 'transactionId'),
|
3737
|
+
'timestamp': timestamp,
|
3738
|
+
'datetime': self.iso8601(timestamp),
|
3739
|
+
'updated': None,
|
3740
|
+
'addressFrom': self.safe_string(transaction, 'fromAddr'),
|
3741
|
+
'addressTo': address,
|
3742
|
+
'address': address,
|
3743
|
+
'tagFrom': None,
|
3744
|
+
'tagTo': None,
|
3745
|
+
'tag': memo,
|
3746
|
+
'type': type,
|
3747
|
+
'amount': self.safe_number(transaction, 'amount'),
|
3748
|
+
'currency': currencyCode,
|
3749
|
+
'network': self.network_id_to_code(networkId, currencyCode),
|
3750
|
+
'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
|
3751
|
+
'comment': memo,
|
3752
|
+
'fee': {
|
3753
|
+
'currency': feeCurrency,
|
3754
|
+
'cost': fee,
|
3755
|
+
'rate': None,
|
3756
|
+
},
|
3757
|
+
'internal': None,
|
3758
|
+
}
|
3759
|
+
|
3760
|
+
def parse_transaction_status(self, status):
|
3761
|
+
statuses = {
|
3762
|
+
'SUBMIT': 'pending',
|
3763
|
+
'REVIEW': 'pending',
|
3764
|
+
'AUDITED': 'pending',
|
3765
|
+
'PENDING': 'pending',
|
3766
|
+
'CANCEL': 'canceled',
|
3767
|
+
'FAIL': 'failed',
|
3768
|
+
'SUCCESS': 'ok',
|
3769
|
+
}
|
3770
|
+
return self.safe_string(statuses, status, status)
|
3771
|
+
|
3772
|
+
async def set_leverage(self, leverage: Int, symbol: str = None, params={}):
|
3773
|
+
"""
|
3774
|
+
set the level of leverage for a market
|
3775
|
+
|
3776
|
+
https://doc.xt.com/#futures_useradjustLeverage
|
3777
|
+
|
3778
|
+
:param float leverage: the rate of leverage
|
3779
|
+
:param str symbol: unified market symbol
|
3780
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3781
|
+
:param str params['positionSide']: 'LONG' or 'SHORT'
|
3782
|
+
:returns dict: response from the exchange
|
3783
|
+
"""
|
3784
|
+
if symbol is None:
|
3785
|
+
raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
|
3786
|
+
positionSide = self.safe_string(params, 'positionSide')
|
3787
|
+
self.check_required_argument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT'])
|
3788
|
+
if (leverage < 1) or (leverage > 125):
|
3789
|
+
raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 125')
|
3790
|
+
await self.load_markets()
|
3791
|
+
market = self.market(symbol)
|
3792
|
+
if not (market['contract']):
|
3793
|
+
raise BadSymbol(self.id + ' setLeverage() supports contract markets only')
|
3794
|
+
request = {
|
3795
|
+
'symbol': market['id'],
|
3796
|
+
'positionSide': positionSide,
|
3797
|
+
'leverage': leverage,
|
3798
|
+
}
|
3799
|
+
subType = None
|
3800
|
+
subType, params = self.handle_sub_type_and_params('setLeverage', market, params)
|
3801
|
+
response = None
|
3802
|
+
if subType == 'inverse':
|
3803
|
+
response = await self.privateInversePostFutureUserV1PositionAdjustLeverage(self.extend(request, params))
|
3804
|
+
else:
|
3805
|
+
response = await self.privateLinearPostFutureUserV1PositionAdjustLeverage(self.extend(request, params))
|
3806
|
+
#
|
3807
|
+
# {
|
3808
|
+
# "returnCode": 0,
|
3809
|
+
# "msgInfo": "success",
|
3810
|
+
# "error": null,
|
3811
|
+
# "result": null
|
3812
|
+
# }
|
3813
|
+
#
|
3814
|
+
return response
|
3815
|
+
|
3816
|
+
async def add_margin(self, symbol: str, amount: float, params={}):
|
3817
|
+
"""
|
3818
|
+
add margin to a position
|
3819
|
+
|
3820
|
+
https://doc.xt.com/#futures_useradjustMargin
|
3821
|
+
|
3822
|
+
:param str symbol: unified market symbol
|
3823
|
+
:param float amount: amount of margin to add
|
3824
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3825
|
+
:param str params['positionSide']: 'LONG' or 'SHORT'
|
3826
|
+
:returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
|
3827
|
+
"""
|
3828
|
+
return await self.modify_margin_helper(symbol, amount, 'ADD', params)
|
3829
|
+
|
3830
|
+
async def reduce_margin(self, symbol: str, amount: float, params={}):
|
3831
|
+
"""
|
3832
|
+
remove margin from a position
|
3833
|
+
|
3834
|
+
https://doc.xt.com/#futures_useradjustMargin
|
3835
|
+
|
3836
|
+
:param str symbol: unified market symbol
|
3837
|
+
:param float amount: the amount of margin to remove
|
3838
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3839
|
+
:param str params['positionSide']: 'LONG' or 'SHORT'
|
3840
|
+
:returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
|
3841
|
+
"""
|
3842
|
+
return await self.modify_margin_helper(symbol, amount, 'SUB', params)
|
3843
|
+
|
3844
|
+
async def modify_margin_helper(self, symbol: str, amount, addOrReduce, params={}) -> MarginModification:
|
3845
|
+
positionSide = self.safe_string(params, 'positionSide')
|
3846
|
+
self.check_required_argument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT'])
|
3847
|
+
await self.load_markets()
|
3848
|
+
market = self.market(symbol)
|
3849
|
+
request = {
|
3850
|
+
'symbol': market['id'],
|
3851
|
+
'margin': amount,
|
3852
|
+
'type': addOrReduce,
|
3853
|
+
'positionSide': positionSide,
|
3854
|
+
}
|
3855
|
+
subType = None
|
3856
|
+
subType, params = self.handle_sub_type_and_params('modifyMarginHelper', market, params)
|
3857
|
+
response = None
|
3858
|
+
if subType == 'inverse':
|
3859
|
+
response = await self.privateInversePostFutureUserV1PositionMargin(self.extend(request, params))
|
3860
|
+
else:
|
3861
|
+
response = await self.privateLinearPostFutureUserV1PositionMargin(self.extend(request, params))
|
3862
|
+
#
|
3863
|
+
# {
|
3864
|
+
# "returnCode": 0,
|
3865
|
+
# "msgInfo": "success",
|
3866
|
+
# "error": null,
|
3867
|
+
# "result": null
|
3868
|
+
# }
|
3869
|
+
#
|
3870
|
+
return self.parse_margin_modification(response, market)
|
3871
|
+
|
3872
|
+
def parse_margin_modification(self, data, market=None) -> MarginModification:
|
3873
|
+
return {
|
3874
|
+
'info': data,
|
3875
|
+
'type': None,
|
3876
|
+
'amount': None,
|
3877
|
+
'code': None,
|
3878
|
+
'symbol': self.safe_symbol(None, market),
|
3879
|
+
'status': None,
|
3880
|
+
'marginMode': None,
|
3881
|
+
'total': None,
|
3882
|
+
'timestamp': None,
|
3883
|
+
'datetime': None,
|
3884
|
+
}
|
3885
|
+
|
3886
|
+
async def fetch_leverage_tiers(self, symbols: List[str] = None, params={}) -> LeverageTiers:
|
3887
|
+
"""
|
3888
|
+
retrieve information on the maximum leverage for different trade sizes
|
3889
|
+
|
3890
|
+
https://doc.xt.com/#futures_quotesgetLeverageBrackets
|
3891
|
+
|
3892
|
+
:param str [symbols]: a list of unified market symbols
|
3893
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3894
|
+
:returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
|
3895
|
+
"""
|
3896
|
+
await self.load_markets()
|
3897
|
+
subType = None
|
3898
|
+
subType, params = self.handle_sub_type_and_params('fetchLeverageTiers', None, params)
|
3899
|
+
response = None
|
3900
|
+
if subType == 'inverse':
|
3901
|
+
response = await self.publicInverseGetFutureMarketV1PublicLeverageBracketList(params)
|
3902
|
+
else:
|
3903
|
+
response = await self.publicLinearGetFutureMarketV1PublicLeverageBracketList(params)
|
3904
|
+
#
|
3905
|
+
# {
|
3906
|
+
# "returnCode": 0,
|
3907
|
+
# "msgInfo": "success",
|
3908
|
+
# "error": null,
|
3909
|
+
# "result": [
|
3910
|
+
# {
|
3911
|
+
# "symbol": "rad_usdt",
|
3912
|
+
# "leverageBrackets": [
|
3913
|
+
# {
|
3914
|
+
# "symbol": "rad_usdt",
|
3915
|
+
# "bracket": 1,
|
3916
|
+
# "maxNominalValue": "5000",
|
3917
|
+
# "maintMarginRate": "0.025",
|
3918
|
+
# "startMarginRate": "0.05",
|
3919
|
+
# "maxStartMarginRate": null,
|
3920
|
+
# "maxLeverage": "20",
|
3921
|
+
# "minLeverage": "1"
|
3922
|
+
# },
|
3923
|
+
# ]
|
3924
|
+
# },
|
3925
|
+
# ]
|
3926
|
+
# }
|
3927
|
+
#
|
3928
|
+
data = self.safe_value(response, 'result', [])
|
3929
|
+
symbols = self.market_symbols(symbols)
|
3930
|
+
return self.parse_leverage_tiers(data, symbols, 'symbol')
|
3931
|
+
|
3932
|
+
def parse_leverage_tiers(self, response, symbols=None, marketIdKey=None) -> LeverageTiers:
|
3933
|
+
#
|
3934
|
+
# {
|
3935
|
+
# "symbol": "rad_usdt",
|
3936
|
+
# "leverageBrackets": [
|
3937
|
+
# {
|
3938
|
+
# "symbol": "rad_usdt",
|
3939
|
+
# "bracket": 1,
|
3940
|
+
# "maxNominalValue": "5000",
|
3941
|
+
# "maintMarginRate": "0.025",
|
3942
|
+
# "startMarginRate": "0.05",
|
3943
|
+
# "maxStartMarginRate": null,
|
3944
|
+
# "maxLeverage": "20",
|
3945
|
+
# "minLeverage": "1"
|
3946
|
+
# },
|
3947
|
+
# ]
|
3948
|
+
# }
|
3949
|
+
#
|
3950
|
+
result = {}
|
3951
|
+
for i in range(0, len(response)):
|
3952
|
+
entry = response[i]
|
3953
|
+
marketId = self.safe_string(entry, 'symbol')
|
3954
|
+
market = self.safe_market(marketId, None, '_', 'contract')
|
3955
|
+
symbol = self.safe_symbol(marketId, market)
|
3956
|
+
if symbols is not None:
|
3957
|
+
if self.in_array(symbol, symbols):
|
3958
|
+
result[symbol] = self.parse_market_leverage_tiers(entry, market)
|
3959
|
+
else:
|
3960
|
+
result[symbol] = self.parse_market_leverage_tiers(response[i], market)
|
3961
|
+
return result
|
3962
|
+
|
3963
|
+
async def fetch_market_leverage_tiers(self, symbol: str, params={}) -> List[LeverageTier]:
|
3964
|
+
"""
|
3965
|
+
retrieve information on the maximum leverage for different trade sizes of a single market
|
3966
|
+
|
3967
|
+
https://doc.xt.com/#futures_quotesgetLeverageBracket
|
3968
|
+
|
3969
|
+
:param str symbol: unified market symbol
|
3970
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
3971
|
+
:returns dict: a `leverage tiers structure <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
|
3972
|
+
"""
|
3973
|
+
await self.load_markets()
|
3974
|
+
market = self.market(symbol)
|
3975
|
+
request = {
|
3976
|
+
'symbol': market['id'],
|
3977
|
+
}
|
3978
|
+
subType = None
|
3979
|
+
subType, params = self.handle_sub_type_and_params('fetchMarketLeverageTiers', market, params)
|
3980
|
+
response = None
|
3981
|
+
if subType == 'inverse':
|
3982
|
+
response = await self.publicInverseGetFutureMarketV1PublicLeverageBracketDetail(self.extend(request, params))
|
3983
|
+
else:
|
3984
|
+
response = await self.publicLinearGetFutureMarketV1PublicLeverageBracketDetail(self.extend(request, params))
|
3985
|
+
#
|
3986
|
+
# {
|
3987
|
+
# "returnCode": 0,
|
3988
|
+
# "msgInfo": "success",
|
3989
|
+
# "error": null,
|
3990
|
+
# "result": {
|
3991
|
+
# "symbol": "btc_usdt",
|
3992
|
+
# "leverageBrackets": [
|
3993
|
+
# {
|
3994
|
+
# "symbol": "btc_usdt",
|
3995
|
+
# "bracket": 1,
|
3996
|
+
# "maxNominalValue": "500000",
|
3997
|
+
# "maintMarginRate": "0.004",
|
3998
|
+
# "startMarginRate": "0.008",
|
3999
|
+
# "maxStartMarginRate": null,
|
4000
|
+
# "maxLeverage": "125",
|
4001
|
+
# "minLeverage": "1"
|
4002
|
+
# },
|
4003
|
+
# ]
|
4004
|
+
# }
|
4005
|
+
# }
|
4006
|
+
#
|
4007
|
+
data = self.safe_value(response, 'result', {})
|
4008
|
+
return self.parse_market_leverage_tiers(data, market)
|
4009
|
+
|
4010
|
+
def parse_market_leverage_tiers(self, info, market=None) -> List[LeverageTier]:
|
4011
|
+
#
|
4012
|
+
# {
|
4013
|
+
# "symbol": "rad_usdt",
|
4014
|
+
# "leverageBrackets": [
|
4015
|
+
# {
|
4016
|
+
# "symbol": "rad_usdt",
|
4017
|
+
# "bracket": 1,
|
4018
|
+
# "maxNominalValue": "5000",
|
4019
|
+
# "maintMarginRate": "0.025",
|
4020
|
+
# "startMarginRate": "0.05",
|
4021
|
+
# "maxStartMarginRate": null,
|
4022
|
+
# "maxLeverage": "20",
|
4023
|
+
# "minLeverage": "1"
|
4024
|
+
# },
|
4025
|
+
# ]
|
4026
|
+
# }
|
4027
|
+
#
|
4028
|
+
tiers = []
|
4029
|
+
brackets = self.safe_value(info, 'leverageBrackets', [])
|
4030
|
+
for i in range(0, len(brackets)):
|
4031
|
+
tier = brackets[i]
|
4032
|
+
marketId = self.safe_string(info, 'symbol')
|
4033
|
+
market = self.safe_market(marketId, market, '_', 'contract')
|
4034
|
+
tiers.append({
|
4035
|
+
'tier': self.safe_integer(tier, 'bracket'),
|
4036
|
+
'symbol': self.safe_symbol(marketId, market, '_', 'contract'),
|
4037
|
+
'currency': market['settle'],
|
4038
|
+
'minNotional': self.safe_number(brackets[i - 1], 'maxNominalValue', 0),
|
4039
|
+
'maxNotional': self.safe_number(tier, 'maxNominalValue'),
|
4040
|
+
'maintenanceMarginRate': self.safe_number(tier, 'maintMarginRate'),
|
4041
|
+
'maxLeverage': self.safe_number(tier, 'maxLeverage'),
|
4042
|
+
'info': tier,
|
4043
|
+
})
|
4044
|
+
return tiers
|
4045
|
+
|
4046
|
+
async def fetch_funding_rate_history(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
|
4047
|
+
"""
|
4048
|
+
fetches historical funding rates
|
4049
|
+
|
4050
|
+
https://doc.xt.com/#futures_quotesgetFundingRateRecord
|
4051
|
+
|
4052
|
+
:param str [symbol]: unified symbol of the market to fetch the funding rate history for
|
4053
|
+
:param int [since]: timestamp in ms of the earliest funding rate to fetch
|
4054
|
+
:param int [limit]: the maximum amount of [funding rate structures] to fetch
|
4055
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
4056
|
+
:returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure>`
|
4057
|
+
"""
|
4058
|
+
if symbol is None:
|
4059
|
+
raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
|
4060
|
+
await self.load_markets()
|
4061
|
+
market = self.market(symbol)
|
4062
|
+
if not market['swap']:
|
4063
|
+
raise BadSymbol(self.id + ' fetchFundingRateHistory() supports swap contracts only')
|
4064
|
+
request = {
|
4065
|
+
'symbol': market['id'],
|
4066
|
+
}
|
4067
|
+
if limit is not None:
|
4068
|
+
request['limit'] = limit
|
4069
|
+
subType = None
|
4070
|
+
subType, params = self.handle_sub_type_and_params('fetchFundingRateHistory', market, params)
|
4071
|
+
response = None
|
4072
|
+
if subType == 'inverse':
|
4073
|
+
response = await self.publicInverseGetFutureMarketV1PublicQFundingRateRecord(self.extend(request, params))
|
4074
|
+
else:
|
4075
|
+
response = await self.publicLinearGetFutureMarketV1PublicQFundingRateRecord(self.extend(request, params))
|
4076
|
+
#
|
4077
|
+
# {
|
4078
|
+
# "returnCode": 0,
|
4079
|
+
# "msgInfo": "success",
|
4080
|
+
# "error": null,
|
4081
|
+
# "result": {
|
4082
|
+
# "hasPrev": False,
|
4083
|
+
# "hasNext": True,
|
4084
|
+
# "items": [
|
4085
|
+
# {
|
4086
|
+
# "id": "210441653482221888",
|
4087
|
+
# "symbol": "btc_usdt",
|
4088
|
+
# "fundingRate": "0.000057",
|
4089
|
+
# "createdTime": 1679875200000,
|
4090
|
+
# "collectionInternal": 28800
|
4091
|
+
# },
|
4092
|
+
# ]
|
4093
|
+
# }
|
4094
|
+
# }
|
4095
|
+
#
|
4096
|
+
result = self.safe_value(response, 'result', {})
|
4097
|
+
items = self.safe_value(result, 'items', [])
|
4098
|
+
rates = []
|
4099
|
+
for i in range(0, len(items)):
|
4100
|
+
entry = items[i]
|
4101
|
+
marketId = self.safe_string(entry, 'symbol')
|
4102
|
+
symbolInner = self.safe_symbol(marketId, market)
|
4103
|
+
timestamp = self.safe_integer(entry, 'createdTime')
|
4104
|
+
rates.append({
|
4105
|
+
'info': entry,
|
4106
|
+
'symbol': symbolInner,
|
4107
|
+
'fundingRate': self.safe_number(entry, 'fundingRate'),
|
4108
|
+
'timestamp': timestamp,
|
4109
|
+
'datetime': self.iso8601(timestamp),
|
4110
|
+
})
|
4111
|
+
sorted = self.sort_by(rates, 'timestamp')
|
4112
|
+
return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
|
4113
|
+
|
4114
|
+
async def fetch_funding_interval(self, symbol: str, params={}) -> FundingRate:
|
4115
|
+
"""
|
4116
|
+
fetch the current funding rate interval
|
4117
|
+
|
4118
|
+
https://doc.xt.com/#futures_quotesgetFundingRate
|
4119
|
+
|
4120
|
+
:param str symbol: unified market symbol
|
4121
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
4122
|
+
:returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
|
4123
|
+
"""
|
4124
|
+
return await self.fetch_funding_rate(symbol, params)
|
4125
|
+
|
4126
|
+
async def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
|
4127
|
+
"""
|
4128
|
+
fetch the current funding rate
|
4129
|
+
|
4130
|
+
https://doc.xt.com/#futures_quotesgetFundingRate
|
4131
|
+
|
4132
|
+
:param str symbol: unified market symbol
|
4133
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
4134
|
+
:returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
|
4135
|
+
"""
|
4136
|
+
await self.load_markets()
|
4137
|
+
market = self.market(symbol)
|
4138
|
+
if not market['swap']:
|
4139
|
+
raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
|
4140
|
+
request = {
|
4141
|
+
'symbol': market['id'],
|
4142
|
+
}
|
4143
|
+
subType = None
|
4144
|
+
subType, params = self.handle_sub_type_and_params('fetchFundingRate', market, params)
|
4145
|
+
response = None
|
4146
|
+
if subType == 'inverse':
|
4147
|
+
response = await self.publicInverseGetFutureMarketV1PublicQFundingRate(self.extend(request, params))
|
4148
|
+
else:
|
4149
|
+
response = await self.publicLinearGetFutureMarketV1PublicQFundingRate(self.extend(request, params))
|
4150
|
+
#
|
4151
|
+
# {
|
4152
|
+
# "returnCode": 0,
|
4153
|
+
# "msgInfo": "success",
|
4154
|
+
# "error": null,
|
4155
|
+
# "result": {
|
4156
|
+
# "symbol": "btc_usdt",
|
4157
|
+
# "fundingRate": "0.000086",
|
4158
|
+
# "nextCollectionTime": 1680307200000,
|
4159
|
+
# "collectionInternal": 8
|
4160
|
+
# }
|
4161
|
+
# }
|
4162
|
+
#
|
4163
|
+
result = self.safe_value(response, 'result', {})
|
4164
|
+
return self.parse_funding_rate(result, market)
|
4165
|
+
|
4166
|
+
def parse_funding_rate(self, contract, market=None) -> FundingRate:
|
4167
|
+
#
|
4168
|
+
# {
|
4169
|
+
# "symbol": "btc_usdt",
|
4170
|
+
# "fundingRate": "0.000086",
|
4171
|
+
# "nextCollectionTime": 1680307200000,
|
4172
|
+
# "collectionInternal": 8
|
4173
|
+
# }
|
4174
|
+
#
|
4175
|
+
marketId = self.safe_string(contract, 'symbol')
|
4176
|
+
symbol = self.safe_symbol(marketId, market, '_', 'swap')
|
4177
|
+
timestamp = self.safe_integer(contract, 'nextCollectionTime')
|
4178
|
+
interval = self.safe_string(contract, 'collectionInternal')
|
4179
|
+
if interval is not None:
|
4180
|
+
interval = interval + 'h'
|
4181
|
+
return {
|
4182
|
+
'info': contract,
|
4183
|
+
'symbol': symbol,
|
4184
|
+
'markPrice': None,
|
4185
|
+
'indexPrice': None,
|
4186
|
+
'interestRate': None,
|
4187
|
+
'estimatedSettlePrice': None,
|
4188
|
+
'timestamp': None,
|
4189
|
+
'datetime': None,
|
4190
|
+
'fundingRate': self.safe_number(contract, 'fundingRate'),
|
4191
|
+
'fundingTimestamp': timestamp,
|
4192
|
+
'fundingDatetime': self.iso8601(timestamp),
|
4193
|
+
'nextFundingRate': None,
|
4194
|
+
'nextFundingTimestamp': None,
|
4195
|
+
'nextFundingDatetime': None,
|
4196
|
+
'previousFundingRate': None,
|
4197
|
+
'previousFundingTimestamp': None,
|
4198
|
+
'previousFundingDatetime': None,
|
4199
|
+
'interval': interval,
|
4200
|
+
}
|
4201
|
+
|
4202
|
+
async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
4203
|
+
"""
|
4204
|
+
fetch the funding history
|
4205
|
+
|
4206
|
+
https://doc.xt.com/#futures_usergetFunding
|
4207
|
+
|
4208
|
+
:param str symbol: unified market symbol
|
4209
|
+
:param int [since]: the starting timestamp in milliseconds
|
4210
|
+
:param int [limit]: the number of entries to return
|
4211
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
4212
|
+
:returns dict[]: a list of `funding history structures <https://docs.ccxt.com/#/?id=funding-history-structure>`
|
4213
|
+
"""
|
4214
|
+
await self.load_markets()
|
4215
|
+
market = self.market(symbol)
|
4216
|
+
if not market['swap']:
|
4217
|
+
raise BadSymbol(self.id + ' fetchFundingHistory() supports swap contracts only')
|
4218
|
+
request = {
|
4219
|
+
'symbol': market['id'],
|
4220
|
+
}
|
4221
|
+
if since is not None:
|
4222
|
+
request['startTime'] = since
|
4223
|
+
if limit is not None:
|
4224
|
+
request['limit'] = limit
|
4225
|
+
subType = None
|
4226
|
+
subType, params = self.handle_sub_type_and_params('fetchFundingHistory', market, params)
|
4227
|
+
response = None
|
4228
|
+
if subType == 'inverse':
|
4229
|
+
response = await self.privateInverseGetFutureUserV1BalanceFundingRateList(self.extend(request, params))
|
4230
|
+
else:
|
4231
|
+
response = await self.privateLinearGetFutureUserV1BalanceFundingRateList(self.extend(request, params))
|
4232
|
+
#
|
4233
|
+
# {
|
4234
|
+
# "returnCode": 0,
|
4235
|
+
# "msgInfo": "success",
|
4236
|
+
# "error": null,
|
4237
|
+
# "result": {
|
4238
|
+
# "hasPrev": False,
|
4239
|
+
# "hasNext": False,
|
4240
|
+
# "items": [
|
4241
|
+
# {
|
4242
|
+
# "id": "210804044057280512",
|
4243
|
+
# "symbol": "btc_usdt",
|
4244
|
+
# "cast": "-0.0013",
|
4245
|
+
# "coin": "usdt",
|
4246
|
+
# "positionSide": "SHORT",
|
4247
|
+
# "createdTime": 1679961600653
|
4248
|
+
# },
|
4249
|
+
# ]
|
4250
|
+
# }
|
4251
|
+
# }
|
4252
|
+
#
|
4253
|
+
data = self.safe_value(response, 'result', {})
|
4254
|
+
items = self.safe_value(data, 'items', [])
|
4255
|
+
result = []
|
4256
|
+
for i in range(0, len(items)):
|
4257
|
+
entry = items[i]
|
4258
|
+
result.append(self.parse_funding_history(entry, market))
|
4259
|
+
sorted = self.sort_by(result, 'timestamp')
|
4260
|
+
return self.filter_by_since_limit(sorted, since, limit)
|
4261
|
+
|
4262
|
+
def parse_funding_history(self, contract, market=None):
|
4263
|
+
#
|
4264
|
+
# {
|
4265
|
+
# "id": "210804044057280512",
|
4266
|
+
# "symbol": "btc_usdt",
|
4267
|
+
# "cast": "-0.0013",
|
4268
|
+
# "coin": "usdt",
|
4269
|
+
# "positionSide": "SHORT",
|
4270
|
+
# "createdTime": 1679961600653
|
4271
|
+
# }
|
4272
|
+
#
|
4273
|
+
marketId = self.safe_string(contract, 'symbol')
|
4274
|
+
symbol = self.safe_symbol(marketId, market, '_', 'swap')
|
4275
|
+
currencyId = self.safe_string(contract, 'coin')
|
4276
|
+
code = self.safe_currency_code(currencyId)
|
4277
|
+
timestamp = self.safe_integer(contract, 'createdTime')
|
4278
|
+
return {
|
4279
|
+
'info': contract,
|
4280
|
+
'symbol': symbol,
|
4281
|
+
'code': code,
|
4282
|
+
'timestamp': timestamp,
|
4283
|
+
'datetime': self.iso8601(timestamp),
|
4284
|
+
'id': self.safe_string(contract, 'id'),
|
4285
|
+
'amount': self.safe_number(contract, 'cast'),
|
4286
|
+
}
|
4287
|
+
|
4288
|
+
async def fetch_position(self, symbol: str, params={}):
|
4289
|
+
"""
|
4290
|
+
fetch data on a single open contract trade position
|
4291
|
+
|
4292
|
+
https://doc.xt.com/#futures_usergetPosition
|
4293
|
+
|
4294
|
+
:param str symbol: unified market symbol of the market the position is held in
|
4295
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
4296
|
+
:returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
4297
|
+
"""
|
4298
|
+
await self.load_markets()
|
4299
|
+
market = self.market(symbol)
|
4300
|
+
request = {
|
4301
|
+
'symbol': market['id'],
|
4302
|
+
}
|
4303
|
+
subType = None
|
4304
|
+
subType, params = self.handle_sub_type_and_params('fetchPosition', market, params)
|
4305
|
+
response = None
|
4306
|
+
if subType == 'inverse':
|
4307
|
+
response = await self.privateInverseGetFutureUserV1PositionList(self.extend(request, params))
|
4308
|
+
else:
|
4309
|
+
response = await self.privateLinearGetFutureUserV1PositionList(self.extend(request, params))
|
4310
|
+
#
|
4311
|
+
# {
|
4312
|
+
# "returnCode": 0,
|
4313
|
+
# "msgInfo": "success",
|
4314
|
+
# "error": null,
|
4315
|
+
# "result": [
|
4316
|
+
# {
|
4317
|
+
# "symbol": "btc_usdt",
|
4318
|
+
# "positionType": "ISOLATED",
|
4319
|
+
# "positionSide": "SHORT",
|
4320
|
+
# "contractType": "PERPETUAL",
|
4321
|
+
# "positionSize": "10",
|
4322
|
+
# "closeOrderSize": "0",
|
4323
|
+
# "availableCloseSize": "10",
|
4324
|
+
# "entryPrice": "27060",
|
4325
|
+
# "openOrderSize": "0",
|
4326
|
+
# "isolatedMargin": "1.0824",
|
4327
|
+
# "openOrderMarginFrozen": "0",
|
4328
|
+
# "realizedProfit": "-0.00130138",
|
4329
|
+
# "autoMargin": False,
|
4330
|
+
# "leverage": 25
|
4331
|
+
# },
|
4332
|
+
# ]
|
4333
|
+
# }
|
4334
|
+
#
|
4335
|
+
positions = self.safe_value(response, 'result', [])
|
4336
|
+
for i in range(0, len(positions)):
|
4337
|
+
entry = positions[i]
|
4338
|
+
marketId = self.safe_string(entry, 'symbol')
|
4339
|
+
marketInner = self.safe_market(marketId, None, None, 'contract')
|
4340
|
+
positionSize = self.safe_string(entry, 'positionSize')
|
4341
|
+
if positionSize != '0':
|
4342
|
+
return self.parse_position(entry, marketInner)
|
4343
|
+
return None
|
4344
|
+
|
4345
|
+
async def fetch_positions(self, symbols: List[str] = None, params={}):
|
4346
|
+
"""
|
4347
|
+
fetch all open positions
|
4348
|
+
|
4349
|
+
https://doc.xt.com/#futures_usergetPosition
|
4350
|
+
|
4351
|
+
:param str [symbols]: list of unified market symbols, not supported with xt
|
4352
|
+
:param dict params: extra parameters specific to the xt api endpoint
|
4353
|
+
:returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
4354
|
+
"""
|
4355
|
+
await self.load_markets()
|
4356
|
+
subType = None
|
4357
|
+
subType, params = self.handle_sub_type_and_params('fetchPositions', None, params)
|
4358
|
+
response = None
|
4359
|
+
if subType == 'inverse':
|
4360
|
+
response = await self.privateInverseGetFutureUserV1PositionList(params)
|
4361
|
+
else:
|
4362
|
+
response = await self.privateLinearGetFutureUserV1PositionList(params)
|
4363
|
+
#
|
4364
|
+
# {
|
4365
|
+
# "returnCode": 0,
|
4366
|
+
# "msgInfo": "success",
|
4367
|
+
# "error": null,
|
4368
|
+
# "result": [
|
4369
|
+
# {
|
4370
|
+
# "symbol": "btc_usdt",
|
4371
|
+
# "positionType": "ISOLATED",
|
4372
|
+
# "positionSide": "SHORT",
|
4373
|
+
# "contractType": "PERPETUAL",
|
4374
|
+
# "positionSize": "10",
|
4375
|
+
# "closeOrderSize": "0",
|
4376
|
+
# "availableCloseSize": "10",
|
4377
|
+
# "entryPrice": "27060",
|
4378
|
+
# "openOrderSize": "0",
|
4379
|
+
# "isolatedMargin": "1.0824",
|
4380
|
+
# "openOrderMarginFrozen": "0",
|
4381
|
+
# "realizedProfit": "-0.00130138",
|
4382
|
+
# "autoMargin": False,
|
4383
|
+
# "leverage": 25
|
4384
|
+
# },
|
4385
|
+
# ]
|
4386
|
+
# }
|
4387
|
+
#
|
4388
|
+
positions = self.safe_value(response, 'result', [])
|
4389
|
+
result = []
|
4390
|
+
for i in range(0, len(positions)):
|
4391
|
+
entry = positions[i]
|
4392
|
+
marketId = self.safe_string(entry, 'symbol')
|
4393
|
+
marketInner = self.safe_market(marketId, None, None, 'contract')
|
4394
|
+
result.append(self.parse_position(entry, marketInner))
|
4395
|
+
return self.filter_by_array_positions(result, 'symbol', symbols, False)
|
4396
|
+
|
4397
|
+
def parse_position(self, position, market=None):
|
4398
|
+
#
|
4399
|
+
# {
|
4400
|
+
# "symbol": "btc_usdt",
|
4401
|
+
# "positionType": "ISOLATED",
|
4402
|
+
# "positionSide": "SHORT",
|
4403
|
+
# "contractType": "PERPETUAL",
|
4404
|
+
# "positionSize": "10",
|
4405
|
+
# "closeOrderSize": "0",
|
4406
|
+
# "availableCloseSize": "10",
|
4407
|
+
# "entryPrice": "27060",
|
4408
|
+
# "openOrderSize": "0",
|
4409
|
+
# "isolatedMargin": "1.0824",
|
4410
|
+
# "openOrderMarginFrozen": "0",
|
4411
|
+
# "realizedProfit": "-0.00130138",
|
4412
|
+
# "autoMargin": False,
|
4413
|
+
# "leverage": 25
|
4414
|
+
# }
|
4415
|
+
#
|
4416
|
+
marketId = self.safe_string(position, 'symbol')
|
4417
|
+
market = self.safe_market(marketId, market, None, 'contract')
|
4418
|
+
symbol = self.safe_symbol(marketId, market, None, 'contract')
|
4419
|
+
positionType = self.safe_string(position, 'positionType')
|
4420
|
+
marginMode = 'cross' if (positionType == 'CROSSED') else 'isolated'
|
4421
|
+
collateral = self.safe_number(position, 'isolatedMargin')
|
4422
|
+
return self.safe_position({
|
4423
|
+
'info': position,
|
4424
|
+
'id': None,
|
4425
|
+
'symbol': symbol,
|
4426
|
+
'timestamp': None,
|
4427
|
+
'datetime': None,
|
4428
|
+
'hedged': None,
|
4429
|
+
'side': self.safe_string_lower(position, 'positionSide'),
|
4430
|
+
'contracts': self.safe_number(position, 'positionSize'),
|
4431
|
+
'contractSize': market['contractSize'],
|
4432
|
+
'entryPrice': self.safe_number(position, 'entryPrice'),
|
4433
|
+
'markPrice': None,
|
4434
|
+
'notional': None,
|
4435
|
+
'leverage': self.safe_integer(position, 'leverage'),
|
4436
|
+
'collateral': collateral,
|
4437
|
+
'initialMargin': collateral,
|
4438
|
+
'maintenanceMargin': None,
|
4439
|
+
'initialMarginPercentage': None,
|
4440
|
+
'maintenanceMarginPercentage': None,
|
4441
|
+
'unrealizedPnl': None,
|
4442
|
+
'liquidationPrice': None,
|
4443
|
+
'marginMode': marginMode,
|
4444
|
+
'percentage': None,
|
4445
|
+
'marginRatio': None,
|
4446
|
+
})
|
4447
|
+
|
4448
|
+
async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
4449
|
+
"""
|
4450
|
+
transfer currency internally between wallets on the same account
|
4451
|
+
|
4452
|
+
https://doc.xt.com/#transfersubTransferPost
|
4453
|
+
|
4454
|
+
:param str code: unified currency code
|
4455
|
+
:param float amount: amount to transfer
|
4456
|
+
:param str fromAccount: account to transfer from - spot, swap, leverage, finance
|
4457
|
+
:param str toAccount: account to transfer to - spot, swap, leverage, finance
|
4458
|
+
:param dict params: extra parameters specific to the whitebit api endpoint
|
4459
|
+
:returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
4460
|
+
"""
|
4461
|
+
await self.load_markets()
|
4462
|
+
currency = self.currency(code)
|
4463
|
+
accountsByType = self.safe_value(self.options, 'accountsById')
|
4464
|
+
fromAccountId = self.safe_string(accountsByType, fromAccount, fromAccount)
|
4465
|
+
toAccountId = self.safe_string(accountsByType, toAccount, toAccount)
|
4466
|
+
amountString = self.currency_to_precision(code, amount)
|
4467
|
+
request = {
|
4468
|
+
'bizId': self.uuid(),
|
4469
|
+
'currency': currency['id'],
|
4470
|
+
'amount': amountString,
|
4471
|
+
'from': fromAccountId,
|
4472
|
+
'to': toAccountId,
|
4473
|
+
}
|
4474
|
+
response = await self.privateSpotPostBalanceTransfer(self.extend(request, params))
|
4475
|
+
#
|
4476
|
+
# {
|
4477
|
+
# info: {rc: '0', mc: 'SUCCESS', ma: [], result: '226971333791398656'},
|
4478
|
+
# id: '226971333791398656',
|
4479
|
+
# timestamp: None,
|
4480
|
+
# datetime: None,
|
4481
|
+
# currency: None,
|
4482
|
+
# amount: None,
|
4483
|
+
# fromAccount: None,
|
4484
|
+
# toAccount: None,
|
4485
|
+
# status: None
|
4486
|
+
# }
|
4487
|
+
#
|
4488
|
+
return self.parse_transfer(response, currency)
|
4489
|
+
|
4490
|
+
def parse_transfer(self, transfer, currency=None):
|
4491
|
+
return {
|
4492
|
+
'info': transfer,
|
4493
|
+
'id': self.safe_string(transfer, 'result'),
|
4494
|
+
'timestamp': None,
|
4495
|
+
'datetime': None,
|
4496
|
+
'currency': None,
|
4497
|
+
'amount': None,
|
4498
|
+
'fromAccount': None,
|
4499
|
+
'toAccount': None,
|
4500
|
+
'status': None,
|
4501
|
+
}
|
4502
|
+
|
4503
|
+
def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
|
4504
|
+
#
|
4505
|
+
# spot: error
|
4506
|
+
#
|
4507
|
+
# {
|
4508
|
+
# "rc": 1,
|
4509
|
+
# "mc": "AUTH_103",
|
4510
|
+
# "ma": [],
|
4511
|
+
# "result": null
|
4512
|
+
# }
|
4513
|
+
#
|
4514
|
+
# spot: success
|
4515
|
+
#
|
4516
|
+
# {
|
4517
|
+
# "returnCode": 0,
|
4518
|
+
# "msgInfo": "success",
|
4519
|
+
# "error": null,
|
4520
|
+
# "result": []
|
4521
|
+
# }
|
4522
|
+
#
|
4523
|
+
# swap and future: error
|
4524
|
+
#
|
4525
|
+
# {
|
4526
|
+
# "returnCode": 1,
|
4527
|
+
# "msgInfo": "failure",
|
4528
|
+
# "error": {
|
4529
|
+
# "code": "403",
|
4530
|
+
# "msg": "invalid signature"
|
4531
|
+
# },
|
4532
|
+
# "result": null
|
4533
|
+
# }
|
4534
|
+
#
|
4535
|
+
# swap and future: success
|
4536
|
+
#
|
4537
|
+
# {
|
4538
|
+
# "returnCode": 0,
|
4539
|
+
# "msgInfo": "success",
|
4540
|
+
# "error": null,
|
4541
|
+
# "result": null
|
4542
|
+
# }
|
4543
|
+
#
|
4544
|
+
# other:
|
4545
|
+
#
|
4546
|
+
# {
|
4547
|
+
# "rc": 0,
|
4548
|
+
# "mc": "SUCCESS",
|
4549
|
+
# "ma": [],
|
4550
|
+
# "result": {}
|
4551
|
+
# }
|
4552
|
+
#
|
4553
|
+
status = self.safe_string_upper_2(response, 'msgInfo', 'mc')
|
4554
|
+
if status is not None and status != 'SUCCESS':
|
4555
|
+
feedback = self.id + ' ' + body
|
4556
|
+
error = self.safe_value(response, 'error', {})
|
4557
|
+
spotErrorCode = self.safe_string(response, 'mc')
|
4558
|
+
errorCode = self.safe_string(error, 'code', spotErrorCode)
|
4559
|
+
spotMessage = self.safe_string(response, 'msgInfo')
|
4560
|
+
message = self.safe_string(error, 'msg', spotMessage)
|
4561
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
4562
|
+
self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
|
4563
|
+
raise ExchangeError(feedback)
|
4564
|
+
return None
|
4565
|
+
|
4566
|
+
def sign(self, path, api=[], method='GET', params={}, headers=None, body=None):
|
4567
|
+
signed = api[0] == 'private'
|
4568
|
+
endpoint = api[1]
|
4569
|
+
request = '/' + self.implode_params(path, params)
|
4570
|
+
payload = None
|
4571
|
+
if (endpoint == 'spot') or (endpoint == 'user'):
|
4572
|
+
if signed:
|
4573
|
+
payload = '/' + self.version + request
|
4574
|
+
else:
|
4575
|
+
payload = '/' + self.version + '/public' + request
|
4576
|
+
else:
|
4577
|
+
payload = request
|
4578
|
+
url = self.urls['api'][endpoint] + payload
|
4579
|
+
query = self.omit(params, self.extract_params(path))
|
4580
|
+
urlencoded = self.urlencode(self.keysort(query))
|
4581
|
+
headers = {
|
4582
|
+
'Content-Type': 'application/json',
|
4583
|
+
}
|
4584
|
+
if signed:
|
4585
|
+
self.check_required_credentials()
|
4586
|
+
defaultRecvWindow = self.safe_string(self.options, 'recvWindow')
|
4587
|
+
recvWindow = self.safe_string(query, 'recvWindow', defaultRecvWindow)
|
4588
|
+
timestamp = self.number_to_string(self.nonce())
|
4589
|
+
body = query
|
4590
|
+
if (payload == '/v4/order') or (payload == '/future/trade/v1/order/create') or (payload == '/future/trade/v1/entrust/create-plan') or (payload == '/future/trade/v1/entrust/create-profit') or (payload == '/future/trade/v1/order/create-batch'):
|
4591
|
+
id = 'CCXT'
|
4592
|
+
if payload.find('future') > -1:
|
4593
|
+
body['clientMedia'] = id
|
4594
|
+
else:
|
4595
|
+
body['media'] = id
|
4596
|
+
isUndefinedBody = ((method == 'GET') or (path == 'order/{orderId}') or (path == 'ws-token'))
|
4597
|
+
body = None if isUndefinedBody else self.json(body)
|
4598
|
+
payloadString = None
|
4599
|
+
if (endpoint == 'spot') or (endpoint == 'user'):
|
4600
|
+
payloadString = 'xt-validate-algorithms=HmacSHA256&xt-validate-appkey=' + self.apiKey + '&xt-validate-recvwindow=' + recvWindow + '&xt-validate-t' + 'imestamp=' + timestamp
|
4601
|
+
if isUndefinedBody:
|
4602
|
+
if urlencoded:
|
4603
|
+
url += '?' + urlencoded
|
4604
|
+
payloadString += '#' + method + '#' + payload + '#' + self.rawencode(self.keysort(query))
|
4605
|
+
else:
|
4606
|
+
payloadString += '#' + method + '#' + payload
|
4607
|
+
else:
|
4608
|
+
payloadString += '#' + method + '#' + payload + '#' + body
|
4609
|
+
headers['xt-validate-algorithms'] = 'HmacSHA256'
|
4610
|
+
headers['xt-validate-recvwindow'] = recvWindow
|
4611
|
+
else:
|
4612
|
+
payloadString = 'xt-validate-appkey=' + self.apiKey + '&xt-validate-t' + 'imestamp=' + timestamp # we can't glue timestamp, breaks in php
|
4613
|
+
if method == 'GET':
|
4614
|
+
if urlencoded:
|
4615
|
+
url += '?' + urlencoded
|
4616
|
+
payloadString += '#' + payload + '#' + urlencoded
|
4617
|
+
else:
|
4618
|
+
payloadString += '#' + payload
|
4619
|
+
else:
|
4620
|
+
payloadString += '#' + payload + '#' + body
|
4621
|
+
signature = self.hmac(self.encode(payloadString), self.encode(self.secret), hashlib.sha256)
|
4622
|
+
headers['xt-validate-appkey'] = self.apiKey
|
4623
|
+
headers['xt-validate-timestamp'] = timestamp
|
4624
|
+
headers['xt-validate-signature'] = signature
|
4625
|
+
else:
|
4626
|
+
if urlencoded:
|
4627
|
+
url += '?' + urlencoded
|
4628
|
+
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|