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