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
@@ -5,10 +5,14 @@
|
|
5
5
|
|
6
6
|
from ccxt.async_support.base.exchange import Exchange
|
7
7
|
from ccxt.abstract.hyperliquid import ImplicitAPI
|
8
|
-
|
8
|
+
import asyncio
|
9
|
+
import math
|
10
|
+
from ccxt.base.types import Balances, Currencies, Currency, Int, LedgerEntry, MarginModification, Market, Num, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFeeInterface, Transaction, TransferEntry
|
9
11
|
from typing import List
|
10
12
|
from ccxt.base.errors import ExchangeError
|
11
13
|
from ccxt.base.errors import ArgumentsRequired
|
14
|
+
from ccxt.base.errors import BadRequest
|
15
|
+
from ccxt.base.errors import InsufficientFunds
|
12
16
|
from ccxt.base.errors import InvalidOrder
|
13
17
|
from ccxt.base.errors import OrderNotFound
|
14
18
|
from ccxt.base.errors import NotSupported
|
@@ -28,11 +32,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
28
32
|
'countries': [],
|
29
33
|
'version': 'v1',
|
30
34
|
'rateLimit': 50, # 1200 requests per minute, 20 request per second
|
31
|
-
'certified':
|
35
|
+
'certified': True,
|
32
36
|
'pro': True,
|
37
|
+
'dex': True,
|
33
38
|
'has': {
|
34
39
|
'CORS': None,
|
35
|
-
'spot':
|
40
|
+
'spot': True,
|
36
41
|
'margin': False,
|
37
42
|
'swap': True,
|
38
43
|
'future': True,
|
@@ -41,8 +46,10 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
41
46
|
'borrowCrossMargin': False,
|
42
47
|
'borrowIsolatedMargin': False,
|
43
48
|
'cancelAllOrders': False,
|
49
|
+
'cancelAllOrdersAfter': True,
|
44
50
|
'cancelOrder': True,
|
45
51
|
'cancelOrders': True,
|
52
|
+
'cancelOrdersForSymbols': True,
|
46
53
|
'closeAllPositions': False,
|
47
54
|
'closePosition': False,
|
48
55
|
'createMarketBuyOrderWithCost': False,
|
@@ -50,31 +57,34 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
50
57
|
'createMarketSellOrderWithCost': False,
|
51
58
|
'createOrder': True,
|
52
59
|
'createOrders': True,
|
53
|
-
'createReduceOnlyOrder':
|
60
|
+
'createReduceOnlyOrder': True,
|
61
|
+
'createStopOrder': True,
|
62
|
+
'createTriggerOrder': True,
|
54
63
|
'editOrder': True,
|
55
64
|
'fetchAccounts': False,
|
56
65
|
'fetchBalance': True,
|
57
66
|
'fetchBorrowInterest': False,
|
58
67
|
'fetchBorrowRateHistories': False,
|
59
68
|
'fetchBorrowRateHistory': False,
|
60
|
-
'
|
69
|
+
'fetchCanceledAndClosedOrders': True,
|
70
|
+
'fetchCanceledOrders': True,
|
61
71
|
'fetchClosedOrders': True,
|
62
72
|
'fetchCrossBorrowRate': False,
|
63
73
|
'fetchCrossBorrowRates': False,
|
64
74
|
'fetchCurrencies': True,
|
65
75
|
'fetchDepositAddress': False,
|
66
76
|
'fetchDepositAddresses': False,
|
67
|
-
'fetchDeposits':
|
77
|
+
'fetchDeposits': True,
|
68
78
|
'fetchDepositWithdrawFee': 'emulated',
|
69
79
|
'fetchDepositWithdrawFees': False,
|
70
80
|
'fetchFundingHistory': False,
|
71
81
|
'fetchFundingRate': False,
|
72
82
|
'fetchFundingRateHistory': True,
|
73
|
-
'fetchFundingRates':
|
83
|
+
'fetchFundingRates': True,
|
74
84
|
'fetchIndexOHLCV': False,
|
75
85
|
'fetchIsolatedBorrowRate': False,
|
76
86
|
'fetchIsolatedBorrowRates': False,
|
77
|
-
'fetchLedger':
|
87
|
+
'fetchLedger': True,
|
78
88
|
'fetchLeverage': False,
|
79
89
|
'fetchLeverageTiers': False,
|
80
90
|
'fetchLiquidations': False,
|
@@ -85,31 +95,33 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
85
95
|
'fetchMyLiquidations': False,
|
86
96
|
'fetchMyTrades': True,
|
87
97
|
'fetchOHLCV': True,
|
88
|
-
'fetchOpenInterest':
|
98
|
+
'fetchOpenInterest': True,
|
89
99
|
'fetchOpenInterestHistory': False,
|
100
|
+
'fetchOpenInterests': True,
|
90
101
|
'fetchOpenOrders': True,
|
91
102
|
'fetchOrder': True,
|
92
103
|
'fetchOrderBook': True,
|
93
|
-
'fetchOrders':
|
104
|
+
'fetchOrders': True,
|
94
105
|
'fetchOrderTrades': False,
|
95
106
|
'fetchPosition': True,
|
96
107
|
'fetchPositionMode': False,
|
97
108
|
'fetchPositions': True,
|
98
109
|
'fetchPositionsRisk': False,
|
99
110
|
'fetchPremiumIndexOHLCV': False,
|
100
|
-
'fetchTicker':
|
101
|
-
'fetchTickers':
|
111
|
+
'fetchTicker': 'emulated',
|
112
|
+
'fetchTickers': True,
|
102
113
|
'fetchTime': False,
|
103
114
|
'fetchTrades': True,
|
104
|
-
'fetchTradingFee':
|
115
|
+
'fetchTradingFee': True,
|
105
116
|
'fetchTradingFees': False,
|
106
117
|
'fetchTransfer': False,
|
107
118
|
'fetchTransfers': False,
|
108
119
|
'fetchWithdrawal': False,
|
109
|
-
'fetchWithdrawals':
|
120
|
+
'fetchWithdrawals': True,
|
110
121
|
'reduceMargin': True,
|
111
122
|
'repayCrossMargin': False,
|
112
123
|
'repayIsolatedMargin': False,
|
124
|
+
'sandbox': True,
|
113
125
|
'setLeverage': True,
|
114
126
|
'setMarginMode': True,
|
115
127
|
'setPositionMode': False,
|
@@ -125,12 +137,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
125
137
|
'1h': '1h',
|
126
138
|
'2h': '2h',
|
127
139
|
'4h': '4h',
|
128
|
-
'
|
140
|
+
'8h': '8h',
|
129
141
|
'12h': '12h',
|
130
142
|
'1d': '1d',
|
131
143
|
'3d': '3d',
|
132
144
|
'1w': '1w',
|
133
|
-
'1M': '
|
145
|
+
'1M': '1M',
|
134
146
|
},
|
135
147
|
'hostname': 'hyperliquid.xyz',
|
136
148
|
'urls': {
|
@@ -151,7 +163,17 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
151
163
|
'api': {
|
152
164
|
'public': {
|
153
165
|
'post': {
|
154
|
-
'info':
|
166
|
+
'info': {
|
167
|
+
'cost': 20,
|
168
|
+
'byType': {
|
169
|
+
'l2Book': 2,
|
170
|
+
'allMids': 2,
|
171
|
+
'clearinghouseState': 2,
|
172
|
+
'orderStatus': 2,
|
173
|
+
'spotClearinghouseState': 2,
|
174
|
+
'exchangeStatus': 2,
|
175
|
+
},
|
176
|
+
},
|
155
177
|
},
|
156
178
|
},
|
157
179
|
'private': {
|
@@ -165,6 +187,10 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
165
187
|
'taker': self.parse_number('0.00035'),
|
166
188
|
'maker': self.parse_number('0.0001'),
|
167
189
|
},
|
190
|
+
'spot': {
|
191
|
+
'taker': self.parse_number('0.00035'),
|
192
|
+
'maker': self.parse_number('0.0001'),
|
193
|
+
},
|
168
194
|
},
|
169
195
|
'requiredCredentials': {
|
170
196
|
'apiKey': False,
|
@@ -186,30 +212,131 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
186
212
|
'No liquidity available for market order.': InvalidOrder,
|
187
213
|
'Order was never placed, already canceled, or filled.': OrderNotFound,
|
188
214
|
'User or API Wallet ': InvalidOrder,
|
215
|
+
'Order has invalid size': InvalidOrder,
|
216
|
+
'Order price cannot be more than 80% away from the reference price': InvalidOrder,
|
217
|
+
'Order has zero size.': InvalidOrder,
|
218
|
+
'Insufficient spot balance asset': InsufficientFunds,
|
189
219
|
},
|
190
220
|
},
|
191
221
|
'precisionMode': TICK_SIZE,
|
192
222
|
'commonCurrencies': {
|
193
223
|
},
|
194
224
|
'options': {
|
225
|
+
'defaultType': 'swap',
|
195
226
|
'sandboxMode': False,
|
196
227
|
'defaultSlippage': 0.05,
|
197
228
|
'zeroAddress': '0x0000000000000000000000000000000000000000',
|
198
229
|
},
|
230
|
+
'features': {
|
231
|
+
'default': {
|
232
|
+
'sandbox': True,
|
233
|
+
'createOrder': {
|
234
|
+
'marginMode': False,
|
235
|
+
'triggerPrice': False,
|
236
|
+
'triggerPriceType': None,
|
237
|
+
'triggerDirection': False,
|
238
|
+
'stopLossPrice': False,
|
239
|
+
'takeProfitPrice': False,
|
240
|
+
'attachedStopLossTakeProfit': None,
|
241
|
+
'timeInForce': {
|
242
|
+
'IOC': True,
|
243
|
+
'FOK': False,
|
244
|
+
'PO': True,
|
245
|
+
'GTD': False,
|
246
|
+
},
|
247
|
+
'hedged': False,
|
248
|
+
'trailing': False,
|
249
|
+
'leverage': False,
|
250
|
+
'marketBuyByCost': False,
|
251
|
+
'marketBuyRequiresPrice': False,
|
252
|
+
'selfTradePrevention': False,
|
253
|
+
'iceberg': False,
|
254
|
+
},
|
255
|
+
'createOrders': {
|
256
|
+
'max': 1000,
|
257
|
+
},
|
258
|
+
'fetchMyTrades': {
|
259
|
+
'marginMode': False,
|
260
|
+
'limit': 2000,
|
261
|
+
'daysBack': None,
|
262
|
+
'untilDays': None,
|
263
|
+
},
|
264
|
+
'fetchOrder': {
|
265
|
+
'marginMode': False,
|
266
|
+
'trigger': False,
|
267
|
+
'trailing': False,
|
268
|
+
},
|
269
|
+
'fetchOpenOrders': {
|
270
|
+
'marginMode': False,
|
271
|
+
'limit': 2000,
|
272
|
+
'trigger': False,
|
273
|
+
'trailing': False,
|
274
|
+
},
|
275
|
+
'fetchOrders': {
|
276
|
+
'marginMode': False,
|
277
|
+
'limit': 2000,
|
278
|
+
'daysBack': None,
|
279
|
+
'untilDays': None,
|
280
|
+
'trigger': False,
|
281
|
+
'trailing': False,
|
282
|
+
},
|
283
|
+
'fetchClosedOrders': {
|
284
|
+
'marginMode': False,
|
285
|
+
'limit': 2000,
|
286
|
+
'daysBack': None,
|
287
|
+
'daysBackCanceled': None,
|
288
|
+
'untilDays': None,
|
289
|
+
'trigger': False,
|
290
|
+
'trailing': False,
|
291
|
+
},
|
292
|
+
'fetchOHLCV': {
|
293
|
+
'limit': 5000,
|
294
|
+
},
|
295
|
+
},
|
296
|
+
'spot': {
|
297
|
+
'extends': 'default',
|
298
|
+
},
|
299
|
+
'forPerps': {
|
300
|
+
'extends': 'default',
|
301
|
+
'createOrder': {
|
302
|
+
'stopLossPrice': True,
|
303
|
+
'takeProfitPrice': True,
|
304
|
+
'attachedStopLossTakeProfit': None, # todo, in two orders
|
305
|
+
},
|
306
|
+
},
|
307
|
+
'swap': {
|
308
|
+
'linear': {
|
309
|
+
'extends': 'forPerps',
|
310
|
+
},
|
311
|
+
'inverse': {
|
312
|
+
'extends': 'forPerps',
|
313
|
+
},
|
314
|
+
},
|
315
|
+
'future': {
|
316
|
+
'linear': {
|
317
|
+
'extends': 'forPerps',
|
318
|
+
},
|
319
|
+
'inverse': {
|
320
|
+
'extends': 'forPerps',
|
321
|
+
},
|
322
|
+
},
|
323
|
+
},
|
199
324
|
})
|
200
325
|
|
201
326
|
def set_sandbox_mode(self, enabled):
|
202
327
|
super(hyperliquid, self).set_sandbox_mode(enabled)
|
203
328
|
self.options['sandboxMode'] = enabled
|
204
329
|
|
205
|
-
async def fetch_currencies(self, params={}):
|
330
|
+
async def fetch_currencies(self, params={}) -> Currencies:
|
206
331
|
"""
|
207
332
|
fetches all available currencies on an exchange
|
208
|
-
|
333
|
+
|
334
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-metadata
|
335
|
+
|
209
336
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
210
337
|
:returns dict: an associative dictionary of currencies
|
211
338
|
"""
|
212
|
-
request = {
|
339
|
+
request: dict = {
|
213
340
|
'type': 'meta',
|
214
341
|
}
|
215
342
|
response = await self.publicPostInfo(self.extend(request, params))
|
@@ -228,7 +355,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
228
355
|
# ]
|
229
356
|
#
|
230
357
|
meta = self.safe_list(response, 'universe', [])
|
231
|
-
result = {}
|
358
|
+
result: dict = {}
|
232
359
|
for i in range(0, len(meta)):
|
233
360
|
data = self.safe_dict(meta, i, {})
|
234
361
|
id = i
|
@@ -245,19 +372,48 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
245
372
|
'withdraw': None,
|
246
373
|
'networks': None,
|
247
374
|
'fee': None,
|
248
|
-
|
249
|
-
|
375
|
+
'limits': {
|
376
|
+
'amount': {
|
377
|
+
'min': None,
|
378
|
+
'max': None,
|
379
|
+
},
|
380
|
+
'withdraw': {
|
381
|
+
'min': None,
|
382
|
+
'max': None,
|
383
|
+
},
|
384
|
+
},
|
250
385
|
}
|
251
386
|
return result
|
252
387
|
|
253
|
-
async def fetch_markets(self, params={}):
|
388
|
+
async def fetch_markets(self, params={}) -> List[Market]:
|
254
389
|
"""
|
255
390
|
retrieves data on all markets for hyperliquid
|
256
|
-
|
391
|
+
|
392
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
393
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-spot-asset-contexts
|
394
|
+
|
395
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
396
|
+
:returns dict[]: an array of objects representing market data
|
397
|
+
"""
|
398
|
+
rawPromises = [
|
399
|
+
self.fetch_swap_markets(params),
|
400
|
+
self.fetch_spot_markets(params),
|
401
|
+
]
|
402
|
+
promises = await asyncio.gather(*rawPromises)
|
403
|
+
swapMarkets = promises[0]
|
404
|
+
spotMarkets = promises[1]
|
405
|
+
return self.array_concat(swapMarkets, spotMarkets)
|
406
|
+
|
407
|
+
async def fetch_swap_markets(self, params={}) -> List[Market]:
|
408
|
+
"""
|
409
|
+
retrieves data on all swap markets for hyperliquid
|
410
|
+
|
411
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
412
|
+
|
257
413
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
258
414
|
:returns dict[]: an array of objects representing market data
|
259
415
|
"""
|
260
|
-
request = {
|
416
|
+
request: dict = {
|
261
417
|
'type': 'metaAndAssetCtxs',
|
262
418
|
}
|
263
419
|
response = await self.publicPostInfo(self.extend(request, params))
|
@@ -291,20 +447,213 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
291
447
|
# ]
|
292
448
|
# ]
|
293
449
|
#
|
450
|
+
#
|
294
451
|
meta = self.safe_dict(response, 0, {})
|
295
|
-
|
296
|
-
assetCtxs = self.
|
452
|
+
universe = self.safe_list(meta, 'universe', [])
|
453
|
+
assetCtxs = self.safe_list(response, 1, [])
|
297
454
|
result = []
|
298
|
-
for i in range(0, len(
|
455
|
+
for i in range(0, len(universe)):
|
299
456
|
data = self.extend(
|
300
|
-
self.safe_dict(
|
457
|
+
self.safe_dict(universe, i, {}),
|
301
458
|
self.safe_dict(assetCtxs, i, {})
|
302
459
|
)
|
303
460
|
data['baseId'] = i
|
304
461
|
result.append(data)
|
305
462
|
return self.parse_markets(result)
|
306
463
|
|
307
|
-
def
|
464
|
+
def calculate_price_precision(self, price: float, amountPrecision: float, maxDecimals: float):
|
465
|
+
"""
|
466
|
+
Helper function to calculate the Hyperliquid DECIMAL_PLACES price precision
|
467
|
+
:param float price: the price to use in the calculation
|
468
|
+
:param int amountPrecision: the amountPrecision to use in the calculation
|
469
|
+
:param int maxDecimals: the maxDecimals to use in the calculation
|
470
|
+
:returns int: The calculated price precision
|
471
|
+
"""
|
472
|
+
pricePrecision = 0
|
473
|
+
priceStr = self.number_to_string(price)
|
474
|
+
if priceStr is None:
|
475
|
+
return 0
|
476
|
+
priceSplitted = priceStr.split('.')
|
477
|
+
if Precise.string_eq(priceStr, '0'):
|
478
|
+
# Significant digits is always hasattr(self, 5) case
|
479
|
+
significantDigits = 5
|
480
|
+
# Integer digits is always hasattr(self, 0) case(0 doesn't count)
|
481
|
+
integerDigits = 0
|
482
|
+
# Calculate the price precision
|
483
|
+
pricePrecision = min(maxDecimals - amountPrecision, significantDigits - integerDigits)
|
484
|
+
elif Precise.string_gt(priceStr, '0') and Precise.string_lt(priceStr, '1'):
|
485
|
+
# Significant digits, always hasattr(self, 5) case
|
486
|
+
significantDigits = 5
|
487
|
+
# Get the part after the decimal separator
|
488
|
+
decimalPart = self.safe_string(priceSplitted, 1, '')
|
489
|
+
# Count the number of leading zeros in the decimal part
|
490
|
+
leadingZeros = 0
|
491
|
+
while((leadingZeros <= len(decimalPart)) and (decimalPart[leadingZeros] == '0')):
|
492
|
+
leadingZeros = leadingZeros + 1
|
493
|
+
# Calculate price precision based on leading zeros and significant digits
|
494
|
+
pricePrecision = leadingZeros + significantDigits
|
495
|
+
# Calculate the price precision based on maxDecimals - szDecimals and the calculated price precision from the previous step
|
496
|
+
pricePrecision = min(maxDecimals - amountPrecision, pricePrecision)
|
497
|
+
else:
|
498
|
+
# Count the numbers before the decimal separator
|
499
|
+
integerPart = self.safe_string(priceSplitted, 0, '')
|
500
|
+
# Get significant digits, take the max() of 5 and the integer digits count
|
501
|
+
significantDigits = max(5, len(integerPart))
|
502
|
+
# Calculate price precision based on maxDecimals - szDecimals and significantDigits - len(integerPart)
|
503
|
+
pricePrecision = min(maxDecimals - amountPrecision, significantDigits - len(integerPart))
|
504
|
+
return self.parse_to_int(pricePrecision)
|
505
|
+
|
506
|
+
async def fetch_spot_markets(self, params={}) -> List[Market]:
|
507
|
+
"""
|
508
|
+
retrieves data on all spot markets for hyperliquid
|
509
|
+
|
510
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-spot-asset-contexts
|
511
|
+
|
512
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
513
|
+
:returns dict[]: an array of objects representing market data
|
514
|
+
"""
|
515
|
+
request: dict = {
|
516
|
+
'type': 'spotMetaAndAssetCtxs',
|
517
|
+
}
|
518
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
519
|
+
#
|
520
|
+
# [
|
521
|
+
# {
|
522
|
+
# "tokens": [
|
523
|
+
# {
|
524
|
+
# "name": "USDC",
|
525
|
+
# "szDecimals": 8,
|
526
|
+
# "weiDecimals" 8,
|
527
|
+
# "index": 0,
|
528
|
+
# "tokenId": "0x6d1e7cde53ba9467b783cb7c530ce054",
|
529
|
+
# "isCanonical": True,
|
530
|
+
# "evmContract":null,
|
531
|
+
# "fullName":null
|
532
|
+
# },
|
533
|
+
# {
|
534
|
+
# "name": "PURR",
|
535
|
+
# "szDecimals": 0,
|
536
|
+
# "weiDecimals": 5,
|
537
|
+
# "index": 1,
|
538
|
+
# "tokenId": "0xc1fb593aeffbeb02f85e0308e9956a90",
|
539
|
+
# "isCanonical": True,
|
540
|
+
# "evmContract":null,
|
541
|
+
# "fullName":null
|
542
|
+
# }
|
543
|
+
# ],
|
544
|
+
# "universe": [
|
545
|
+
# {
|
546
|
+
# "name": "PURR/USDC",
|
547
|
+
# "tokens": [1, 0],
|
548
|
+
# "index": 0,
|
549
|
+
# "isCanonical": True
|
550
|
+
# }
|
551
|
+
# ]
|
552
|
+
# },
|
553
|
+
# [
|
554
|
+
# {
|
555
|
+
# "dayNtlVlm":"8906.0",
|
556
|
+
# "markPx":"0.14",
|
557
|
+
# "midPx":"0.209265",
|
558
|
+
# "prevDayPx":"0.20432"
|
559
|
+
# }
|
560
|
+
# ]
|
561
|
+
# ]
|
562
|
+
#
|
563
|
+
first = self.safe_dict(response, 0, {})
|
564
|
+
second = self.safe_list(response, 1, [])
|
565
|
+
meta = self.safe_list(first, 'universe', [])
|
566
|
+
tokens = self.safe_list(first, 'tokens', [])
|
567
|
+
markets = []
|
568
|
+
for i in range(0, len(meta)):
|
569
|
+
market = self.safe_dict(meta, i, {})
|
570
|
+
index = self.safe_integer(market, 'index')
|
571
|
+
extraData = self.safe_dict(second, index, {})
|
572
|
+
marketName = self.safe_string(market, 'name')
|
573
|
+
# if marketName.find('/') < 0:
|
574
|
+
# # there are some weird spot markets in testnet, eg @2
|
575
|
+
# continue
|
576
|
+
# }
|
577
|
+
# marketParts = marketName.split('/')
|
578
|
+
# baseName = self.safe_string(marketParts, 0)
|
579
|
+
# quoteId = self.safe_string(marketParts, 1)
|
580
|
+
fees = self.safe_dict(self.fees, 'spot', {})
|
581
|
+
taker = self.safe_number(fees, 'taker')
|
582
|
+
maker = self.safe_number(fees, 'maker')
|
583
|
+
tokensPos = self.safe_list(market, 'tokens', [])
|
584
|
+
baseTokenPos = self.safe_integer(tokensPos, 0)
|
585
|
+
quoteTokenPos = self.safe_integer(tokensPos, 1)
|
586
|
+
baseTokenInfo = self.safe_dict(tokens, baseTokenPos, {})
|
587
|
+
quoteTokenInfo = self.safe_dict(tokens, quoteTokenPos, {})
|
588
|
+
baseName = self.safe_string(baseTokenInfo, 'name')
|
589
|
+
quoteId = self.safe_string(quoteTokenInfo, 'name')
|
590
|
+
base = self.safe_currency_code(baseName)
|
591
|
+
quote = self.safe_currency_code(quoteId)
|
592
|
+
symbol = base + '/' + quote
|
593
|
+
innerBaseTokenInfo = self.safe_dict(baseTokenInfo, 'spec', baseTokenInfo)
|
594
|
+
# innerQuoteTokenInfo = self.safe_dict(quoteTokenInfo, 'spec', quoteTokenInfo)
|
595
|
+
amountPrecisionStr = self.safe_string(innerBaseTokenInfo, 'szDecimals')
|
596
|
+
amountPrecision = int(amountPrecisionStr)
|
597
|
+
price = self.safe_number(extraData, 'midPx')
|
598
|
+
pricePrecision = self.calculate_price_precision(price, amountPrecision, 8)
|
599
|
+
pricePrecisionStr = self.number_to_string(pricePrecision)
|
600
|
+
# quotePrecision = self.parse_number(self.parse_precision(self.safe_string(innerQuoteTokenInfo, 'szDecimals')))
|
601
|
+
baseId = self.number_to_string(index + 10000)
|
602
|
+
markets.append(self.safe_market_structure({
|
603
|
+
'id': marketName,
|
604
|
+
'symbol': symbol,
|
605
|
+
'base': base,
|
606
|
+
'quote': quote,
|
607
|
+
'settle': None,
|
608
|
+
'baseId': baseId,
|
609
|
+
'quoteId': quoteId,
|
610
|
+
'settleId': None,
|
611
|
+
'type': 'spot',
|
612
|
+
'spot': True,
|
613
|
+
'subType': None,
|
614
|
+
'margin': None,
|
615
|
+
'swap': False,
|
616
|
+
'future': False,
|
617
|
+
'option': False,
|
618
|
+
'active': True,
|
619
|
+
'contract': False,
|
620
|
+
'linear': None,
|
621
|
+
'inverse': None,
|
622
|
+
'taker': taker,
|
623
|
+
'maker': maker,
|
624
|
+
'contractSize': None,
|
625
|
+
'expiry': None,
|
626
|
+
'expiryDatetime': None,
|
627
|
+
'strike': None,
|
628
|
+
'optionType': None,
|
629
|
+
'precision': {
|
630
|
+
'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
|
631
|
+
'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
|
632
|
+
},
|
633
|
+
'limits': {
|
634
|
+
'leverage': {
|
635
|
+
'min': None,
|
636
|
+
'max': None,
|
637
|
+
},
|
638
|
+
'amount': {
|
639
|
+
'min': None,
|
640
|
+
'max': None,
|
641
|
+
},
|
642
|
+
'price': {
|
643
|
+
'min': None,
|
644
|
+
'max': None,
|
645
|
+
},
|
646
|
+
'cost': {
|
647
|
+
'min': self.parse_number('10'),
|
648
|
+
'max': None,
|
649
|
+
},
|
650
|
+
},
|
651
|
+
'created': None,
|
652
|
+
'info': self.extend(extraData, market),
|
653
|
+
}))
|
654
|
+
return markets
|
655
|
+
|
656
|
+
def parse_market(self, market: dict) -> Market:
|
308
657
|
#
|
309
658
|
# {
|
310
659
|
# "maxLeverage": "50",
|
@@ -340,7 +689,16 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
340
689
|
fees = self.safe_dict(self.fees, 'swap', {})
|
341
690
|
taker = self.safe_number(fees, 'taker')
|
342
691
|
maker = self.safe_number(fees, 'maker')
|
343
|
-
|
692
|
+
amountPrecisionStr = self.safe_string(market, 'szDecimals')
|
693
|
+
amountPrecision = int(amountPrecisionStr)
|
694
|
+
price = self.safe_number(market, 'markPx', 0)
|
695
|
+
pricePrecision = self.calculate_price_precision(price, amountPrecision, 6)
|
696
|
+
pricePrecisionStr = self.number_to_string(pricePrecision)
|
697
|
+
isDelisted = self.safe_bool(market, 'isDelisted')
|
698
|
+
active = True
|
699
|
+
if isDelisted is not None:
|
700
|
+
active = not isDelisted
|
701
|
+
return self.safe_market_structure({
|
344
702
|
'id': baseId,
|
345
703
|
'symbol': symbol,
|
346
704
|
'base': base,
|
@@ -355,7 +713,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
355
713
|
'swap': swap,
|
356
714
|
'future': False,
|
357
715
|
'option': False,
|
358
|
-
'active':
|
716
|
+
'active': active,
|
359
717
|
'contract': contract,
|
360
718
|
'linear': True,
|
361
719
|
'inverse': False,
|
@@ -367,13 +725,13 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
367
725
|
'strike': None,
|
368
726
|
'optionType': None,
|
369
727
|
'precision': {
|
370
|
-
'amount': self.parse_number(self.parse_precision(
|
371
|
-
'price':
|
728
|
+
'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
|
729
|
+
'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
|
372
730
|
},
|
373
731
|
'limits': {
|
374
732
|
'leverage': {
|
375
733
|
'min': None,
|
376
|
-
'max':
|
734
|
+
'max': self.safe_integer(market, 'maxLeverage'),
|
377
735
|
},
|
378
736
|
'amount': {
|
379
737
|
'min': None,
|
@@ -384,26 +742,34 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
384
742
|
'max': None,
|
385
743
|
},
|
386
744
|
'cost': {
|
387
|
-
'min':
|
745
|
+
'min': self.parse_number('10'),
|
388
746
|
'max': None,
|
389
747
|
},
|
390
748
|
},
|
391
749
|
'created': None,
|
392
750
|
'info': market,
|
393
|
-
}
|
751
|
+
})
|
394
752
|
|
395
753
|
async def fetch_balance(self, params={}) -> Balances:
|
396
754
|
"""
|
397
755
|
query for balance and get the amount of funds available for trading or funds locked in orders
|
398
|
-
|
756
|
+
|
757
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-a-users-token-balances
|
758
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-users-perpetuals-account-summary
|
759
|
+
|
399
760
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
400
761
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
762
|
+
:param str [params.type]: wallet type, ['spot', 'swap'], defaults to swap
|
401
763
|
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
402
764
|
"""
|
403
765
|
userAddress = None
|
404
766
|
userAddress, params = self.handle_public_address('fetchBalance', params)
|
405
|
-
|
406
|
-
|
767
|
+
type = None
|
768
|
+
type, params = self.handle_market_type_and_params('fetchBalance', None, params)
|
769
|
+
isSpot = (type == 'spot')
|
770
|
+
reqType = 'spotClearinghouseState' if (isSpot) else 'clearinghouseState'
|
771
|
+
request: dict = {
|
772
|
+
'type': reqType,
|
407
773
|
'user': userAddress,
|
408
774
|
}
|
409
775
|
response = await self.publicPostInfo(self.extend(request, params))
|
@@ -426,13 +792,41 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
426
792
|
# "time": "1704261007014",
|
427
793
|
# "withdrawable": "100.0"
|
428
794
|
# }
|
795
|
+
# spot
|
796
|
+
#
|
797
|
+
# {
|
798
|
+
# "balances":[
|
799
|
+
# {
|
800
|
+
# "coin":"USDC",
|
801
|
+
# "hold":"0.0",
|
802
|
+
# "total":"1481.844"
|
803
|
+
# },
|
804
|
+
# {
|
805
|
+
# "coin":"PURR",
|
806
|
+
# "hold":"0.0",
|
807
|
+
# "total":"999.65004"
|
808
|
+
# }
|
809
|
+
# }
|
429
810
|
#
|
811
|
+
balances = self.safe_list(response, 'balances')
|
812
|
+
if balances is not None:
|
813
|
+
spotBalances: dict = {'info': response}
|
814
|
+
for i in range(0, len(balances)):
|
815
|
+
balance = balances[i]
|
816
|
+
code = self.safe_currency_code(self.safe_string(balance, 'coin'))
|
817
|
+
account = self.account()
|
818
|
+
total = self.safe_string(balance, 'total')
|
819
|
+
used = self.safe_string(balance, 'hold')
|
820
|
+
account['total'] = total
|
821
|
+
account['used'] = used
|
822
|
+
spotBalances[code] = account
|
823
|
+
return self.safe_balance(spotBalances)
|
430
824
|
data = self.safe_dict(response, 'marginSummary', {})
|
431
|
-
result = {
|
825
|
+
result: dict = {
|
432
826
|
'info': response,
|
433
827
|
'USDC': {
|
434
|
-
'total': self.
|
435
|
-
'
|
828
|
+
'total': self.safe_number(data, 'accountValue'),
|
829
|
+
'free': self.safe_number(response, 'withdrawable'),
|
436
830
|
},
|
437
831
|
}
|
438
832
|
timestamp = self.safe_integer(response, 'time')
|
@@ -443,7 +837,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
443
837
|
async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
444
838
|
"""
|
445
839
|
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
446
|
-
|
840
|
+
|
841
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#l2-book-snapshot
|
842
|
+
|
447
843
|
:param str symbol: unified symbol of the market to fetch the order book for
|
448
844
|
:param int [limit]: the maximum amount of order book entries to return
|
449
845
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -451,9 +847,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
451
847
|
"""
|
452
848
|
await self.load_markets()
|
453
849
|
market = self.market(symbol)
|
454
|
-
request = {
|
850
|
+
request: dict = {
|
455
851
|
'type': 'l2Book',
|
456
|
-
'coin': market['base'],
|
852
|
+
'coin': market['base'] if market['swap'] else market['id'],
|
457
853
|
}
|
458
854
|
response = await self.publicPostInfo(self.extend(request, params))
|
459
855
|
#
|
@@ -479,17 +875,188 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
479
875
|
# }
|
480
876
|
#
|
481
877
|
data = self.safe_list(response, 'levels', [])
|
482
|
-
result = {
|
878
|
+
result: dict = {
|
483
879
|
'bids': self.safe_list(data, 0, []),
|
484
880
|
'asks': self.safe_list(data, 1, []),
|
485
881
|
}
|
486
882
|
timestamp = self.safe_integer(response, 'time')
|
487
883
|
return self.parse_order_book(result, market['symbol'], timestamp, 'bids', 'asks', 'px', 'sz')
|
488
884
|
|
885
|
+
async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
886
|
+
"""
|
887
|
+
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
888
|
+
|
889
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
890
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-spot-asset-contexts
|
891
|
+
|
892
|
+
:param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
893
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
894
|
+
:param str [params.type]: 'spot' or 'swap', by default fetches both
|
895
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
896
|
+
"""
|
897
|
+
await self.load_markets()
|
898
|
+
symbols = self.market_symbols(symbols)
|
899
|
+
# at self stage, to get tickers data, we use fetchMarkets endpoints
|
900
|
+
response = []
|
901
|
+
type = self.safe_string(params, 'type')
|
902
|
+
params = self.omit(params, 'type')
|
903
|
+
if type == 'spot':
|
904
|
+
response = await self.fetch_spot_markets(params)
|
905
|
+
elif type == 'swap':
|
906
|
+
response = await self.fetch_swap_markets(params)
|
907
|
+
else:
|
908
|
+
response = await self.fetch_markets(params)
|
909
|
+
# same response "fetchMarkets"
|
910
|
+
result: dict = {}
|
911
|
+
for i in range(0, len(response)):
|
912
|
+
market = response[i]
|
913
|
+
info = market['info']
|
914
|
+
ticker = self.parse_ticker(info, market)
|
915
|
+
symbol = self.safe_string(ticker, 'symbol')
|
916
|
+
result[symbol] = ticker
|
917
|
+
return self.filter_by_array_tickers(result, 'symbol', symbols)
|
918
|
+
|
919
|
+
async def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
|
920
|
+
"""
|
921
|
+
retrieves data on all swap markets for hyperliquid
|
922
|
+
|
923
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
924
|
+
|
925
|
+
:param str[] [symbols]: list of unified market symbols
|
926
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
927
|
+
:returns dict[]: an array of objects representing market data
|
928
|
+
"""
|
929
|
+
request: dict = {
|
930
|
+
'type': 'metaAndAssetCtxs',
|
931
|
+
}
|
932
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
933
|
+
#
|
934
|
+
# [
|
935
|
+
# {
|
936
|
+
# "universe": [
|
937
|
+
# {
|
938
|
+
# "maxLeverage": 50,
|
939
|
+
# "name": "SOL",
|
940
|
+
# "onlyIsolated": False,
|
941
|
+
# "szDecimals": 2
|
942
|
+
# }
|
943
|
+
# ]
|
944
|
+
# },
|
945
|
+
# [
|
946
|
+
# {
|
947
|
+
# "dayNtlVlm": "9450588.2273",
|
948
|
+
# "funding": "0.0000198",
|
949
|
+
# "impactPxs": [
|
950
|
+
# "108.04",
|
951
|
+
# "108.06"
|
952
|
+
# ],
|
953
|
+
# "markPx": "108.04",
|
954
|
+
# "midPx": "108.05",
|
955
|
+
# "openInterest": "10764.48",
|
956
|
+
# "oraclePx": "107.99",
|
957
|
+
# "premium": "0.00055561",
|
958
|
+
# "prevDayPx": "111.81"
|
959
|
+
# }
|
960
|
+
# ]
|
961
|
+
# ]
|
962
|
+
#
|
963
|
+
#
|
964
|
+
meta = self.safe_dict(response, 0, {})
|
965
|
+
universe = self.safe_list(meta, 'universe', [])
|
966
|
+
assetCtxs = self.safe_list(response, 1, [])
|
967
|
+
result = []
|
968
|
+
for i in range(0, len(universe)):
|
969
|
+
data = self.extend(
|
970
|
+
self.safe_dict(universe, i, {}),
|
971
|
+
self.safe_dict(assetCtxs, i, {})
|
972
|
+
)
|
973
|
+
result.append(data)
|
974
|
+
return self.parse_funding_rates(result, symbols)
|
975
|
+
|
976
|
+
def parse_funding_rate(self, info, market: Market = None) -> FundingRate:
|
977
|
+
#
|
978
|
+
# {
|
979
|
+
# "maxLeverage": "50",
|
980
|
+
# "name": "ETH",
|
981
|
+
# "onlyIsolated": False,
|
982
|
+
# "szDecimals": "4",
|
983
|
+
# "dayNtlVlm": "1709813.11535",
|
984
|
+
# "funding": "0.00004807",
|
985
|
+
# "impactPxs": [
|
986
|
+
# "2369.3",
|
987
|
+
# "2369.6"
|
988
|
+
# ],
|
989
|
+
# "markPx": "2369.6",
|
990
|
+
# "midPx": "2369.45",
|
991
|
+
# "openInterest": "1815.4712",
|
992
|
+
# "oraclePx": "2367.3",
|
993
|
+
# "premium": "0.00090821",
|
994
|
+
# "prevDayPx": "2381.5"
|
995
|
+
# }
|
996
|
+
#
|
997
|
+
base = self.safe_string(info, 'name')
|
998
|
+
marketId = self.coin_to_market_id(base)
|
999
|
+
symbol = self.safe_symbol(marketId, market)
|
1000
|
+
funding = self.safe_number(info, 'funding')
|
1001
|
+
markPx = self.safe_number(info, 'markPx')
|
1002
|
+
oraclePx = self.safe_number(info, 'oraclePx')
|
1003
|
+
fundingTimestamp = (int(math.floor(self.milliseconds()) / 60 / 60 / 1000) + 1) * 60 * 60 * 1000
|
1004
|
+
return {
|
1005
|
+
'info': info,
|
1006
|
+
'symbol': symbol,
|
1007
|
+
'markPrice': markPx,
|
1008
|
+
'indexPrice': oraclePx,
|
1009
|
+
'interestRate': None,
|
1010
|
+
'estimatedSettlePrice': None,
|
1011
|
+
'timestamp': None,
|
1012
|
+
'datetime': None,
|
1013
|
+
'fundingRate': funding,
|
1014
|
+
'fundingTimestamp': fundingTimestamp,
|
1015
|
+
'fundingDatetime': self.iso8601(fundingTimestamp),
|
1016
|
+
'nextFundingRate': None,
|
1017
|
+
'nextFundingTimestamp': None,
|
1018
|
+
'nextFundingDatetime': None,
|
1019
|
+
'previousFundingRate': None,
|
1020
|
+
'previousFundingTimestamp': None,
|
1021
|
+
'previousFundingDatetime': None,
|
1022
|
+
'interval': '1h',
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
|
1026
|
+
#
|
1027
|
+
# {
|
1028
|
+
# "prevDayPx": "3400.5",
|
1029
|
+
# "dayNtlVlm": "511297257.47936022",
|
1030
|
+
# "markPx": "3464.7",
|
1031
|
+
# "midPx": "3465.05",
|
1032
|
+
# "oraclePx": "3460.1", # only in swap
|
1033
|
+
# "openInterest": "64638.1108", # only in swap
|
1034
|
+
# "premium": "0.00141614", # only in swap
|
1035
|
+
# "funding": "0.00008727", # only in swap
|
1036
|
+
# "impactPxs": ["3465.0", "3465.1"], # only in swap
|
1037
|
+
# "coin": "PURR", # only in spot
|
1038
|
+
# "circulatingSupply": "998949190.03400207", # only in spot
|
1039
|
+
# },
|
1040
|
+
#
|
1041
|
+
bidAsk = self.safe_list(ticker, 'impactPxs')
|
1042
|
+
return self.safe_ticker({
|
1043
|
+
'symbol': market['symbol'],
|
1044
|
+
'timestamp': None,
|
1045
|
+
'datetime': None,
|
1046
|
+
'previousClose': self.safe_number(ticker, 'prevDayPx'),
|
1047
|
+
'close': self.safe_number(ticker, 'midPx'),
|
1048
|
+
'bid': self.safe_number(bidAsk, 0),
|
1049
|
+
'ask': self.safe_number(bidAsk, 1),
|
1050
|
+
'quoteVolume': self.safe_number(ticker, 'dayNtlVlm'),
|
1051
|
+
'info': ticker,
|
1052
|
+
}, market)
|
1053
|
+
|
489
1054
|
async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
490
1055
|
"""
|
491
1056
|
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
492
|
-
|
1057
|
+
|
1058
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#candle-snapshot
|
1059
|
+
|
493
1060
|
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
494
1061
|
:param str timeframe: the length of time each candle represents, support '1m', '15m', '1h', '1d'
|
495
1062
|
:param int [since]: timestamp in ms of the earliest candle to fetch
|
@@ -501,16 +1068,22 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
501
1068
|
await self.load_markets()
|
502
1069
|
market = self.market(symbol)
|
503
1070
|
until = self.safe_integer(params, 'until', self.milliseconds())
|
1071
|
+
useTail = since is None
|
1072
|
+
originalSince = since
|
504
1073
|
if since is None:
|
505
|
-
|
506
|
-
|
507
|
-
|
1074
|
+
if limit is not None:
|
1075
|
+
# optimization if limit is provided
|
1076
|
+
timeframeInMilliseconds = self.parse_timeframe(timeframe) * 1000
|
1077
|
+
since = self.sum(until, timeframeInMilliseconds * limit * -1)
|
1078
|
+
useTail = False
|
1079
|
+
else:
|
1080
|
+
since = 0
|
508
1081
|
params = self.omit(params, ['until'])
|
509
|
-
request = {
|
1082
|
+
request: dict = {
|
510
1083
|
'type': 'candleSnapshot',
|
511
1084
|
'req': {
|
512
|
-
'coin': market['base'],
|
513
|
-
'interval': timeframe,
|
1085
|
+
'coin': market['base'] if market['swap'] else market['id'],
|
1086
|
+
'interval': self.safe_string(self.timeframes, timeframe, timeframe),
|
514
1087
|
'startTime': since,
|
515
1088
|
'endTime': until,
|
516
1089
|
},
|
@@ -532,7 +1105,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
532
1105
|
# }
|
533
1106
|
# ]
|
534
1107
|
#
|
535
|
-
return self.parse_ohlcvs(response, market, timeframe,
|
1108
|
+
return self.parse_ohlcvs(response, market, timeframe, originalSince, limit, useTail)
|
536
1109
|
|
537
1110
|
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
538
1111
|
#
|
@@ -550,7 +1123,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
550
1123
|
# }
|
551
1124
|
#
|
552
1125
|
return [
|
553
|
-
self.safe_integer(ohlcv, '
|
1126
|
+
self.safe_integer(ohlcv, 't'),
|
554
1127
|
self.safe_number(ohlcv, 'o'),
|
555
1128
|
self.safe_number(ohlcv, 'h'),
|
556
1129
|
self.safe_number(ohlcv, 'l'),
|
@@ -561,8 +1134,10 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
561
1134
|
async def fetch_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
562
1135
|
"""
|
563
1136
|
get the list of most recent trades for a particular symbol
|
564
|
-
|
565
|
-
|
1137
|
+
|
1138
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills
|
1139
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills-by-time
|
1140
|
+
|
566
1141
|
:param str symbol: unified market symbol
|
567
1142
|
:param int [since]: the earliest time in ms to fetch trades for
|
568
1143
|
:param int [limit]: the maximum number of trades structures to retrieve
|
@@ -576,7 +1151,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
576
1151
|
userAddress, params = self.handle_public_address('fetchTrades', params)
|
577
1152
|
await self.load_markets()
|
578
1153
|
market = self.safe_market(symbol)
|
579
|
-
request = {
|
1154
|
+
request: dict = {
|
580
1155
|
'user': userAddress,
|
581
1156
|
}
|
582
1157
|
if since is not None:
|
@@ -612,13 +1187,18 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
612
1187
|
return self.parse_trades(response, market, since, limit)
|
613
1188
|
|
614
1189
|
def amount_to_precision(self, symbol, amount):
|
615
|
-
|
1190
|
+
market = self.market(symbol)
|
1191
|
+
return self.decimal_to_precision(amount, ROUND, market['precision']['amount'], self.precisionMode, self.paddingMode)
|
616
1192
|
|
617
1193
|
def price_to_precision(self, symbol: str, price) -> str:
|
618
1194
|
market = self.market(symbol)
|
619
|
-
|
620
|
-
|
621
|
-
|
1195
|
+
priceStr = self.number_to_string(price)
|
1196
|
+
integerPart = priceStr.split('.')[0]
|
1197
|
+
significantDigits = max(5, len(integerPart))
|
1198
|
+
result = self.decimal_to_precision(price, ROUND, significantDigits, SIGNIFICANT_DIGITS, self.paddingMode)
|
1199
|
+
maxDecimals = 8 if market['spot'] else 6
|
1200
|
+
subtractedValue = maxDecimals - self.precision_from_string(self.safe_string(market['precision'], 'amount'))
|
1201
|
+
return self.decimal_to_precision(result, ROUND, subtractedValue, DECIMAL_PLACES, self.paddingMode)
|
622
1202
|
|
623
1203
|
def hash_message(self, message):
|
624
1204
|
return '0x' + self.hash(message, 'keccak', 'hex')
|
@@ -657,7 +1237,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
657
1237
|
hash = self.action_hash(action, vaultAdress, nonce)
|
658
1238
|
isTestnet = self.safe_bool(self.options, 'sandboxMode', False)
|
659
1239
|
phantomAgent = self.construct_phantom_agent(hash, isTestnet)
|
660
|
-
# data = {
|
1240
|
+
# data: Dict = {
|
661
1241
|
# 'domain': {
|
662
1242
|
# 'chainId': 1337,
|
663
1243
|
# 'name': 'Exchange',
|
@@ -681,13 +1261,13 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
681
1261
|
# }
|
682
1262
|
zeroAddress = self.safe_string(self.options, 'zeroAddress')
|
683
1263
|
chainId = 1337 # check self out
|
684
|
-
domain = {
|
1264
|
+
domain: dict = {
|
685
1265
|
'chainId': chainId,
|
686
1266
|
'name': 'Exchange',
|
687
1267
|
'verifyingContract': zeroAddress,
|
688
1268
|
'version': '1',
|
689
1269
|
}
|
690
|
-
messageTypes = {
|
1270
|
+
messageTypes: dict = {
|
691
1271
|
'Agent': [
|
692
1272
|
{'name': 'source', 'type': 'string'},
|
693
1273
|
{'name': 'connectionId', 'type': 'bytes32'},
|
@@ -697,11 +1277,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
697
1277
|
signature = self.sign_message(msg, self.privateKey)
|
698
1278
|
return signature
|
699
1279
|
|
700
|
-
def
|
1280
|
+
def sign_user_signed_action(self, messageTypes, message):
|
701
1281
|
zeroAddress = self.safe_string(self.options, 'zeroAddress')
|
702
|
-
|
1282
|
+
chainId = 421614 # check self out
|
1283
|
+
domain: dict = {
|
703
1284
|
'chainId': chainId,
|
704
|
-
'name': '
|
1285
|
+
'name': 'HyperliquidSignTransaction',
|
705
1286
|
'verifyingContract': zeroAddress,
|
706
1287
|
'version': '1',
|
707
1288
|
}
|
@@ -709,72 +1290,108 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
709
1290
|
signature = self.sign_message(msg, self.privateKey)
|
710
1291
|
return signature
|
711
1292
|
|
712
|
-
def
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
'UsdTransferSignPayload': [
|
1293
|
+
def build_usd_send_sig(self, message):
|
1294
|
+
messageTypes: dict = {
|
1295
|
+
'HyperliquidTransaction:UsdSend': [
|
1296
|
+
{'name': 'hyperliquidChain', 'type': 'string'},
|
717
1297
|
{'name': 'destination', 'type': 'string'},
|
718
1298
|
{'name': 'amount', 'type': 'string'},
|
719
1299
|
{'name': 'time', 'type': 'uint64'},
|
720
1300
|
],
|
721
1301
|
}
|
722
|
-
return self.
|
1302
|
+
return self.sign_user_signed_action(messageTypes, message)
|
1303
|
+
|
1304
|
+
def build_usd_class_send_sig(self, message):
|
1305
|
+
messageTypes: dict = {
|
1306
|
+
'HyperliquidTransaction:UsdClassTransfer': [
|
1307
|
+
{'name': 'hyperliquidChain', 'type': 'string'},
|
1308
|
+
{'name': 'amount', 'type': 'string'},
|
1309
|
+
{'name': 'toPerp', 'type': 'bool'},
|
1310
|
+
{'name': 'nonce', 'type': 'uint64'},
|
1311
|
+
],
|
1312
|
+
}
|
1313
|
+
return self.sign_user_signed_action(messageTypes, message)
|
723
1314
|
|
724
1315
|
def build_withdraw_sig(self, message):
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
'WithdrawFromBridge2SignPayload': [
|
1316
|
+
messageTypes: dict = {
|
1317
|
+
'HyperliquidTransaction:Withdraw': [
|
1318
|
+
{'name': 'hyperliquidChain', 'type': 'string'},
|
729
1319
|
{'name': 'destination', 'type': 'string'},
|
730
|
-
{'name': '
|
1320
|
+
{'name': 'amount', 'type': 'string'},
|
731
1321
|
{'name': 'time', 'type': 'uint64'},
|
732
1322
|
],
|
733
1323
|
}
|
734
|
-
return self.
|
1324
|
+
return self.sign_user_signed_action(messageTypes, message)
|
735
1325
|
|
736
1326
|
async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
737
1327
|
"""
|
738
1328
|
create a trade order
|
739
|
-
|
1329
|
+
|
1330
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
1331
|
+
|
740
1332
|
:param str symbol: unified symbol of the market to create an order in
|
741
1333
|
:param str type: 'market' or 'limit'
|
742
1334
|
:param str side: 'buy' or 'sell'
|
743
1335
|
:param float amount: how much of currency you want to trade in units of base currency
|
744
|
-
:param float [price]: the price at which the order is to be
|
1336
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
745
1337
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
746
1338
|
:param str [params.timeInForce]: 'Gtc', 'Ioc', 'Alo'
|
747
1339
|
:param bool [params.postOnly]: True or False whether the order is post-only
|
748
1340
|
:param bool [params.reduceOnly]: True or False whether the order is reduce-only
|
749
1341
|
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
750
|
-
:param str [params.clientOrderId]: client order id,
|
1342
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
751
1343
|
:param str [params.slippage]: the slippage for market order
|
1344
|
+
:param str [params.vaultAddress]: the vault address for order
|
752
1345
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
753
1346
|
"""
|
754
1347
|
await self.load_markets()
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
'symbol': symbol,
|
759
|
-
'type': type,
|
760
|
-
'side': side,
|
761
|
-
'amount': amount,
|
762
|
-
'price': price,
|
763
|
-
'params': params,
|
764
|
-
}
|
765
|
-
response = await self.create_orders([order], params)
|
766
|
-
first = self.safe_dict(response, 0)
|
767
|
-
return first
|
1348
|
+
order, globalParams = self.parse_create_order_args(symbol, type, side, amount, price, params)
|
1349
|
+
orders = await self.create_orders([order], globalParams)
|
1350
|
+
return orders[0]
|
768
1351
|
|
769
1352
|
async def create_orders(self, orders: List[OrderRequest], params={}):
|
770
1353
|
"""
|
771
1354
|
create a list of trade orders
|
772
|
-
|
1355
|
+
|
1356
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
1357
|
+
|
773
1358
|
:param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
|
1359
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
774
1360
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
775
1361
|
"""
|
776
|
-
self.check_required_credentials()
|
777
1362
|
await self.load_markets()
|
1363
|
+
request = self.create_orders_request(orders, params)
|
1364
|
+
response = await self.privatePostExchange(request)
|
1365
|
+
#
|
1366
|
+
# {
|
1367
|
+
# "status": "ok",
|
1368
|
+
# "response": {
|
1369
|
+
# "type": "order",
|
1370
|
+
# "data": {
|
1371
|
+
# "statuses": [
|
1372
|
+
# {
|
1373
|
+
# "resting": {
|
1374
|
+
# "oid": 5063830287
|
1375
|
+
# }
|
1376
|
+
# }
|
1377
|
+
# ]
|
1378
|
+
# }
|
1379
|
+
# }
|
1380
|
+
# }
|
1381
|
+
#
|
1382
|
+
responseObj = self.safe_dict(response, 'response', {})
|
1383
|
+
data = self.safe_dict(responseObj, 'data', {})
|
1384
|
+
statuses = self.safe_list(data, 'statuses', [])
|
1385
|
+
return self.parse_orders(statuses, None)
|
1386
|
+
|
1387
|
+
def create_orders_request(self, orders, params={}) -> dict:
|
1388
|
+
"""
|
1389
|
+
create a list of trade orders
|
1390
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
1391
|
+
:param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
|
1392
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
1393
|
+
"""
|
1394
|
+
self.check_required_credentials()
|
778
1395
|
defaultSlippage = self.safe_string(self.options, 'defaultSlippage')
|
779
1396
|
defaultSlippage = self.safe_string(params, 'slippage', defaultSlippage)
|
780
1397
|
hasClientOrderId = False
|
@@ -791,7 +1408,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
791
1408
|
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
792
1409
|
if clientOrderId is None:
|
793
1410
|
raise ArgumentsRequired(self.id + ' createOrders() all orders must have clientOrderId if at least one has a clientOrderId')
|
794
|
-
params = self.omit(params, ['slippage', 'clientOrderId', 'client_id', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice'])
|
1411
|
+
params = self.omit(params, ['slippage', 'clientOrderId', 'client_id', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce'])
|
795
1412
|
nonce = self.milliseconds()
|
796
1413
|
orderReq = []
|
797
1414
|
for i in range(0, len(orders)):
|
@@ -806,7 +1423,6 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
806
1423
|
amount = self.safe_string(rawOrder, 'amount')
|
807
1424
|
price = self.safe_string(rawOrder, 'price')
|
808
1425
|
orderParams = self.safe_dict(rawOrder, 'params', {})
|
809
|
-
orderParams = self.extend(params, orderParams)
|
810
1426
|
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
811
1427
|
slippage = self.safe_string(orderParams, 'slippage', defaultSlippage)
|
812
1428
|
defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
|
@@ -829,7 +1445,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
829
1445
|
px = self.price_to_precision(symbol, price)
|
830
1446
|
sz = self.amount_to_precision(symbol, amount)
|
831
1447
|
reduceOnly = self.safe_bool(orderParams, 'reduceOnly', False)
|
832
|
-
orderType = {}
|
1448
|
+
orderType: dict = {}
|
833
1449
|
if isTrigger:
|
834
1450
|
isTp = False
|
835
1451
|
if takeProfitPrice is not None:
|
@@ -846,7 +1462,8 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
846
1462
|
orderType['limit'] = {
|
847
1463
|
'tif': timeInForce,
|
848
1464
|
}
|
849
|
-
|
1465
|
+
orderParams = self.omit(orderParams, ['clientOrderId', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce', 'client_id', 'reduceOnly', 'postOnly'])
|
1466
|
+
orderObj: dict = {
|
850
1467
|
'a': self.parse_to_int(market['baseId']),
|
851
1468
|
'b': isBuy,
|
852
1469
|
'p': px,
|
@@ -858,8 +1475,8 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
858
1475
|
if clientOrderId is not None:
|
859
1476
|
orderObj['c'] = clientOrderId
|
860
1477
|
orderReq.append(orderObj)
|
861
|
-
vaultAddress = self.safe_string(params, 'vaultAddress')
|
862
|
-
orderAction = {
|
1478
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
1479
|
+
orderAction: dict = {
|
863
1480
|
'type': 'order',
|
864
1481
|
'orders': orderReq,
|
865
1482
|
'grouping': 'na',
|
@@ -868,57 +1485,46 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
868
1485
|
if vaultAddress is None:
|
869
1486
|
orderAction['brokerCode'] = 1
|
870
1487
|
signature = self.sign_l1_action(orderAction, nonce, vaultAddress)
|
871
|
-
request = {
|
1488
|
+
request: dict = {
|
872
1489
|
'action': orderAction,
|
873
1490
|
'nonce': nonce,
|
874
1491
|
'signature': signature,
|
875
1492
|
# 'vaultAddress': vaultAddress,
|
876
1493
|
}
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
# "response": {
|
882
|
-
# "type": "order",
|
883
|
-
# "data": {
|
884
|
-
# "statuses": [
|
885
|
-
# {
|
886
|
-
# "resting": {
|
887
|
-
# "oid": 5063830287
|
888
|
-
# }
|
889
|
-
# }
|
890
|
-
# ]
|
891
|
-
# }
|
892
|
-
# }
|
893
|
-
# }
|
894
|
-
#
|
895
|
-
responseObj = self.safe_dict(response, 'response', {})
|
896
|
-
data = self.safe_dict(responseObj, 'data', {})
|
897
|
-
statuses = self.safe_list(data, 'statuses', [])
|
898
|
-
return self.parse_orders(statuses, None)
|
1494
|
+
if vaultAddress is not None:
|
1495
|
+
params = self.omit(params, 'vaultAddress')
|
1496
|
+
request['vaultAddress'] = vaultAddress
|
1497
|
+
return request
|
899
1498
|
|
900
1499
|
async def cancel_order(self, id: str, symbol: Str = None, params={}):
|
901
1500
|
"""
|
902
1501
|
cancels an open order
|
903
|
-
|
904
|
-
|
1502
|
+
|
1503
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
1504
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
1505
|
+
|
905
1506
|
:param str id: order id
|
906
1507
|
:param str symbol: unified symbol of the market the order was made in
|
907
1508
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
908
|
-
:param str [params.clientOrderId]: client order id(
|
1509
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
1510
|
+
:param str [params.vaultAddress]: the vault address for order
|
909
1511
|
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
910
1512
|
"""
|
911
|
-
|
1513
|
+
orders = await self.cancel_orders([id], symbol, params)
|
1514
|
+
return self.safe_dict(orders, 0)
|
912
1515
|
|
913
1516
|
async def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
|
914
1517
|
"""
|
915
1518
|
cancel multiple orders
|
916
|
-
|
917
|
-
|
1519
|
+
|
1520
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
1521
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
1522
|
+
|
918
1523
|
:param str[] ids: order ids
|
919
1524
|
:param str [symbol]: unified market symbol
|
920
1525
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
921
|
-
:param string|str[] [params.clientOrderId]: client order ids(
|
1526
|
+
:param string|str[] [params.clientOrderId]: client order ids,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
1527
|
+
:param str [params.vaultAddress]: the vault address
|
922
1528
|
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
923
1529
|
"""
|
924
1530
|
self.check_required_credentials()
|
@@ -929,12 +1535,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
929
1535
|
clientOrderId = self.safe_value_2(params, 'clientOrderId', 'client_id')
|
930
1536
|
params = self.omit(params, ['clientOrderId', 'client_id'])
|
931
1537
|
nonce = self.milliseconds()
|
932
|
-
request = {
|
1538
|
+
request: dict = {
|
933
1539
|
'nonce': nonce,
|
934
1540
|
# 'vaultAddress': vaultAddress,
|
935
1541
|
}
|
936
1542
|
cancelReq = []
|
937
|
-
cancelAction = {
|
1543
|
+
cancelAction: dict = {
|
938
1544
|
'type': '',
|
939
1545
|
'cancels': [],
|
940
1546
|
}
|
@@ -956,11 +1562,92 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
956
1562
|
'o': self.parse_to_numeric(ids[i]),
|
957
1563
|
})
|
958
1564
|
cancelAction['cancels'] = cancelReq
|
959
|
-
vaultAddress = self.safe_string(params, 'vaultAddress')
|
1565
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
960
1566
|
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
961
1567
|
request['action'] = cancelAction
|
962
1568
|
request['signature'] = signature
|
963
|
-
|
1569
|
+
if vaultAddress is not None:
|
1570
|
+
params = self.omit(params, 'vaultAddress')
|
1571
|
+
request['vaultAddress'] = vaultAddress
|
1572
|
+
response = await self.privatePostExchange(request)
|
1573
|
+
#
|
1574
|
+
# {
|
1575
|
+
# "status":"ok",
|
1576
|
+
# "response":{
|
1577
|
+
# "type":"cancel",
|
1578
|
+
# "data":{
|
1579
|
+
# "statuses":[
|
1580
|
+
# "success"
|
1581
|
+
# ]
|
1582
|
+
# }
|
1583
|
+
# }
|
1584
|
+
# }
|
1585
|
+
#
|
1586
|
+
innerResponse = self.safe_dict(response, 'response')
|
1587
|
+
data = self.safe_dict(innerResponse, 'data')
|
1588
|
+
statuses = self.safe_list(data, 'statuses')
|
1589
|
+
orders = []
|
1590
|
+
for i in range(0, len(statuses)):
|
1591
|
+
status = statuses[i]
|
1592
|
+
orders.append(self.safe_order({
|
1593
|
+
'info': status,
|
1594
|
+
'status': status,
|
1595
|
+
}))
|
1596
|
+
return orders
|
1597
|
+
|
1598
|
+
async def cancel_orders_for_symbols(self, orders: List[CancellationRequest], params={}):
|
1599
|
+
"""
|
1600
|
+
cancel multiple orders for multiple symbols
|
1601
|
+
|
1602
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
1603
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
1604
|
+
|
1605
|
+
:param CancellationRequest[] orders: each order should contain the parameters required by cancelOrder namely id and symbol, example [{"id": "a", "symbol": "BTC/USDT"}, {"id": "b", "symbol": "ETH/USDT"}]
|
1606
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1607
|
+
:param str [params.vaultAddress]: the vault address
|
1608
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
1609
|
+
"""
|
1610
|
+
self.check_required_credentials()
|
1611
|
+
await self.load_markets()
|
1612
|
+
nonce = self.milliseconds()
|
1613
|
+
request: dict = {
|
1614
|
+
'nonce': nonce,
|
1615
|
+
# 'vaultAddress': vaultAddress,
|
1616
|
+
}
|
1617
|
+
cancelReq = []
|
1618
|
+
cancelAction: dict = {
|
1619
|
+
'type': '',
|
1620
|
+
'cancels': [],
|
1621
|
+
}
|
1622
|
+
cancelByCloid = False
|
1623
|
+
for i in range(0, len(orders)):
|
1624
|
+
order = orders[i]
|
1625
|
+
clientOrderId = self.safe_string(order, 'clientOrderId')
|
1626
|
+
if clientOrderId is not None:
|
1627
|
+
cancelByCloid = True
|
1628
|
+
id = self.safe_string(order, 'id')
|
1629
|
+
symbol = self.safe_string(order, 'symbol')
|
1630
|
+
if symbol is None:
|
1631
|
+
raise ArgumentsRequired(self.id + ' cancelOrdersForSymbols() requires a symbol argument in each order')
|
1632
|
+
if id is not None and cancelByCloid:
|
1633
|
+
raise BadRequest(self.id + ' cancelOrdersForSymbols() all orders must have either id or clientOrderId')
|
1634
|
+
assetKey = 'asset' if cancelByCloid else 'a'
|
1635
|
+
idKey = 'cloid' if cancelByCloid else 'o'
|
1636
|
+
market = self.market(symbol)
|
1637
|
+
cancelObj: dict = {}
|
1638
|
+
cancelObj[assetKey] = self.parse_to_numeric(market['baseId'])
|
1639
|
+
cancelObj[idKey] = clientOrderId if cancelByCloid else self.parse_to_numeric(id)
|
1640
|
+
cancelReq.append(cancelObj)
|
1641
|
+
cancelAction['type'] = 'cancelByCloid' if cancelByCloid else 'cancel'
|
1642
|
+
cancelAction['cancels'] = cancelReq
|
1643
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
1644
|
+
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
1645
|
+
request['action'] = cancelAction
|
1646
|
+
request['signature'] = signature
|
1647
|
+
if vaultAddress is not None:
|
1648
|
+
params = self.omit(params, 'vaultAddress')
|
1649
|
+
request['vaultAddress'] = vaultAddress
|
1650
|
+
response = await self.privatePostExchange(request)
|
964
1651
|
#
|
965
1652
|
# {
|
966
1653
|
# "status":"ok",
|
@@ -976,29 +1663,46 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
976
1663
|
#
|
977
1664
|
return response
|
978
1665
|
|
979
|
-
async def
|
1666
|
+
async def cancel_all_orders_after(self, timeout: Int, params={}):
|
980
1667
|
"""
|
981
|
-
|
982
|
-
:
|
983
|
-
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
|
984
|
-
:param str id: cancel order id
|
985
|
-
:param str symbol: unified symbol of the market to create an order in
|
986
|
-
:param str type: 'market' or 'limit'
|
987
|
-
:param str side: 'buy' or 'sell'
|
988
|
-
:param float amount: how much of currency you want to trade in units of base currency
|
989
|
-
:param float [price]: the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
|
1668
|
+
dead man's switch, cancel all orders after the given timeout
|
1669
|
+
:param number timeout: time in milliseconds, 0 represents cancel the timer
|
990
1670
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
991
|
-
:param str [params.
|
992
|
-
:
|
993
|
-
:param bool [params.reduceOnly]: True or False whether the order is reduce-only
|
994
|
-
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
995
|
-
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
996
|
-
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
1671
|
+
:param str [params.vaultAddress]: the vault address
|
1672
|
+
:returns dict: the api result
|
997
1673
|
"""
|
1674
|
+
self.check_required_credentials()
|
1675
|
+
await self.load_markets()
|
1676
|
+
params = self.omit(params, ['clientOrderId', 'client_id'])
|
1677
|
+
nonce = self.milliseconds()
|
1678
|
+
request: dict = {
|
1679
|
+
'nonce': nonce,
|
1680
|
+
# 'vaultAddress': vaultAddress,
|
1681
|
+
}
|
1682
|
+
cancelAction: dict = {
|
1683
|
+
'type': 'scheduleCancel',
|
1684
|
+
'time': nonce + timeout,
|
1685
|
+
}
|
1686
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
1687
|
+
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
1688
|
+
request['action'] = cancelAction
|
1689
|
+
request['signature'] = signature
|
1690
|
+
if vaultAddress is not None:
|
1691
|
+
params = self.omit(params, 'vaultAddress')
|
1692
|
+
request['vaultAddress'] = vaultAddress
|
1693
|
+
response = await self.privatePostExchange(request)
|
1694
|
+
#
|
1695
|
+
# {
|
1696
|
+
# "status":"err",
|
1697
|
+
# "response":"Cannot set scheduled cancel time until enough volume traded. Required: $1000000. Traded: $373.47205."
|
1698
|
+
# }
|
1699
|
+
#
|
1700
|
+
return response
|
1701
|
+
|
1702
|
+
def edit_order_request(self, id: str, symbol: str, type: str, side: str, amount: Num = None, price: Num = None, params={}):
|
998
1703
|
self.check_required_credentials()
|
999
1704
|
if id is None:
|
1000
1705
|
raise ArgumentsRequired(self.id + ' editOrder() requires an id argument')
|
1001
|
-
await self.load_markets()
|
1002
1706
|
market = self.market(symbol)
|
1003
1707
|
type = type.upper()
|
1004
1708
|
isMarket = (type == 'MARKET')
|
@@ -1025,7 +1729,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1025
1729
|
px = self.price_to_precision(symbol, str(price))
|
1026
1730
|
sz = self.amount_to_precision(symbol, amount)
|
1027
1731
|
reduceOnly = self.safe_bool(params, 'reduceOnly', False)
|
1028
|
-
orderType = {}
|
1732
|
+
orderType: dict = {}
|
1029
1733
|
if isTrigger:
|
1030
1734
|
isTp = False
|
1031
1735
|
if takeProfitPrice is not None:
|
@@ -1045,7 +1749,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1045
1749
|
if triggerPrice is None:
|
1046
1750
|
triggerPrice = '0'
|
1047
1751
|
nonce = self.milliseconds()
|
1048
|
-
orderReq = {
|
1752
|
+
orderReq: dict = {
|
1049
1753
|
'a': self.parse_to_int(market['baseId']),
|
1050
1754
|
'b': isBuy,
|
1051
1755
|
'p': px,
|
@@ -1056,23 +1760,53 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1056
1760
|
}
|
1057
1761
|
if clientOrderId is not None:
|
1058
1762
|
orderReq['c'] = clientOrderId
|
1059
|
-
modifyReq = {
|
1763
|
+
modifyReq: dict = {
|
1060
1764
|
'oid': self.parse_to_int(id),
|
1061
1765
|
'order': orderReq,
|
1062
1766
|
}
|
1063
|
-
modifyAction = {
|
1767
|
+
modifyAction: dict = {
|
1064
1768
|
'type': 'batchModify',
|
1065
1769
|
'modifies': [modifyReq],
|
1066
1770
|
}
|
1067
|
-
vaultAddress = self.safe_string(params, 'vaultAddress')
|
1771
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
1068
1772
|
signature = self.sign_l1_action(modifyAction, nonce, vaultAddress)
|
1069
|
-
request = {
|
1773
|
+
request: dict = {
|
1070
1774
|
'action': modifyAction,
|
1071
1775
|
'nonce': nonce,
|
1072
1776
|
'signature': signature,
|
1073
1777
|
# 'vaultAddress': vaultAddress,
|
1074
1778
|
}
|
1075
|
-
|
1779
|
+
if vaultAddress is not None:
|
1780
|
+
params = self.omit(params, 'vaultAddress')
|
1781
|
+
request['vaultAddress'] = vaultAddress
|
1782
|
+
return request
|
1783
|
+
|
1784
|
+
async def edit_order(self, id: str, symbol: str, type: str, side: str, amount: Num = None, price: Num = None, params={}):
|
1785
|
+
"""
|
1786
|
+
edit a trade order
|
1787
|
+
|
1788
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-an-order
|
1789
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
|
1790
|
+
|
1791
|
+
:param str id: cancel order id
|
1792
|
+
:param str symbol: unified symbol of the market to create an order in
|
1793
|
+
:param str type: 'market' or 'limit'
|
1794
|
+
:param str side: 'buy' or 'sell'
|
1795
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
1796
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
1797
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1798
|
+
:param str [params.timeInForce]: 'Gtc', 'Ioc', 'Alo'
|
1799
|
+
:param bool [params.postOnly]: True or False whether the order is post-only
|
1800
|
+
:param bool [params.reduceOnly]: True or False whether the order is reduce-only
|
1801
|
+
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
1802
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
1803
|
+
:param str [params.vaultAddress]: the vault address for order
|
1804
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
1805
|
+
"""
|
1806
|
+
await self.load_markets()
|
1807
|
+
market = self.market(symbol)
|
1808
|
+
request = self.edit_order_request(id, symbol, type, side, amount, price, params)
|
1809
|
+
response = await self.privatePostExchange(request)
|
1076
1810
|
#
|
1077
1811
|
# {
|
1078
1812
|
# "status": "ok",
|
@@ -1117,7 +1851,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1117
1851
|
async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
1118
1852
|
"""
|
1119
1853
|
fetches historical funding rate prices
|
1120
|
-
|
1854
|
+
|
1855
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-historical-funding-rates
|
1856
|
+
|
1121
1857
|
:param str symbol: unified symbol of the market to fetch the funding rate history for
|
1122
1858
|
:param int [since]: timestamp in ms of the earliest funding rate to fetch
|
1123
1859
|
:param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
|
@@ -1126,15 +1862,18 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1126
1862
|
:returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
|
1127
1863
|
"""
|
1128
1864
|
await self.load_markets()
|
1865
|
+
if symbol is None:
|
1866
|
+
raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
|
1129
1867
|
market = self.market(symbol)
|
1130
|
-
request = {
|
1868
|
+
request: dict = {
|
1131
1869
|
'type': 'fundingHistory',
|
1132
1870
|
'coin': market['base'],
|
1133
1871
|
}
|
1134
1872
|
if since is not None:
|
1135
1873
|
request['startTime'] = since
|
1136
1874
|
else:
|
1137
|
-
|
1875
|
+
maxLimit = 500 if (limit is None) else limit
|
1876
|
+
request['startTime'] = self.milliseconds() - maxLimit * 60 * 60 * 1000
|
1138
1877
|
until = self.safe_integer(params, 'until')
|
1139
1878
|
params = self.omit(params, 'until')
|
1140
1879
|
if until is not None:
|
@@ -1167,20 +1906,25 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1167
1906
|
async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
1168
1907
|
"""
|
1169
1908
|
fetch all unfilled currently open orders
|
1170
|
-
|
1909
|
+
|
1910
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-open-orders
|
1911
|
+
|
1171
1912
|
:param str symbol: unified market symbol
|
1172
1913
|
:param int [since]: the earliest time in ms to fetch open orders for
|
1173
1914
|
:param int [limit]: the maximum number of open orders structures to retrieve
|
1174
1915
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1175
1916
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
1917
|
+
:param str [params.method]: 'openOrders' or 'frontendOpenOrders' default is 'frontendOpenOrders'
|
1176
1918
|
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
1177
1919
|
"""
|
1178
1920
|
userAddress = None
|
1179
1921
|
userAddress, params = self.handle_public_address('fetchOpenOrders', params)
|
1922
|
+
method = None
|
1923
|
+
method, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'method', 'frontendOpenOrders')
|
1180
1924
|
await self.load_markets()
|
1181
1925
|
market = self.safe_market(symbol)
|
1182
|
-
request = {
|
1183
|
-
'type':
|
1926
|
+
request: dict = {
|
1927
|
+
'type': method,
|
1184
1928
|
'user': userAddress,
|
1185
1929
|
}
|
1186
1930
|
response = await self.publicPostInfo(self.extend(request, params))
|
@@ -1197,7 +1941,14 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1197
1941
|
# }
|
1198
1942
|
# ]
|
1199
1943
|
#
|
1200
|
-
|
1944
|
+
orderWithStatus = []
|
1945
|
+
for i in range(0, len(response)):
|
1946
|
+
order = response[i]
|
1947
|
+
extendOrder = {}
|
1948
|
+
if self.safe_string(order, 'status') is None:
|
1949
|
+
extendOrder['ccxtStatus'] = 'open'
|
1950
|
+
orderWithStatus.append(self.extend(order, extendOrder))
|
1951
|
+
return self.parse_orders(orderWithStatus, market, since, limit)
|
1201
1952
|
|
1202
1953
|
async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
1203
1954
|
"""
|
@@ -1209,11 +1960,56 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1209
1960
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
1210
1961
|
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
1211
1962
|
"""
|
1963
|
+
await self.load_markets()
|
1964
|
+
orders = await self.fetch_orders(symbol, None, None, params) # don't filter here because we don't want to catch open orders
|
1965
|
+
closedOrders = self.filter_by_array(orders, 'status', ['closed'], False)
|
1966
|
+
return self.filter_by_symbol_since_limit(closedOrders, symbol, since, limit)
|
1967
|
+
|
1968
|
+
async def fetch_canceled_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
1969
|
+
"""
|
1970
|
+
fetch all canceled orders
|
1971
|
+
:param str symbol: unified market symbol
|
1972
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
1973
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
1974
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1975
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
1976
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
1977
|
+
"""
|
1978
|
+
await self.load_markets()
|
1979
|
+
orders = await self.fetch_orders(symbol, None, None, params) # don't filter here because we don't want to catch open orders
|
1980
|
+
closedOrders = self.filter_by_array(orders, 'status', ['canceled'], False)
|
1981
|
+
return self.filter_by_symbol_since_limit(closedOrders, symbol, since, limit)
|
1982
|
+
|
1983
|
+
async def fetch_canceled_and_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
1984
|
+
"""
|
1985
|
+
fetch all closed and canceled orders
|
1986
|
+
:param str symbol: unified market symbol
|
1987
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
1988
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
1989
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1990
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
1991
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
1992
|
+
"""
|
1993
|
+
await self.load_markets()
|
1994
|
+
orders = await self.fetch_orders(symbol, None, None, params) # don't filter here because we don't want to catch open orders
|
1995
|
+
closedOrders = self.filter_by_array(orders, 'status', ['canceled', 'closed', 'rejected'], False)
|
1996
|
+
return self.filter_by_symbol_since_limit(closedOrders, symbol, since, limit)
|
1997
|
+
|
1998
|
+
async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
1999
|
+
"""
|
2000
|
+
fetch all orders
|
2001
|
+
:param str symbol: unified market symbol
|
2002
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
2003
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
2004
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2005
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
2006
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
2007
|
+
"""
|
1212
2008
|
userAddress = None
|
1213
|
-
userAddress, params = self.handle_public_address('
|
2009
|
+
userAddress, params = self.handle_public_address('fetchOrders', params)
|
1214
2010
|
await self.load_markets()
|
1215
2011
|
market = self.safe_market(symbol)
|
1216
|
-
request = {
|
2012
|
+
request: dict = {
|
1217
2013
|
'type': 'historicalOrders',
|
1218
2014
|
'user': userAddress,
|
1219
2015
|
}
|
@@ -1236,7 +2032,10 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1236
2032
|
async def fetch_order(self, id: str, symbol: Str = None, params={}):
|
1237
2033
|
"""
|
1238
2034
|
fetches information on an order made by the user
|
1239
|
-
|
2035
|
+
|
2036
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-order-status-by-oid-or-cloid
|
2037
|
+
|
2038
|
+
:param str id: order id
|
1240
2039
|
:param str symbol: unified symbol of the market the order was made in
|
1241
2040
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1242
2041
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
@@ -1246,9 +2045,10 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1246
2045
|
userAddress, params = self.handle_public_address('fetchOrder', params)
|
1247
2046
|
await self.load_markets()
|
1248
2047
|
market = self.safe_market(symbol)
|
1249
|
-
|
2048
|
+
isClientOrderId = len(id) >= 34
|
2049
|
+
request: dict = {
|
1250
2050
|
'type': 'orderStatus',
|
1251
|
-
'oid': self.parse_to_numeric(id),
|
2051
|
+
'oid': id if isClientOrderId else self.parse_to_numeric(id),
|
1252
2052
|
'user': userAddress,
|
1253
2053
|
}
|
1254
2054
|
response = await self.publicPostInfo(self.extend(request, params))
|
@@ -1282,7 +2082,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1282
2082
|
data = self.safe_dict(response, 'order')
|
1283
2083
|
return self.parse_order(data, market)
|
1284
2084
|
|
1285
|
-
def parse_order(self, order, market: Market = None) -> Order:
|
2085
|
+
def parse_order(self, order: dict, market: Market = None) -> Order:
|
1286
2086
|
#
|
1287
2087
|
# fetchOpenOrders
|
1288
2088
|
#
|
@@ -1354,6 +2154,25 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1354
2154
|
# "oid":6195281425
|
1355
2155
|
# }
|
1356
2156
|
# }
|
2157
|
+
# frontendOrder
|
2158
|
+
# {
|
2159
|
+
# "children": [],
|
2160
|
+
# "cloid": null,
|
2161
|
+
# "coin": "BLUR",
|
2162
|
+
# "isPositionTpsl": False,
|
2163
|
+
# "isTrigger": True,
|
2164
|
+
# "limitPx": "0.5",
|
2165
|
+
# "oid": 8670487141,
|
2166
|
+
# "orderType": "Stop Limit",
|
2167
|
+
# "origSz": "20.0",
|
2168
|
+
# "reduceOnly": False,
|
2169
|
+
# "side": "B",
|
2170
|
+
# "sz": "20.0",
|
2171
|
+
# "tif": null,
|
2172
|
+
# "timestamp": 1715523663687,
|
2173
|
+
# "triggerCondition": "Price above 0.6",
|
2174
|
+
# "triggerPx": "0.6"
|
2175
|
+
# }
|
1357
2176
|
#
|
1358
2177
|
entry = self.safe_dict_n(order, ['order', 'resting', 'filled'])
|
1359
2178
|
if entry is None:
|
@@ -1361,17 +2180,20 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1361
2180
|
coin = self.safe_string(entry, 'coin')
|
1362
2181
|
marketId = None
|
1363
2182
|
if coin is not None:
|
1364
|
-
marketId = coin
|
2183
|
+
marketId = self.coin_to_market_id(coin)
|
1365
2184
|
if self.safe_string(entry, 'id') is None:
|
1366
2185
|
market = self.safe_market(marketId, None)
|
1367
2186
|
else:
|
1368
2187
|
market = self.safe_market(marketId, market)
|
1369
2188
|
symbol = market['symbol']
|
1370
|
-
timestamp = self.
|
1371
|
-
status = self.
|
2189
|
+
timestamp = self.safe_integer(entry, 'timestamp')
|
2190
|
+
status = self.safe_string_2(order, 'status', 'ccxtStatus')
|
2191
|
+
order = self.omit(order, ['ccxtStatus'])
|
1372
2192
|
side = self.safe_string(entry, 'side')
|
1373
2193
|
if side is not None:
|
1374
2194
|
side = 'sell' if (side == 'A') else 'buy'
|
2195
|
+
totalAmount = self.safe_string_2(entry, 'origSz', 'totalSz')
|
2196
|
+
remaining = self.safe_string(entry, 'sz')
|
1375
2197
|
return self.safe_order({
|
1376
2198
|
'info': order,
|
1377
2199
|
'id': self.safe_string(entry, 'oid'),
|
@@ -1379,34 +2201,38 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1379
2201
|
'timestamp': timestamp,
|
1380
2202
|
'datetime': self.iso8601(timestamp),
|
1381
2203
|
'lastTradeTimestamp': None,
|
1382
|
-
'lastUpdateTimestamp':
|
2204
|
+
'lastUpdateTimestamp': self.safe_integer(order, 'statusTimestamp'),
|
1383
2205
|
'symbol': symbol,
|
1384
|
-
'type': self.safe_string_lower(entry, 'orderType'),
|
2206
|
+
'type': self.parse_order_type(self.safe_string_lower(entry, 'orderType')),
|
1385
2207
|
'timeInForce': self.safe_string_upper(entry, 'tif'),
|
1386
2208
|
'postOnly': None,
|
1387
2209
|
'reduceOnly': self.safe_bool(entry, 'reduceOnly'),
|
1388
2210
|
'side': side,
|
1389
|
-
'price': self.
|
2211
|
+
'price': self.safe_string(entry, 'limitPx'),
|
1390
2212
|
'triggerPrice': self.safe_number(entry, 'triggerPx') if self.safe_bool(entry, 'isTrigger') else None,
|
1391
|
-
'amount':
|
2213
|
+
'amount': totalAmount,
|
1392
2214
|
'cost': None,
|
1393
|
-
'average': self.
|
1394
|
-
'filled':
|
1395
|
-
'remaining':
|
2215
|
+
'average': self.safe_string(entry, 'avgPx'),
|
2216
|
+
'filled': Precise.string_sub(totalAmount, remaining),
|
2217
|
+
'remaining': remaining,
|
1396
2218
|
'status': self.parse_order_status(status),
|
1397
2219
|
'fee': None,
|
1398
2220
|
'trades': None,
|
1399
2221
|
}, market)
|
1400
2222
|
|
1401
|
-
def parse_order_status(self, status):
|
1402
|
-
statuses = {
|
2223
|
+
def parse_order_status(self, status: Str):
|
2224
|
+
statuses: dict = {
|
1403
2225
|
'triggered': 'open',
|
1404
2226
|
'filled': 'closed',
|
2227
|
+
'open': 'open',
|
2228
|
+
'canceled': 'canceled',
|
2229
|
+
'rejected': 'rejected',
|
2230
|
+
'marginCanceled': 'canceled',
|
1405
2231
|
}
|
1406
2232
|
return self.safe_string(statuses, status, status)
|
1407
2233
|
|
1408
2234
|
def parse_order_type(self, status):
|
1409
|
-
statuses = {
|
2235
|
+
statuses: dict = {
|
1410
2236
|
'stop limit': 'limit',
|
1411
2237
|
'stop market': 'market',
|
1412
2238
|
}
|
@@ -1415,8 +2241,10 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1415
2241
|
async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
1416
2242
|
"""
|
1417
2243
|
fetch all trades made by the user
|
1418
|
-
|
1419
|
-
|
2244
|
+
|
2245
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills
|
2246
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills-by-time
|
2247
|
+
|
1420
2248
|
:param str symbol: unified market symbol
|
1421
2249
|
:param int [since]: the earliest time in ms to fetch trades for
|
1422
2250
|
:param int [limit]: the maximum number of trades structures to retrieve
|
@@ -1428,7 +2256,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1428
2256
|
userAddress, params = self.handle_public_address('fetchMyTrades', params)
|
1429
2257
|
await self.load_markets()
|
1430
2258
|
market = self.safe_market(symbol)
|
1431
|
-
request = {
|
2259
|
+
request: dict = {
|
1432
2260
|
'user': userAddress,
|
1433
2261
|
}
|
1434
2262
|
if since is not None:
|
@@ -1449,6 +2277,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1449
2277
|
# "crossed": True,
|
1450
2278
|
# "dir": "Close Long",
|
1451
2279
|
# "fee": "0.050062",
|
2280
|
+
# "feeToken": "USDC",
|
1452
2281
|
# "hash": "0x09d77c96791e98b5775a04092584ab010d009445119c71e4005c0d634ea322bc",
|
1453
2282
|
# "liquidationMarkPx": null,
|
1454
2283
|
# "oid": 3929354691,
|
@@ -1463,7 +2292,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1463
2292
|
#
|
1464
2293
|
return self.parse_trades(response, market, since, limit)
|
1465
2294
|
|
1466
|
-
def parse_trade(self, trade, market: Market = None) -> Trade:
|
2295
|
+
def parse_trade(self, trade: dict, market: Market = None) -> Trade:
|
1467
2296
|
#
|
1468
2297
|
# {
|
1469
2298
|
# "closedPnl": "0.19343",
|
@@ -1486,7 +2315,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1486
2315
|
price = self.safe_string(trade, 'px')
|
1487
2316
|
amount = self.safe_string(trade, 'sz')
|
1488
2317
|
coin = self.safe_string(trade, 'coin')
|
1489
|
-
marketId = coin
|
2318
|
+
marketId = self.coin_to_market_id(coin)
|
1490
2319
|
market = self.safe_market(marketId, None)
|
1491
2320
|
symbol = market['symbol']
|
1492
2321
|
id = self.safe_string(trade, 'tid')
|
@@ -1507,13 +2336,19 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1507
2336
|
'price': price,
|
1508
2337
|
'amount': amount,
|
1509
2338
|
'cost': None,
|
1510
|
-
'fee': {
|
2339
|
+
'fee': {
|
2340
|
+
'cost': fee,
|
2341
|
+
'currency': self.safe_string(trade, 'feeToken'),
|
2342
|
+
'rate': None,
|
2343
|
+
},
|
1511
2344
|
}, market)
|
1512
2345
|
|
1513
2346
|
async def fetch_position(self, symbol: str, params={}):
|
1514
2347
|
"""
|
1515
2348
|
fetch data on an open position
|
1516
|
-
|
2349
|
+
|
2350
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-users-perpetuals-account-summary
|
2351
|
+
|
1517
2352
|
:param str symbol: unified market symbol of the market the position is held in
|
1518
2353
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1519
2354
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
@@ -1525,7 +2360,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1525
2360
|
async def fetch_positions(self, symbols: Strings = None, params={}):
|
1526
2361
|
"""
|
1527
2362
|
fetch all open positions
|
1528
|
-
|
2363
|
+
|
2364
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-users-perpetuals-account-summary
|
2365
|
+
|
1529
2366
|
:param str[] [symbols]: list of unified market symbols
|
1530
2367
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1531
2368
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
@@ -1535,7 +2372,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1535
2372
|
userAddress = None
|
1536
2373
|
userAddress, params = self.handle_public_address('fetchPositions', params)
|
1537
2374
|
symbols = self.market_symbols(symbols)
|
1538
|
-
request = {
|
2375
|
+
request: dict = {
|
1539
2376
|
'type': 'clearinghouseState',
|
1540
2377
|
'user': userAddress,
|
1541
2378
|
}
|
@@ -1591,7 +2428,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1591
2428
|
result.append(self.parse_position(data[i], None))
|
1592
2429
|
return self.filter_by_array_positions(result, 'symbol', symbols, False)
|
1593
2430
|
|
1594
|
-
def parse_position(self, position, market: Market = None):
|
2431
|
+
def parse_position(self, position: dict, market: Market = None):
|
1595
2432
|
#
|
1596
2433
|
# {
|
1597
2434
|
# "position": {
|
@@ -1620,18 +2457,22 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1620
2457
|
#
|
1621
2458
|
entry = self.safe_dict(position, 'position', {})
|
1622
2459
|
coin = self.safe_string(entry, 'coin')
|
1623
|
-
marketId = coin
|
2460
|
+
marketId = self.coin_to_market_id(coin)
|
1624
2461
|
market = self.safe_market(marketId, None)
|
1625
2462
|
symbol = market['symbol']
|
1626
2463
|
leverage = self.safe_dict(entry, 'leverage', {})
|
1627
|
-
|
1628
|
-
|
2464
|
+
marginMode = self.safe_string(leverage, 'type')
|
2465
|
+
isIsolated = (marginMode == 'isolated')
|
2466
|
+
rawSize = self.safe_string(entry, 'szi')
|
2467
|
+
size = rawSize
|
1629
2468
|
side = None
|
1630
|
-
if
|
1631
|
-
side = '
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
2469
|
+
if size is not None:
|
2470
|
+
side = 'long' if Precise.string_gt(rawSize, '0') else 'short'
|
2471
|
+
size = Precise.string_abs(size)
|
2472
|
+
rawUnrealizedPnl = self.safe_string(entry, 'unrealizedPnl')
|
2473
|
+
absRawUnrealizedPnl = Precise.string_abs(rawUnrealizedPnl)
|
2474
|
+
initialMargin = self.safe_string(entry, 'marginUsed')
|
2475
|
+
percentage = Precise.string_mul(Precise.string_div(absRawUnrealizedPnl, initialMargin), '100')
|
1635
2476
|
return self.safe_position({
|
1636
2477
|
'info': position,
|
1637
2478
|
'id': None,
|
@@ -1641,21 +2482,21 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1641
2482
|
'isolated': isIsolated,
|
1642
2483
|
'hedged': None,
|
1643
2484
|
'side': side,
|
1644
|
-
'contracts': self.parse_number(
|
2485
|
+
'contracts': self.parse_number(size),
|
1645
2486
|
'contractSize': None,
|
1646
2487
|
'entryPrice': self.safe_number(entry, 'entryPx'),
|
1647
2488
|
'markPrice': None,
|
1648
2489
|
'notional': self.safe_number(entry, 'positionValue'),
|
1649
2490
|
'leverage': self.safe_number(leverage, 'value'),
|
1650
|
-
'collateral':
|
1651
|
-
'initialMargin': initialMargin,
|
2491
|
+
'collateral': self.safe_number(entry, 'marginUsed'),
|
2492
|
+
'initialMargin': self.parse_number(initialMargin),
|
1652
2493
|
'maintenanceMargin': None,
|
1653
2494
|
'initialMarginPercentage': None,
|
1654
2495
|
'maintenanceMarginPercentage': None,
|
1655
|
-
'unrealizedPnl':
|
2496
|
+
'unrealizedPnl': self.parse_number(rawUnrealizedPnl),
|
1656
2497
|
'liquidationPrice': self.safe_number(entry, 'liquidationPx'),
|
1657
|
-
'marginMode':
|
1658
|
-
'percentage': percentage,
|
2498
|
+
'marginMode': marginMode,
|
2499
|
+
'percentage': self.parse_number(percentage),
|
1659
2500
|
})
|
1660
2501
|
|
1661
2502
|
async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
|
@@ -1675,24 +2516,30 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1675
2516
|
if leverage is None:
|
1676
2517
|
raise ArgumentsRequired(self.id + ' setMarginMode() requires a leverage parameter')
|
1677
2518
|
asset = self.parse_to_int(market['baseId'])
|
1678
|
-
isCross = (marginMode == '
|
2519
|
+
isCross = (marginMode == 'cross')
|
1679
2520
|
nonce = self.milliseconds()
|
1680
2521
|
params = self.omit(params, ['leverage'])
|
1681
|
-
updateAction = {
|
2522
|
+
updateAction: dict = {
|
1682
2523
|
'type': 'updateLeverage',
|
1683
2524
|
'asset': asset,
|
1684
2525
|
'isCross': isCross,
|
1685
2526
|
'leverage': leverage,
|
1686
2527
|
}
|
1687
2528
|
vaultAddress = self.safe_string(params, 'vaultAddress')
|
2529
|
+
if vaultAddress is not None:
|
2530
|
+
params = self.omit(params, 'vaultAddress')
|
2531
|
+
if vaultAddress.startswith('0x'):
|
2532
|
+
vaultAddress = vaultAddress.replace('0x', '')
|
1688
2533
|
signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
|
1689
|
-
request = {
|
2534
|
+
request: dict = {
|
1690
2535
|
'action': updateAction,
|
1691
2536
|
'nonce': nonce,
|
1692
2537
|
'signature': signature,
|
1693
2538
|
# 'vaultAddress': vaultAddress,
|
1694
2539
|
}
|
1695
|
-
|
2540
|
+
if vaultAddress is not None:
|
2541
|
+
request['vaultAddress'] = vaultAddress
|
2542
|
+
response = await self.privatePostExchange(request)
|
1696
2543
|
#
|
1697
2544
|
# {
|
1698
2545
|
# 'response': {
|
@@ -1721,21 +2568,24 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1721
2568
|
asset = self.parse_to_int(market['baseId'])
|
1722
2569
|
nonce = self.milliseconds()
|
1723
2570
|
params = self.omit(params, 'marginMode')
|
1724
|
-
updateAction = {
|
2571
|
+
updateAction: dict = {
|
1725
2572
|
'type': 'updateLeverage',
|
1726
2573
|
'asset': asset,
|
1727
2574
|
'isCross': isCross,
|
1728
2575
|
'leverage': leverage,
|
1729
2576
|
}
|
1730
|
-
vaultAddress = self.safe_string(params, 'vaultAddress')
|
2577
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
1731
2578
|
signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
|
1732
|
-
request = {
|
2579
|
+
request: dict = {
|
1733
2580
|
'action': updateAction,
|
1734
2581
|
'nonce': nonce,
|
1735
2582
|
'signature': signature,
|
1736
2583
|
# 'vaultAddress': vaultAddress,
|
1737
2584
|
}
|
1738
|
-
|
2585
|
+
if vaultAddress is not None:
|
2586
|
+
params = self.omit(params, 'vaultAddress')
|
2587
|
+
request['vaultAddress'] = vaultAddress
|
2588
|
+
response = await self.privatePostExchange(request)
|
1739
2589
|
#
|
1740
2590
|
# {
|
1741
2591
|
# 'response': {
|
@@ -1746,10 +2596,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1746
2596
|
#
|
1747
2597
|
return response
|
1748
2598
|
|
1749
|
-
async def add_margin(self, symbol: str, amount, params={}):
|
2599
|
+
async def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
|
1750
2600
|
"""
|
1751
2601
|
add margin
|
1752
|
-
|
2602
|
+
|
2603
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
|
2604
|
+
|
1753
2605
|
:param str symbol: unified market symbol
|
1754
2606
|
:param float amount: amount of margin to add
|
1755
2607
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -1757,9 +2609,11 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1757
2609
|
"""
|
1758
2610
|
return await self.modify_margin_helper(symbol, amount, 'add', params)
|
1759
2611
|
|
1760
|
-
async def reduce_margin(self, symbol: str, amount, params={}):
|
2612
|
+
async def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
|
1761
2613
|
"""
|
1762
|
-
|
2614
|
+
|
2615
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
|
2616
|
+
|
1763
2617
|
remove margin from a position
|
1764
2618
|
:param str symbol: unified market symbol
|
1765
2619
|
:param float amount: the amount of margin to remove
|
@@ -1768,7 +2622,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1768
2622
|
"""
|
1769
2623
|
return await self.modify_margin_helper(symbol, amount, 'reduce', params)
|
1770
2624
|
|
1771
|
-
async def modify_margin_helper(self, symbol: str, amount, type, params={}):
|
2625
|
+
async def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
|
1772
2626
|
await self.load_markets()
|
1773
2627
|
market = self.market(symbol)
|
1774
2628
|
asset = self.parse_to_int(market['baseId'])
|
@@ -1776,21 +2630,24 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1776
2630
|
if type == 'reduce':
|
1777
2631
|
sz = -sz
|
1778
2632
|
nonce = self.milliseconds()
|
1779
|
-
updateAction = {
|
2633
|
+
updateAction: dict = {
|
1780
2634
|
'type': 'updateIsolatedMargin',
|
1781
2635
|
'asset': asset,
|
1782
2636
|
'isBuy': True,
|
1783
2637
|
'ntli': sz,
|
1784
2638
|
}
|
1785
|
-
vaultAddress = self.safe_string(params, 'vaultAddress')
|
2639
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
1786
2640
|
signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
|
1787
|
-
request = {
|
2641
|
+
request: dict = {
|
1788
2642
|
'action': updateAction,
|
1789
2643
|
'nonce': nonce,
|
1790
2644
|
'signature': signature,
|
1791
2645
|
# 'vaultAddress': vaultAddress,
|
1792
2646
|
}
|
1793
|
-
|
2647
|
+
if vaultAddress is not None:
|
2648
|
+
params = self.omit(params, 'vaultAddress')
|
2649
|
+
request['vaultAddress'] = vaultAddress
|
2650
|
+
response = await self.privatePostExchange(request)
|
1794
2651
|
#
|
1795
2652
|
# {
|
1796
2653
|
# 'response': {
|
@@ -1799,58 +2656,121 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1799
2656
|
# 'status': 'ok'
|
1800
2657
|
# }
|
1801
2658
|
#
|
1802
|
-
return response
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
2659
|
+
return self.extend(self.parse_margin_modification(response, market), {
|
2660
|
+
'code': self.safe_string(response, 'status'),
|
2661
|
+
})
|
2662
|
+
|
2663
|
+
def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
|
2664
|
+
#
|
2665
|
+
# {
|
2666
|
+
# 'type': 'default'
|
2667
|
+
# }
|
2668
|
+
#
|
2669
|
+
return {
|
2670
|
+
'info': data,
|
2671
|
+
'symbol': self.safe_symbol(None, market),
|
2672
|
+
'type': None,
|
2673
|
+
'marginMode': 'isolated',
|
2674
|
+
'amount': None,
|
2675
|
+
'total': None,
|
2676
|
+
'code': self.safe_string(market, 'settle'),
|
2677
|
+
'status': None,
|
2678
|
+
'timestamp': None,
|
2679
|
+
'datetime': None,
|
2680
|
+
}
|
1806
2681
|
|
1807
2682
|
async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
1808
2683
|
"""
|
1809
2684
|
transfer currency internally between wallets on the same account
|
1810
|
-
|
2685
|
+
|
2686
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#l1-usdc-transfer
|
2687
|
+
|
1811
2688
|
:param str code: unified currency code
|
1812
2689
|
:param float amount: amount to transfer
|
1813
|
-
:param str fromAccount: account to transfer from
|
1814
|
-
:param str toAccount: account to transfer to
|
2690
|
+
:param str fromAccount: account to transfer from *spot, swap*
|
2691
|
+
:param str toAccount: account to transfer to *swap, spot or address*
|
1815
2692
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2693
|
+
:param str [params.vaultAddress]: the vault address for order
|
1816
2694
|
:returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
1817
2695
|
"""
|
1818
2696
|
self.check_required_credentials()
|
1819
2697
|
await self.load_markets()
|
2698
|
+
isSandboxMode = self.safe_bool(self.options, 'sandboxMode')
|
2699
|
+
nonce = self.milliseconds()
|
2700
|
+
if self.in_array(fromAccount, ['spot', 'swap', 'perp']):
|
2701
|
+
# handle swap <> spot account transfer
|
2702
|
+
if not self.in_array(toAccount, ['spot', 'swap', 'perp']):
|
2703
|
+
raise NotSupported(self.id + 'transfer() only support spot <> swap transfer')
|
2704
|
+
strAmount = self.number_to_string(amount)
|
2705
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
2706
|
+
params = self.omit(params, 'vaultAddress')
|
2707
|
+
if vaultAddress is not None:
|
2708
|
+
strAmount = strAmount + ' subaccount:' + vaultAddress
|
2709
|
+
toPerp = (toAccount == 'perp') or (toAccount == 'swap')
|
2710
|
+
transferPayload: dict = {
|
2711
|
+
'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
|
2712
|
+
'amount': strAmount,
|
2713
|
+
'toPerp': toPerp,
|
2714
|
+
'nonce': nonce,
|
2715
|
+
}
|
2716
|
+
transferSig = self.build_usd_class_send_sig(transferPayload)
|
2717
|
+
transferRequest: dict = {
|
2718
|
+
'action': {
|
2719
|
+
'hyperliquidChain': transferPayload['hyperliquidChain'],
|
2720
|
+
'signatureChainId': '0x66eee',
|
2721
|
+
'type': 'usdClassTransfer',
|
2722
|
+
'amount': strAmount,
|
2723
|
+
'toPerp': toPerp,
|
2724
|
+
'nonce': nonce,
|
2725
|
+
},
|
2726
|
+
'nonce': nonce,
|
2727
|
+
'signature': transferSig,
|
2728
|
+
}
|
2729
|
+
if vaultAddress is not None:
|
2730
|
+
transferRequest['vaultAddress'] = vaultAddress
|
2731
|
+
transferResponse = await self.privatePostExchange(transferRequest)
|
2732
|
+
return transferResponse
|
2733
|
+
# handle sub-account/different account transfer
|
1820
2734
|
self.check_address(toAccount)
|
1821
2735
|
if code is not None:
|
1822
2736
|
code = code.upper()
|
1823
2737
|
if code != 'USDC':
|
1824
|
-
raise NotSupported(self.id + '
|
1825
|
-
|
1826
|
-
|
1827
|
-
payload = {
|
2738
|
+
raise NotSupported(self.id + 'transfer() only support USDC')
|
2739
|
+
payload: dict = {
|
2740
|
+
'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
|
1828
2741
|
'destination': toAccount,
|
1829
|
-
'amount':
|
2742
|
+
'amount': self.number_to_string(amount),
|
1830
2743
|
'time': nonce,
|
1831
2744
|
}
|
1832
|
-
sig = self.
|
1833
|
-
request = {
|
2745
|
+
sig = self.build_usd_send_sig(payload)
|
2746
|
+
request: dict = {
|
1834
2747
|
'action': {
|
1835
|
-
'
|
1836
|
-
'
|
1837
|
-
'
|
2748
|
+
'hyperliquidChain': payload['hyperliquidChain'],
|
2749
|
+
'signatureChainId': '0x66eee', # check self out
|
2750
|
+
'destination': toAccount,
|
2751
|
+
'amount': str(amount),
|
2752
|
+
'time': nonce,
|
2753
|
+
'type': 'usdSend',
|
1838
2754
|
},
|
1839
2755
|
'nonce': nonce,
|
1840
2756
|
'signature': sig,
|
1841
2757
|
}
|
1842
|
-
response = await self.privatePostExchange(
|
2758
|
+
response = await self.privatePostExchange(request)
|
1843
2759
|
return response
|
1844
2760
|
|
1845
|
-
async def withdraw(self, code: str, amount, address, tag=None, params={}):
|
2761
|
+
async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
|
1846
2762
|
"""
|
1847
2763
|
make a withdrawal(only support USDC)
|
1848
|
-
|
2764
|
+
|
2765
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#initiate-a-withdrawal-request
|
2766
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#deposit-or-withdraw-from-a-vault
|
2767
|
+
|
1849
2768
|
:param str code: unified currency code
|
1850
2769
|
:param float amount: the amount to withdraw
|
1851
2770
|
:param str address: the address to withdraw to
|
1852
2771
|
:param str tag:
|
1853
2772
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2773
|
+
:param str [params.vaultAddress]: vault address withdraw from
|
1854
2774
|
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
1855
2775
|
"""
|
1856
2776
|
self.check_required_credentials()
|
@@ -1860,38 +2780,457 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1860
2780
|
code = code.upper()
|
1861
2781
|
if code != 'USDC':
|
1862
2782
|
raise NotSupported(self.id + 'withdraw() only support USDC')
|
1863
|
-
|
2783
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
2784
|
+
params = self.omit(params, 'vaultAddress')
|
1864
2785
|
nonce = self.milliseconds()
|
1865
|
-
|
1866
|
-
|
1867
|
-
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
1875
|
-
|
1876
|
-
|
2786
|
+
action: dict = {}
|
2787
|
+
sig = None
|
2788
|
+
if vaultAddress is not None:
|
2789
|
+
action = {
|
2790
|
+
'type': 'vaultTransfer',
|
2791
|
+
'vaultAddress': '0x' + vaultAddress,
|
2792
|
+
'isDeposit': False,
|
2793
|
+
'usd': amount,
|
2794
|
+
}
|
2795
|
+
sig = self.sign_l1_action(action, nonce)
|
2796
|
+
else:
|
2797
|
+
isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
|
2798
|
+
payload: dict = {
|
2799
|
+
'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
|
2800
|
+
'destination': address,
|
2801
|
+
'amount': str(amount),
|
2802
|
+
'time': nonce,
|
2803
|
+
}
|
2804
|
+
sig = self.build_withdraw_sig(payload)
|
2805
|
+
action = {
|
2806
|
+
'hyperliquidChain': payload['hyperliquidChain'],
|
2807
|
+
'signatureChainId': '0x66eee', # check self out
|
2808
|
+
'destination': address,
|
2809
|
+
'amount': str(amount),
|
2810
|
+
'time': nonce,
|
2811
|
+
'type': 'withdraw3',
|
2812
|
+
}
|
2813
|
+
request: dict = {
|
2814
|
+
'action': action,
|
1877
2815
|
'nonce': nonce,
|
1878
2816
|
'signature': sig,
|
1879
2817
|
}
|
1880
|
-
response = await self.privatePostExchange(
|
1881
|
-
return response
|
2818
|
+
response = await self.privatePostExchange(request)
|
2819
|
+
return self.parse_transaction(response)
|
2820
|
+
|
2821
|
+
def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
|
2822
|
+
#
|
2823
|
+
# {status: 'ok', response: {type: 'default'}}
|
2824
|
+
#
|
2825
|
+
# fetchDeposits / fetchWithdrawals
|
2826
|
+
# {
|
2827
|
+
# "time":1724762307531,
|
2828
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
2829
|
+
# "delta":{
|
2830
|
+
# "type":"accountClassTransfer",
|
2831
|
+
# "usdc":"50.0",
|
2832
|
+
# "toPerp":false
|
2833
|
+
# }
|
2834
|
+
# }
|
2835
|
+
#
|
2836
|
+
timestamp = self.safe_integer(transaction, 'time')
|
2837
|
+
delta = self.safe_dict(transaction, 'delta', {})
|
2838
|
+
fee = None
|
2839
|
+
feeCost = self.safe_integer(delta, 'fee')
|
2840
|
+
if feeCost is not None:
|
2841
|
+
fee = {
|
2842
|
+
'currency': 'USDC',
|
2843
|
+
'cost': feeCost,
|
2844
|
+
}
|
2845
|
+
internal = None
|
2846
|
+
type = self.safe_string(delta, 'type')
|
2847
|
+
if type is not None:
|
2848
|
+
internal = (type == 'internalTransfer')
|
2849
|
+
return {
|
2850
|
+
'info': transaction,
|
2851
|
+
'id': None,
|
2852
|
+
'txid': self.safe_string(transaction, 'hash'),
|
2853
|
+
'timestamp': timestamp,
|
2854
|
+
'datetime': self.iso8601(timestamp),
|
2855
|
+
'network': None,
|
2856
|
+
'address': None,
|
2857
|
+
'addressTo': self.safe_string(delta, 'destination'),
|
2858
|
+
'addressFrom': self.safe_string(delta, 'user'),
|
2859
|
+
'tag': None,
|
2860
|
+
'tagTo': None,
|
2861
|
+
'tagFrom': None,
|
2862
|
+
'type': None,
|
2863
|
+
'amount': self.safe_integer(delta, 'usdc'),
|
2864
|
+
'currency': None,
|
2865
|
+
'status': self.safe_string(transaction, 'status'),
|
2866
|
+
'updated': None,
|
2867
|
+
'comment': None,
|
2868
|
+
'internal': internal,
|
2869
|
+
'fee': fee,
|
2870
|
+
}
|
2871
|
+
|
2872
|
+
async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
|
2873
|
+
"""
|
2874
|
+
fetch the trading fees for a market
|
2875
|
+
:param str symbol: unified market symbol
|
2876
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2877
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
2878
|
+
:returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
|
2879
|
+
"""
|
2880
|
+
await self.load_markets()
|
2881
|
+
userAddress = None
|
2882
|
+
userAddress, params = self.handle_public_address('fetchTradingFee', params)
|
2883
|
+
market = self.market(symbol)
|
2884
|
+
request: dict = {
|
2885
|
+
'type': 'userFees',
|
2886
|
+
'user': userAddress,
|
2887
|
+
}
|
2888
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
2889
|
+
#
|
2890
|
+
# {
|
2891
|
+
# "dailyUserVlm": [
|
2892
|
+
# {
|
2893
|
+
# "date": "2024-07-08",
|
2894
|
+
# "userCross": "0.0",
|
2895
|
+
# "userAdd": "0.0",
|
2896
|
+
# "exchange": "90597185.23639999"
|
2897
|
+
# }
|
2898
|
+
# ],
|
2899
|
+
# "feeSchedule": {
|
2900
|
+
# "cross": "0.00035",
|
2901
|
+
# "add": "0.0001",
|
2902
|
+
# "tiers": {
|
2903
|
+
# "vip": [
|
2904
|
+
# {
|
2905
|
+
# "ntlCutoff": "5000000.0",
|
2906
|
+
# "cross": "0.0003",
|
2907
|
+
# "add": "0.00005"
|
2908
|
+
# }
|
2909
|
+
# ],
|
2910
|
+
# "mm": [
|
2911
|
+
# {
|
2912
|
+
# "makerFractionCutoff": "0.005",
|
2913
|
+
# "add": "-0.00001"
|
2914
|
+
# }
|
2915
|
+
# ]
|
2916
|
+
# },
|
2917
|
+
# "referralDiscount": "0.04"
|
2918
|
+
# },
|
2919
|
+
# "userCrossRate": "0.00035",
|
2920
|
+
# "userAddRate": "0.0001",
|
2921
|
+
# "activeReferralDiscount": "0.0"
|
2922
|
+
# }
|
2923
|
+
#
|
2924
|
+
data: dict = {
|
2925
|
+
'userCrossRate': self.safe_string(response, 'userCrossRate'),
|
2926
|
+
'userAddRate': self.safe_string(response, 'userAddRate'),
|
2927
|
+
}
|
2928
|
+
return self.parse_trading_fee(data, market)
|
2929
|
+
|
2930
|
+
def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
|
2931
|
+
#
|
2932
|
+
# {
|
2933
|
+
# "dailyUserVlm": [
|
2934
|
+
# {
|
2935
|
+
# "date": "2024-07-08",
|
2936
|
+
# "userCross": "0.0",
|
2937
|
+
# "userAdd": "0.0",
|
2938
|
+
# "exchange": "90597185.23639999"
|
2939
|
+
# }
|
2940
|
+
# ],
|
2941
|
+
# "feeSchedule": {
|
2942
|
+
# "cross": "0.00035",
|
2943
|
+
# "add": "0.0001",
|
2944
|
+
# "tiers": {
|
2945
|
+
# "vip": [
|
2946
|
+
# {
|
2947
|
+
# "ntlCutoff": "5000000.0",
|
2948
|
+
# "cross": "0.0003",
|
2949
|
+
# "add": "0.00005"
|
2950
|
+
# }
|
2951
|
+
# ],
|
2952
|
+
# "mm": [
|
2953
|
+
# {
|
2954
|
+
# "makerFractionCutoff": "0.005",
|
2955
|
+
# "add": "-0.00001"
|
2956
|
+
# }
|
2957
|
+
# ]
|
2958
|
+
# },
|
2959
|
+
# "referralDiscount": "0.04"
|
2960
|
+
# },
|
2961
|
+
# "userCrossRate": "0.00035",
|
2962
|
+
# "userAddRate": "0.0001",
|
2963
|
+
# "activeReferralDiscount": "0.0"
|
2964
|
+
# }
|
2965
|
+
#
|
2966
|
+
symbol = self.safe_symbol(None, market)
|
2967
|
+
return {
|
2968
|
+
'info': fee,
|
2969
|
+
'symbol': symbol,
|
2970
|
+
'maker': self.safe_number(fee, 'userAddRate'),
|
2971
|
+
'taker': self.safe_number(fee, 'userCrossRate'),
|
2972
|
+
'percentage': None,
|
2973
|
+
'tierBased': None,
|
2974
|
+
}
|
2975
|
+
|
2976
|
+
async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
|
2977
|
+
"""
|
2978
|
+
fetch the history of changes, actions done by the user or operations that altered the balance of the user
|
2979
|
+
:param str [code]: unified currency code
|
2980
|
+
:param int [since]: timestamp in ms of the earliest ledger entry
|
2981
|
+
:param int [limit]: max number of ledger entries to return
|
2982
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2983
|
+
:param int [params.until]: timestamp in ms of the latest ledger entry
|
2984
|
+
:returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
|
2985
|
+
"""
|
2986
|
+
await self.load_markets()
|
2987
|
+
userAddress = None
|
2988
|
+
userAddress, params = self.handle_public_address('fetchLedger', params)
|
2989
|
+
request: dict = {
|
2990
|
+
'type': 'userNonFundingLedgerUpdates',
|
2991
|
+
'user': userAddress,
|
2992
|
+
}
|
2993
|
+
if since is not None:
|
2994
|
+
request['startTime'] = since
|
2995
|
+
until = self.safe_integer(params, 'until')
|
2996
|
+
if until is not None:
|
2997
|
+
request['endTime'] = until
|
2998
|
+
params = self.omit(params, ['until'])
|
2999
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
3000
|
+
#
|
3001
|
+
# [
|
3002
|
+
# {
|
3003
|
+
# "time":1724762307531,
|
3004
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
3005
|
+
# "delta":{
|
3006
|
+
# "type":"accountClassTransfer",
|
3007
|
+
# "usdc":"50.0",
|
3008
|
+
# "toPerp":false
|
3009
|
+
# }
|
3010
|
+
# }
|
3011
|
+
# ]
|
3012
|
+
#
|
3013
|
+
return self.parse_ledger(response, None, since, limit)
|
3014
|
+
|
3015
|
+
def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
|
3016
|
+
#
|
3017
|
+
# {
|
3018
|
+
# "time":1724762307531,
|
3019
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
3020
|
+
# "delta":{
|
3021
|
+
# "type":"accountClassTransfer",
|
3022
|
+
# "usdc":"50.0",
|
3023
|
+
# "toPerp":false
|
3024
|
+
# }
|
3025
|
+
# }
|
3026
|
+
#
|
3027
|
+
timestamp = self.safe_integer(item, 'time')
|
3028
|
+
delta = self.safe_dict(item, 'delta', {})
|
3029
|
+
fee = None
|
3030
|
+
feeCost = self.safe_integer(delta, 'fee')
|
3031
|
+
if feeCost is not None:
|
3032
|
+
fee = {
|
3033
|
+
'currency': 'USDC',
|
3034
|
+
'cost': feeCost,
|
3035
|
+
}
|
3036
|
+
type = self.safe_string(delta, 'type')
|
3037
|
+
amount = self.safe_string(delta, 'usdc')
|
3038
|
+
return self.safe_ledger_entry({
|
3039
|
+
'info': item,
|
3040
|
+
'id': self.safe_string(item, 'hash'),
|
3041
|
+
'direction': None,
|
3042
|
+
'account': None,
|
3043
|
+
'referenceAccount': self.safe_string(delta, 'user'),
|
3044
|
+
'referenceId': self.safe_string(item, 'hash'),
|
3045
|
+
'type': self.parse_ledger_entry_type(type),
|
3046
|
+
'currency': None,
|
3047
|
+
'amount': self.parse_number(amount),
|
3048
|
+
'timestamp': timestamp,
|
3049
|
+
'datetime': self.iso8601(timestamp),
|
3050
|
+
'before': None,
|
3051
|
+
'after': None,
|
3052
|
+
'status': None,
|
3053
|
+
'fee': fee,
|
3054
|
+
}, currency)
|
3055
|
+
|
3056
|
+
def parse_ledger_entry_type(self, type):
|
3057
|
+
ledgerType: dict = {
|
3058
|
+
'internalTransfer': 'transfer',
|
3059
|
+
'accountClassTransfer': 'transfer',
|
3060
|
+
}
|
3061
|
+
return self.safe_string(ledgerType, type, type)
|
3062
|
+
|
3063
|
+
async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
3064
|
+
"""
|
3065
|
+
fetch all deposits made to an account
|
3066
|
+
:param str code: unified currency code
|
3067
|
+
:param int [since]: the earliest time in ms to fetch deposits for
|
3068
|
+
:param int [limit]: the maximum number of deposits structures to retrieve
|
3069
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
3070
|
+
:param int [params.until]: the latest time in ms to fetch withdrawals for
|
3071
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
3072
|
+
"""
|
3073
|
+
await self.load_markets()
|
3074
|
+
userAddress = None
|
3075
|
+
userAddress, params = self.handle_public_address('fetchDepositsWithdrawals', params)
|
3076
|
+
request: dict = {
|
3077
|
+
'type': 'userNonFundingLedgerUpdates',
|
3078
|
+
'user': userAddress,
|
3079
|
+
}
|
3080
|
+
if since is not None:
|
3081
|
+
request['startTime'] = since
|
3082
|
+
until = self.safe_integer(params, 'until')
|
3083
|
+
if until is not None:
|
3084
|
+
request['endTime'] = until
|
3085
|
+
params = self.omit(params, ['until'])
|
3086
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
3087
|
+
#
|
3088
|
+
# [
|
3089
|
+
# {
|
3090
|
+
# "time":1724762307531,
|
3091
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
3092
|
+
# "delta":{
|
3093
|
+
# "type":"accountClassTransfer",
|
3094
|
+
# "usdc":"50.0",
|
3095
|
+
# "toPerp":false
|
3096
|
+
# }
|
3097
|
+
# }
|
3098
|
+
# ]
|
3099
|
+
#
|
3100
|
+
records = self.extract_type_from_delta(response)
|
3101
|
+
deposits = self.filter_by_array(records, 'type', ['deposit'], False)
|
3102
|
+
return self.parse_transactions(deposits, None, since, limit)
|
3103
|
+
|
3104
|
+
async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
3105
|
+
"""
|
3106
|
+
fetch all withdrawals made from an account
|
3107
|
+
:param str code: unified currency code
|
3108
|
+
:param int [since]: the earliest time in ms to fetch withdrawals for
|
3109
|
+
:param int [limit]: the maximum number of withdrawals structures to retrieve
|
3110
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
3111
|
+
:param int [params.until]: the latest time in ms to fetch withdrawals for
|
3112
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
3113
|
+
"""
|
3114
|
+
await self.load_markets()
|
3115
|
+
userAddress = None
|
3116
|
+
userAddress, params = self.handle_public_address('fetchDepositsWithdrawals', params)
|
3117
|
+
request: dict = {
|
3118
|
+
'type': 'userNonFundingLedgerUpdates',
|
3119
|
+
'user': userAddress,
|
3120
|
+
}
|
3121
|
+
if since is not None:
|
3122
|
+
request['startTime'] = since
|
3123
|
+
until = self.safe_integer(params, 'until')
|
3124
|
+
if until is not None:
|
3125
|
+
request['endTime'] = until
|
3126
|
+
params = self.omit(params, ['until'])
|
3127
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
3128
|
+
#
|
3129
|
+
# [
|
3130
|
+
# {
|
3131
|
+
# "time":1724762307531,
|
3132
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
3133
|
+
# "delta":{
|
3134
|
+
# "type":"accountClassTransfer",
|
3135
|
+
# "usdc":"50.0",
|
3136
|
+
# "toPerp":false
|
3137
|
+
# }
|
3138
|
+
# }
|
3139
|
+
# ]
|
3140
|
+
#
|
3141
|
+
records = self.extract_type_from_delta(response)
|
3142
|
+
withdrawals = self.filter_by_array(records, 'type', ['withdraw'], False)
|
3143
|
+
return self.parse_transactions(withdrawals, None, since, limit)
|
3144
|
+
|
3145
|
+
async def fetch_open_interests(self, symbols: Strings = None, params={}):
|
3146
|
+
"""
|
3147
|
+
Retrieves the open interest for a list of symbols
|
3148
|
+
:param str[] [symbols]: Unified CCXT market symbol
|
3149
|
+
:param dict [params]: exchange specific parameters
|
3150
|
+
:returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
|
3151
|
+
"""
|
3152
|
+
await self.load_markets()
|
3153
|
+
symbols = self.market_symbols(symbols)
|
3154
|
+
swapMarkets = await self.fetch_swap_markets()
|
3155
|
+
return self.parse_open_interests(swapMarkets, symbols)
|
3156
|
+
|
3157
|
+
async def fetch_open_interest(self, symbol: str, params={}):
|
3158
|
+
"""
|
3159
|
+
retrieves the open interest of a contract trading pair
|
3160
|
+
:param str symbol: unified CCXT market symbol
|
3161
|
+
:param dict [params]: exchange specific parameters
|
3162
|
+
:returns dict: an `open interest structure <https://docs.ccxt.com/#/?id=open-interest-structure>`
|
3163
|
+
"""
|
3164
|
+
symbol = self.symbol(symbol)
|
3165
|
+
await self.load_markets()
|
3166
|
+
ois = await self.fetch_open_interests([symbol], params)
|
3167
|
+
return ois[symbol]
|
3168
|
+
|
3169
|
+
def parse_open_interest(self, interest, market: Market = None):
|
3170
|
+
#
|
3171
|
+
# {
|
3172
|
+
# szDecimals: '2',
|
3173
|
+
# name: 'HYPE',
|
3174
|
+
# maxLeverage: '3',
|
3175
|
+
# funding: '0.00014735',
|
3176
|
+
# openInterest: '14677900.74',
|
3177
|
+
# prevDayPx: '26.145',
|
3178
|
+
# dayNtlVlm: '299643445.12560016',
|
3179
|
+
# premium: '0.00081613',
|
3180
|
+
# oraclePx: '27.569',
|
3181
|
+
# markPx: '27.63',
|
3182
|
+
# midPx: '27.599',
|
3183
|
+
# impactPxs: ['27.5915', '27.6319'],
|
3184
|
+
# dayBaseVlm: '10790652.83',
|
3185
|
+
# baseId: 159
|
3186
|
+
# }
|
3187
|
+
#
|
3188
|
+
interest = self.safe_dict(interest, 'info', {})
|
3189
|
+
coin = self.safe_string(interest, 'name')
|
3190
|
+
marketId = None
|
3191
|
+
if coin is not None:
|
3192
|
+
marketId = self.coin_to_market_id(coin)
|
3193
|
+
return self.safe_open_interest({
|
3194
|
+
'symbol': self.safe_symbol(marketId),
|
3195
|
+
'openInterestAmount': self.safe_number(interest, 'openInterest'),
|
3196
|
+
'openInterestValue': None,
|
3197
|
+
'timestamp': None,
|
3198
|
+
'datetime': None,
|
3199
|
+
'info': interest,
|
3200
|
+
}, market)
|
3201
|
+
|
3202
|
+
def extract_type_from_delta(self, data=[]):
|
3203
|
+
records = []
|
3204
|
+
for i in range(0, len(data)):
|
3205
|
+
record = data[i]
|
3206
|
+
record['type'] = record['delta']['type']
|
3207
|
+
records.append(record)
|
3208
|
+
return records
|
3209
|
+
|
3210
|
+
def format_vault_address(self, address: Str = None):
|
3211
|
+
if address is None:
|
3212
|
+
return None
|
3213
|
+
if address.startswith('0x'):
|
3214
|
+
return address.replace('0x', '')
|
3215
|
+
return address
|
1882
3216
|
|
1883
3217
|
def handle_public_address(self, methodName: str, params: dict):
|
1884
3218
|
userAux = None
|
1885
3219
|
userAux, params = self.handle_option_and_params(params, methodName, 'user')
|
1886
3220
|
user = userAux
|
1887
3221
|
user, params = self.handle_option_and_params(params, methodName, 'address', userAux)
|
1888
|
-
if user is not None:
|
3222
|
+
if (user is not None) and (user != ''):
|
1889
3223
|
return [user, params]
|
1890
|
-
if self.walletAddress is not None:
|
3224
|
+
if (self.walletAddress is not None) and (self.walletAddress != ''):
|
1891
3225
|
return [self.walletAddress, params]
|
1892
3226
|
raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a user parameter inside \'params\' or the wallet address set')
|
1893
3227
|
|
1894
|
-
def
|
3228
|
+
def coin_to_market_id(self, coin: Str):
|
3229
|
+
if coin.find('/') > -1 or coin.find('@') > -1:
|
3230
|
+
return coin # spot
|
3231
|
+
return coin + '/USDC:USDC'
|
3232
|
+
|
3233
|
+
def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
|
1895
3234
|
if not response:
|
1896
3235
|
return None # fallback to default error handler
|
1897
3236
|
# {"status":"err","response":"User or API Wallet 0xb8a6f8b26223de27c31938d56e470a5b832703a5 does not exist."}
|
@@ -1928,3 +3267,29 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1928
3267
|
}
|
1929
3268
|
body = self.json(params)
|
1930
3269
|
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
3270
|
+
|
3271
|
+
def calculate_rate_limiter_cost(self, api, method, path, params, config={}):
|
3272
|
+
if ('byType' in config) and ('type' in params):
|
3273
|
+
type = params['type']
|
3274
|
+
byType = config['byType']
|
3275
|
+
if type in byType:
|
3276
|
+
return byType[type]
|
3277
|
+
return self.safe_value(config, 'cost', 1)
|
3278
|
+
|
3279
|
+
def parse_create_order_args(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
3280
|
+
market = self.market(symbol)
|
3281
|
+
vaultAddress = self.safe_string(params, 'vaultAddress')
|
3282
|
+
params = self.omit(params, 'vaultAddress')
|
3283
|
+
symbol = market['symbol']
|
3284
|
+
order = {
|
3285
|
+
'symbol': symbol,
|
3286
|
+
'type': type,
|
3287
|
+
'side': side,
|
3288
|
+
'amount': amount,
|
3289
|
+
'price': price,
|
3290
|
+
'params': params,
|
3291
|
+
}
|
3292
|
+
globalParams = {}
|
3293
|
+
if vaultAddress is not None:
|
3294
|
+
globalParams['vaultAddress'] = vaultAddress
|
3295
|
+
return [order, globalParams]
|