ccxt-ir 4.3.46.0.3__py2.py3-none-any.whl → 4.5.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccxt/__init__.py +39 -35
- ccxt/abantether.py +8 -8
- ccxt/abstract/alpaca.py +4 -0
- ccxt/abstract/apex.py +31 -0
- ccxt/abstract/bigone.py +1 -1
- ccxt/abstract/binance.py +106 -48
- ccxt/abstract/binancecoinm.py +106 -48
- ccxt/abstract/binanceus.py +141 -83
- ccxt/abstract/binanceusdm.py +106 -48
- ccxt/abstract/bingx.py +50 -1
- ccxt/abstract/bitbank.py +5 -0
- ccxt/abstract/bitfinex.py +136 -65
- ccxt/abstract/bitflyer.py +1 -0
- ccxt/abstract/bitget.py +67 -0
- ccxt/abstract/bitmart.py +19 -1
- ccxt/abstract/bitopro.py +1 -0
- ccxt/abstract/bitrue.py +68 -68
- ccxt/abstract/bitstamp.py +1 -0
- ccxt/abstract/blofin.py +30 -0
- ccxt/abstract/btcbox.py +2 -0
- ccxt/abstract/bybit.py +28 -13
- ccxt/abstract/cex.py +28 -29
- ccxt/abstract/coinbaseexchange.py +1 -0
- ccxt/abstract/coinbaseinternational.py +1 -1
- ccxt/abstract/cryptocom.py +16 -0
- ccxt/abstract/cryptomus.py +20 -0
- ccxt/abstract/defx.py +69 -0
- ccxt/abstract/deribit.py +1 -0
- ccxt/abstract/derive.py +117 -0
- ccxt/abstract/digifinex.py +1 -0
- ccxt/abstract/ellipx.py +25 -0
- ccxt/abstract/foxbit.py +26 -0
- ccxt/abstract/gate.py +19 -0
- ccxt/abstract/gateio.py +19 -0
- ccxt/abstract/gemini.py +1 -0
- ccxt/abstract/hibachi.py +26 -0
- ccxt/abstract/hyperliquid.py +1 -1
- ccxt/abstract/independentreserve.py +6 -0
- ccxt/abstract/kraken.py +1 -0
- ccxt/abstract/krakenfutures.py +4 -0
- ccxt/abstract/kucoin.py +10 -0
- ccxt/abstract/kucoinfutures.py +18 -0
- ccxt/abstract/lbank.py +2 -1
- ccxt/abstract/luno.py +1 -0
- ccxt/abstract/mexc.py +2 -0
- ccxt/abstract/modetrade.py +119 -0
- ccxt/abstract/myokx.py +349 -0
- ccxt/abstract/oceanex.py +5 -0
- ccxt/abstract/okx.py +25 -0
- ccxt/abstract/okxus.py +349 -0
- ccxt/abstract/onetrading.py +0 -12
- ccxt/abstract/paradex.py +23 -0
- ccxt/abstract/phemex.py +2 -0
- ccxt/abstract/poloniex.py +36 -0
- ccxt/abstract/tradeogre.py +3 -1
- ccxt/abstract/upbit.py +51 -34
- ccxt/abstract/whitebit.py +16 -0
- ccxt/abstract/woo.py +64 -6
- ccxt/abstract/xt.py +10 -5
- ccxt/afratether.py +8 -8
- ccxt/alpaca.py +828 -51
- ccxt/apex.py +1875 -0
- ccxt/arzinja.py +7 -7
- ccxt/arzplus.py +9 -9
- ccxt/ascendex.py +501 -306
- ccxt/async_support/__init__.py +39 -35
- ccxt/async_support/abantether.py +8 -8
- ccxt/async_support/afratether.py +10 -10
- ccxt/async_support/alpaca.py +828 -51
- ccxt/async_support/apex.py +1875 -0
- ccxt/async_support/arzinja.py +10 -10
- ccxt/async_support/arzplus.py +12 -12
- ccxt/async_support/ascendex.py +502 -306
- ccxt/async_support/base/exchange.py +303 -89
- ccxt/async_support/base/ws/cache.py +9 -3
- ccxt/async_support/base/ws/client.py +173 -38
- ccxt/async_support/base/ws/future.py +25 -37
- ccxt/async_support/bequant.py +5 -3
- ccxt/async_support/bigone.py +279 -144
- ccxt/async_support/binance.py +2347 -1158
- ccxt/async_support/binancecoinm.py +9 -3
- ccxt/async_support/binanceus.py +17 -3
- ccxt/async_support/binanceusdm.py +9 -4
- ccxt/async_support/bingx.py +2962 -920
- ccxt/async_support/bit2c.py +147 -27
- ccxt/async_support/bitbank.py +151 -23
- ccxt/async_support/bitbns.py +104 -30
- ccxt/async_support/bitfinex.py +3291 -1113
- ccxt/async_support/bitflyer.py +202 -27
- ccxt/async_support/bitget.py +3683 -1538
- ccxt/async_support/bithumb.py +195 -38
- ccxt/async_support/bitimen.py +12 -12
- ccxt/async_support/bitir.py +38 -38
- ccxt/async_support/bitmart.py +1288 -350
- ccxt/async_support/bitmex.py +260 -75
- ccxt/async_support/bitopro.py +262 -62
- ccxt/async_support/bitpin.py +17 -16
- ccxt/async_support/bitrue.py +459 -290
- ccxt/async_support/bitso.py +199 -54
- ccxt/async_support/bitstamp.py +230 -96
- ccxt/async_support/bitteam.py +167 -25
- ccxt/async_support/{huobijp.py → bittrade.py} +158 -30
- ccxt/async_support/bitvavo.py +213 -49
- ccxt/async_support/blockchaincom.py +160 -46
- ccxt/async_support/blofin.py +502 -120
- ccxt/async_support/btcalpha.py +169 -31
- ccxt/async_support/btcbox.py +292 -23
- ccxt/async_support/btcmarkets.py +211 -58
- ccxt/async_support/btcturk.py +161 -38
- ccxt/async_support/bybit.py +1775 -1030
- ccxt/async_support/cex.py +1440 -1303
- ccxt/async_support/coinbase.py +724 -212
- ccxt/async_support/coinbaseadvanced.py +2 -1
- ccxt/async_support/coinbaseexchange.py +388 -89
- ccxt/async_support/coinbaseinternational.py +412 -57
- ccxt/async_support/coincatch.py +177 -78
- ccxt/async_support/coincheck.py +135 -19
- ccxt/async_support/coinex.py +606 -232
- ccxt/async_support/coinmate.py +189 -63
- ccxt/async_support/coinmetro.py +195 -54
- ccxt/async_support/coinone.py +158 -51
- ccxt/async_support/coinsph.py +336 -61
- ccxt/async_support/coinspot.py +151 -52
- ccxt/async_support/cryptocom.py +661 -111
- ccxt/async_support/cryptomus.py +1137 -0
- ccxt/async_support/defx.py +2071 -0
- ccxt/async_support/delta.py +299 -99
- ccxt/async_support/deribit.py +348 -126
- ccxt/async_support/derive.py +2572 -0
- ccxt/async_support/digifinex.py +430 -214
- ccxt/async_support/ellipx.py +2029 -0
- ccxt/async_support/eterex.py +10 -10
- ccxt/async_support/excoino.py +31 -31
- ccxt/async_support/exir.py +14 -14
- ccxt/async_support/exmo.py +344 -131
- ccxt/async_support/exnovin.py +10 -10
- ccxt/async_support/farhadexchange.py +12 -12
- ccxt/async_support/fmfwio.py +2 -1
- ccxt/async_support/foxbit.py +1935 -0
- ccxt/async_support/gate.py +1351 -529
- ccxt/async_support/gateio.py +2 -1
- ccxt/async_support/gemini.py +144 -39
- ccxt/async_support/hashkey.py +152 -109
- ccxt/async_support/hibachi.py +2080 -0
- ccxt/async_support/hitbtc.py +395 -167
- ccxt/async_support/hitobit.py +12 -12
- ccxt/async_support/hollaex.py +307 -119
- ccxt/async_support/htx.py +851 -383
- ccxt/async_support/huobi.py +2 -1
- ccxt/async_support/hyperliquid.py +1848 -536
- ccxt/async_support/independentreserve.py +288 -15
- ccxt/async_support/indodax.py +190 -33
- ccxt/async_support/jibitex.py +12 -12
- ccxt/async_support/kraken.py +795 -351
- ccxt/async_support/krakenfutures.py +214 -62
- ccxt/async_support/kucoin.py +715 -396
- ccxt/async_support/kucoinfutures.py +652 -89
- ccxt/async_support/latoken.py +217 -113
- ccxt/async_support/lbank.py +425 -97
- ccxt/async_support/luno.py +382 -35
- ccxt/async_support/mercado.py +113 -6
- ccxt/async_support/mexc.py +874 -437
- ccxt/async_support/modetrade.py +2818 -0
- ccxt/async_support/myokx.py +54 -0
- ccxt/async_support/ndax.py +221 -64
- ccxt/async_support/nobitex.py +32 -38
- ccxt/async_support/novadax.py +190 -34
- ccxt/async_support/oceanex.py +217 -28
- ccxt/async_support/okcoin.py +253 -145
- ccxt/async_support/okexchange.py +11 -11
- ccxt/async_support/okx.py +1088 -351
- ccxt/async_support/okxus.py +54 -0
- ccxt/async_support/ompfinex.py +32 -27
- ccxt/async_support/onetrading.py +213 -392
- ccxt/async_support/oxfun.py +245 -166
- ccxt/async_support/p2b.py +151 -29
- ccxt/async_support/paradex.py +562 -49
- ccxt/async_support/paymium.py +82 -19
- ccxt/async_support/phemex.py +713 -172
- ccxt/async_support/poloniex.py +1602 -283
- ccxt/async_support/probit.py +224 -95
- ccxt/async_support/ramzinex.py +34 -30
- ccxt/async_support/sarmayex.py +9 -9
- ccxt/async_support/sarrafex.py +13 -13
- ccxt/async_support/tabdeal.py +15 -14
- ccxt/async_support/tetherland.py +9 -9
- ccxt/async_support/timex.py +210 -51
- ccxt/async_support/tokocrypto.py +167 -47
- ccxt/async_support/tradeogre.py +266 -31
- ccxt/async_support/twox.py +9 -9
- ccxt/async_support/ubitex.py +12 -12
- ccxt/async_support/upbit.py +568 -165
- ccxt/async_support/vertex.py +160 -32
- ccxt/async_support/wallex.py +12 -12
- ccxt/async_support/wavesexchange.py +165 -30
- ccxt/async_support/whitebit.py +975 -127
- ccxt/async_support/woo.py +1918 -1016
- ccxt/async_support/woofipro.py +433 -141
- ccxt/async_support/xt.py +649 -193
- ccxt/async_support/yobit.py +195 -70
- ccxt/async_support/zaif.py +91 -15
- ccxt/async_support/zonda.py +151 -36
- ccxt/base/decimal_to_precision.py +14 -10
- ccxt/base/errors.py +49 -18
- ccxt/base/exchange.py +1556 -450
- ccxt/base/precise.py +10 -0
- ccxt/base/types.py +114 -6
- ccxt/bequant.py +5 -3
- ccxt/bigone.py +279 -144
- ccxt/binance.py +2347 -1158
- ccxt/binancecoinm.py +9 -3
- ccxt/binanceus.py +17 -3
- ccxt/binanceusdm.py +9 -4
- ccxt/bingx.py +2962 -920
- ccxt/bit2c.py +147 -27
- ccxt/bitbank.py +151 -23
- ccxt/bitbns.py +104 -30
- ccxt/bitfinex.py +3290 -1113
- ccxt/bitflyer.py +202 -27
- ccxt/bitget.py +3683 -1538
- ccxt/bithumb.py +194 -38
- ccxt/bitimen.py +9 -9
- ccxt/bitir.py +35 -35
- ccxt/bitmart.py +1288 -350
- ccxt/bitmex.py +260 -75
- ccxt/bitopro.py +262 -62
- ccxt/bitpin.py +15 -14
- ccxt/bitrue.py +459 -290
- ccxt/bitso.py +199 -54
- ccxt/bitstamp.py +230 -96
- ccxt/bitteam.py +167 -25
- ccxt/{huobijp.py → bittrade.py} +158 -30
- ccxt/bitvavo.py +213 -49
- ccxt/blockchaincom.py +160 -46
- ccxt/blofin.py +502 -120
- ccxt/btcalpha.py +169 -31
- ccxt/btcbox.py +291 -23
- ccxt/btcmarkets.py +211 -58
- ccxt/btcturk.py +161 -38
- ccxt/bybit.py +1775 -1030
- ccxt/cex.py +1439 -1303
- ccxt/coinbase.py +724 -212
- ccxt/coinbaseadvanced.py +2 -1
- ccxt/coinbaseexchange.py +388 -89
- ccxt/coinbaseinternational.py +412 -57
- ccxt/coincatch.py +177 -78
- ccxt/coincheck.py +135 -19
- ccxt/coinex.py +606 -232
- ccxt/coinmate.py +189 -63
- ccxt/coinmetro.py +194 -54
- ccxt/coinone.py +158 -51
- ccxt/coinsph.py +336 -61
- ccxt/coinspot.py +151 -52
- ccxt/cryptocom.py +661 -111
- ccxt/cryptomus.py +1137 -0
- ccxt/defx.py +2070 -0
- ccxt/delta.py +299 -99
- ccxt/deribit.py +348 -126
- ccxt/derive.py +2571 -0
- ccxt/digifinex.py +430 -214
- ccxt/ellipx.py +2029 -0
- ccxt/eterex.py +7 -7
- ccxt/excoino.py +29 -29
- ccxt/exir.py +11 -11
- ccxt/exmo.py +343 -131
- ccxt/exnovin.py +8 -8
- ccxt/farhadexchange.py +10 -10
- ccxt/fmfwio.py +2 -1
- ccxt/foxbit.py +1935 -0
- ccxt/gate.py +1351 -529
- ccxt/gateio.py +2 -1
- ccxt/gemini.py +144 -39
- ccxt/hashkey.py +152 -109
- ccxt/hibachi.py +2079 -0
- ccxt/hitbtc.py +395 -167
- ccxt/hitobit.py +9 -9
- ccxt/hollaex.py +307 -119
- ccxt/htx.py +851 -383
- ccxt/huobi.py +2 -1
- ccxt/hyperliquid.py +1848 -536
- ccxt/independentreserve.py +287 -15
- ccxt/indodax.py +190 -33
- ccxt/jibitex.py +9 -9
- ccxt/kraken.py +794 -351
- ccxt/krakenfutures.py +214 -62
- ccxt/kucoin.py +715 -396
- ccxt/kucoinfutures.py +652 -89
- ccxt/latoken.py +217 -113
- ccxt/lbank.py +425 -97
- ccxt/luno.py +382 -35
- ccxt/mercado.py +113 -6
- ccxt/mexc.py +873 -437
- ccxt/modetrade.py +2818 -0
- ccxt/myokx.py +54 -0
- ccxt/ndax.py +221 -64
- ccxt/nobitex.py +30 -36
- ccxt/novadax.py +190 -34
- ccxt/oceanex.py +217 -28
- ccxt/okcoin.py +253 -145
- ccxt/okexchange.py +9 -9
- ccxt/okx.py +1088 -351
- ccxt/okxus.py +54 -0
- ccxt/ompfinex.py +29 -24
- ccxt/onetrading.py +213 -392
- ccxt/oxfun.py +245 -166
- ccxt/p2b.py +151 -29
- ccxt/paradex.py +562 -49
- ccxt/paymium.py +82 -19
- ccxt/phemex.py +712 -172
- ccxt/poloniex.py +1601 -283
- ccxt/pro/__init__.py +76 -17
- ccxt/pro/alpaca.py +21 -6
- ccxt/pro/apex.py +984 -0
- ccxt/pro/ascendex.py +58 -10
- ccxt/pro/bequant.py +6 -1
- ccxt/pro/binance.py +728 -156
- ccxt/pro/binancecoinm.py +6 -2
- ccxt/pro/binanceus.py +8 -4
- ccxt/pro/binanceusdm.py +7 -2
- ccxt/pro/bingx.py +333 -142
- ccxt/pro/bitfinex.py +727 -262
- ccxt/pro/bitget.py +570 -79
- ccxt/pro/bithumb.py +20 -6
- ccxt/pro/bitmart.py +216 -87
- ccxt/pro/bitmex.py +47 -9
- ccxt/pro/bitopro.py +26 -14
- ccxt/pro/bitrue.py +22 -22
- ccxt/pro/bitstamp.py +54 -21
- ccxt/pro/{huobijp.py → bittrade.py} +7 -6
- ccxt/pro/bitvavo.py +191 -67
- ccxt/pro/blockchaincom.py +21 -8
- ccxt/pro/blofin.py +9 -1
- ccxt/pro/bybit.py +632 -245
- ccxt/pro/cex.py +59 -24
- ccxt/pro/coinbase.py +102 -73
- ccxt/pro/coinbaseadvanced.py +2 -1
- ccxt/pro/coinbaseexchange.py +8 -8
- ccxt/pro/coinbaseinternational.py +181 -25
- ccxt/pro/coincatch.py +6 -7
- ccxt/pro/coincheck.py +11 -6
- ccxt/pro/coinex.py +967 -665
- ccxt/pro/coinone.py +16 -9
- ccxt/pro/cryptocom.py +448 -45
- ccxt/pro/defx.py +831 -0
- ccxt/pro/deribit.py +150 -14
- ccxt/pro/derive.py +704 -0
- ccxt/pro/exmo.py +239 -6
- ccxt/pro/gate.py +623 -65
- ccxt/pro/gateio.py +2 -1
- ccxt/pro/gemini.py +27 -11
- ccxt/pro/hashkey.py +2 -2
- ccxt/pro/hitbtc.py +196 -91
- ccxt/pro/hollaex.py +23 -7
- ccxt/pro/htx.py +51 -14
- ccxt/pro/huobi.py +2 -1
- ccxt/pro/hyperliquid.py +591 -27
- ccxt/pro/independentreserve.py +9 -6
- ccxt/pro/kraken.py +640 -320
- ccxt/pro/krakenfutures.py +62 -35
- ccxt/pro/kucoin.py +267 -46
- ccxt/pro/kucoinfutures.py +165 -21
- ccxt/pro/lbank.py +102 -21
- ccxt/pro/luno.py +12 -8
- ccxt/pro/mexc.py +877 -111
- ccxt/pro/modetrade.py +1271 -0
- ccxt/pro/myokx.py +38 -0
- ccxt/pro/ndax.py +15 -2
- ccxt/pro/okcoin.py +23 -4
- ccxt/pro/okx.py +573 -98
- ccxt/pro/okxus.py +38 -0
- ccxt/pro/onetrading.py +30 -13
- ccxt/pro/oxfun.py +131 -27
- ccxt/pro/p2b.py +88 -22
- ccxt/pro/paradex.py +3 -3
- ccxt/pro/phemex.py +75 -21
- ccxt/pro/poloniex.py +124 -41
- ccxt/pro/probit.py +87 -80
- ccxt/pro/tradeogre.py +272 -0
- ccxt/pro/upbit.py +152 -12
- ccxt/pro/vertex.py +8 -3
- ccxt/pro/whitebit.py +58 -5
- ccxt/pro/woo.py +228 -37
- ccxt/pro/woofipro.py +106 -18
- ccxt/pro/xt.py +111 -5
- ccxt/probit.py +224 -95
- ccxt/protobuf/__init__.py +0 -0
- ccxt/protobuf/mexc/PrivateAccountV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PrivateDealsV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PrivateOrdersV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PublicAggreBookTickerV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PublicAggreDealsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicAggreDepthsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicBookTickerBatchV3Api_pb2.py +38 -0
- ccxt/protobuf/mexc/PublicBookTickerV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PublicDealsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicIncreaseDepthsBatchV3Api_pb2.py +38 -0
- ccxt/protobuf/mexc/PublicIncreaseDepthsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicLimitDepthsV3Api_pb2.py +39 -0
- ccxt/protobuf/mexc/PublicMiniTickerV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PublicMiniTickersV3Api_pb2.py +38 -0
- ccxt/protobuf/mexc/PublicSpotKlineV3Api_pb2.py +37 -0
- ccxt/protobuf/mexc/PushDataV3ApiWrapper_pb2.py +52 -0
- ccxt/protobuf/mexc/__init__.py +0 -0
- ccxt/ramzinex.py +32 -28
- ccxt/sarmayex.py +7 -7
- ccxt/sarrafex.py +10 -10
- ccxt/static_dependencies/__init__.py +1 -1
- ccxt/static_dependencies/lark/py.typed +0 -0
- ccxt/static_dependencies/marshmallow/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- ccxt/tabdeal.py +13 -12
- ccxt/test/tests_async.py +261 -57
- ccxt/test/tests_helpers.py +1 -3
- ccxt/test/tests_init.py +4 -3
- ccxt/test/tests_sync.py +261 -57
- ccxt/tetherland.py +7 -7
- ccxt/timex.py +210 -51
- ccxt/tokocrypto.py +167 -47
- ccxt/tradeogre.py +266 -31
- ccxt/twox.py +7 -7
- ccxt/ubitex.py +9 -9
- ccxt/upbit.py +568 -165
- ccxt/vertex.py +160 -32
- ccxt/wallex.py +9 -9
- ccxt/wavesexchange.py +165 -30
- ccxt/whitebit.py +975 -127
- ccxt/woo.py +1917 -1016
- ccxt/woofipro.py +432 -141
- ccxt/xt.py +649 -193
- ccxt/yobit.py +194 -70
- ccxt/zaif.py +91 -15
- ccxt/zonda.py +151 -36
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.1.dist-info}/METADATA +225 -73
- ccxt_ir-4.5.1.dist-info/RECORD +743 -0
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.1.dist-info}/WHEEL +1 -1
- ccxt/__test__.py +0 -7
- ccxt/abstract/ace.py +0 -15
- ccxt/abstract/bitbay.py +0 -53
- ccxt/abstract/bitcoincom.py +0 -115
- ccxt/abstract/bitfinex2.py +0 -139
- ccxt/abstract/bitpanda.py +0 -35
- ccxt/abstract/bl3p.py +0 -19
- ccxt/abstract/coinlist.py +0 -54
- ccxt/abstract/currencycom.py +0 -68
- ccxt/abstract/hitbtc3.py +0 -115
- ccxt/abstract/idex.py +0 -26
- ccxt/abstract/kuna.py +0 -182
- ccxt/abstract/lykke.py +0 -29
- ccxt/abstract/poloniexfutures.py +0 -48
- ccxt/abstract/wazirx.py +0 -30
- ccxt/ace.py +0 -1012
- ccxt/async_support/ace.py +0 -1012
- ccxt/async_support/base/ws/aiohttp_client.py +0 -125
- ccxt/async_support/base/ws/fast_client.py +0 -96
- ccxt/async_support/bitbay.py +0 -17
- ccxt/async_support/bitcoincom.py +0 -17
- ccxt/async_support/bitfinex2.py +0 -3552
- ccxt/async_support/bitpanda.py +0 -16
- ccxt/async_support/bl3p.py +0 -485
- ccxt/async_support/coinlist.py +0 -2243
- ccxt/async_support/currencycom.py +0 -1950
- ccxt/async_support/hitbtc3.py +0 -16
- ccxt/async_support/idex.py +0 -1766
- ccxt/async_support/kuna.py +0 -1841
- ccxt/async_support/lykke.py +0 -1270
- ccxt/async_support/poloniexfutures.py +0 -1717
- ccxt/async_support/wazirx.py +0 -1224
- ccxt/bitbay.py +0 -17
- ccxt/bitcoincom.py +0 -17
- ccxt/bitfinex2.py +0 -3552
- ccxt/bitpanda.py +0 -16
- ccxt/bl3p.py +0 -485
- ccxt/coinlist.py +0 -2243
- ccxt/currencycom.py +0 -1950
- ccxt/hitbtc3.py +0 -16
- ccxt/idex.py +0 -1766
- ccxt/kuna.py +0 -1841
- ccxt/lykke.py +0 -1270
- ccxt/poloniexfutures.py +0 -1717
- ccxt/pro/bitcoincom.py +0 -34
- ccxt/pro/bitfinex2.py +0 -1083
- ccxt/pro/bitpanda.py +0 -15
- ccxt/pro/currencycom.py +0 -536
- ccxt/pro/idex.py +0 -672
- ccxt/pro/poloniexfutures.py +0 -990
- ccxt/pro/wazirx.py +0 -749
- ccxt/test/base/__init__.py +0 -29
- ccxt/test/base/test_account.py +0 -26
- ccxt/test/base/test_balance.py +0 -56
- ccxt/test/base/test_borrow_interest.py +0 -35
- ccxt/test/base/test_borrow_rate.py +0 -32
- ccxt/test/base/test_calculate_fee.py +0 -51
- ccxt/test/base/test_crypto.py +0 -127
- ccxt/test/base/test_currency.py +0 -76
- ccxt/test/base/test_datetime.py +0 -109
- ccxt/test/base/test_decimal_to_precision.py +0 -392
- ccxt/test/base/test_deep_extend.py +0 -68
- ccxt/test/base/test_deposit_withdrawal.py +0 -50
- ccxt/test/base/test_exchange_datetime_functions.py +0 -76
- ccxt/test/base/test_funding_rate_history.py +0 -29
- ccxt/test/base/test_last_price.py +0 -31
- ccxt/test/base/test_ledger_entry.py +0 -45
- ccxt/test/base/test_ledger_item.py +0 -48
- ccxt/test/base/test_leverage_tier.py +0 -33
- ccxt/test/base/test_liquidation.py +0 -50
- ccxt/test/base/test_margin_mode.py +0 -24
- ccxt/test/base/test_margin_modification.py +0 -35
- ccxt/test/base/test_market.py +0 -193
- ccxt/test/base/test_number.py +0 -411
- ccxt/test/base/test_ohlcv.py +0 -33
- ccxt/test/base/test_open_interest.py +0 -32
- ccxt/test/base/test_order.py +0 -64
- ccxt/test/base/test_order_book.py +0 -69
- ccxt/test/base/test_position.py +0 -60
- ccxt/test/base/test_shared_methods.py +0 -353
- ccxt/test/base/test_status.py +0 -24
- ccxt/test/base/test_throttle.py +0 -126
- ccxt/test/base/test_ticker.py +0 -92
- ccxt/test/base/test_trade.py +0 -47
- ccxt/test/base/test_trading_fee.py +0 -26
- ccxt/test/base/test_transaction.py +0 -39
- ccxt/test/test_async.py +0 -1649
- ccxt/test/test_sync.py +0 -1648
- ccxt/wazirx.py +0 -1224
- ccxt_ir-4.3.46.0.3.dist-info/RECORD +0 -773
- /ccxt/abstract/{huobijp.py → bittrade.py} +0 -0
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.1.dist-info/licenses}/LICENSE.txt +0 -0
- {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.1.dist-info}/top_level.txt +0 -0
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
from ccxt.async_support.base.exchange import Exchange
|
|
7
7
|
from ccxt.abstract.hyperliquid import ImplicitAPI
|
|
8
8
|
import asyncio
|
|
9
|
-
|
|
9
|
+
import math
|
|
10
|
+
from ccxt.base.types import Any, Balances, Currencies, Currency, Int, LedgerEntry, MarginModification, Market, Num, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFeeInterface, Transaction, TransferEntry
|
|
10
11
|
from typing import List
|
|
11
12
|
from ccxt.base.errors import ExchangeError
|
|
12
13
|
from ccxt.base.errors import ArgumentsRequired
|
|
13
14
|
from ccxt.base.errors import BadRequest
|
|
15
|
+
from ccxt.base.errors import InsufficientFunds
|
|
14
16
|
from ccxt.base.errors import InvalidOrder
|
|
15
17
|
from ccxt.base.errors import OrderNotFound
|
|
16
18
|
from ccxt.base.errors import NotSupported
|
|
@@ -23,14 +25,14 @@ from ccxt.base.precise import Precise
|
|
|
23
25
|
|
|
24
26
|
class hyperliquid(Exchange, ImplicitAPI):
|
|
25
27
|
|
|
26
|
-
def describe(self):
|
|
28
|
+
def describe(self) -> Any:
|
|
27
29
|
return self.deep_extend(super(hyperliquid, self).describe(), {
|
|
28
30
|
'id': 'hyperliquid',
|
|
29
31
|
'name': 'Hyperliquid',
|
|
30
32
|
'countries': [],
|
|
31
33
|
'version': 'v1',
|
|
32
34
|
'rateLimit': 50, # 1200 requests per minute, 20 request per second
|
|
33
|
-
'certified':
|
|
35
|
+
'certified': True,
|
|
34
36
|
'pro': True,
|
|
35
37
|
'dex': True,
|
|
36
38
|
'has': {
|
|
@@ -55,31 +57,36 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
55
57
|
'createMarketSellOrderWithCost': False,
|
|
56
58
|
'createOrder': True,
|
|
57
59
|
'createOrders': True,
|
|
60
|
+
'createOrderWithTakeProfitAndStopLoss': True,
|
|
58
61
|
'createReduceOnlyOrder': True,
|
|
62
|
+
'createStopOrder': True,
|
|
63
|
+
'createTriggerOrder': True,
|
|
59
64
|
'editOrder': True,
|
|
65
|
+
'editOrders': True,
|
|
60
66
|
'fetchAccounts': False,
|
|
61
67
|
'fetchBalance': True,
|
|
62
68
|
'fetchBorrowInterest': False,
|
|
63
69
|
'fetchBorrowRateHistories': False,
|
|
64
70
|
'fetchBorrowRateHistory': False,
|
|
65
|
-
'
|
|
71
|
+
'fetchCanceledAndClosedOrders': True,
|
|
72
|
+
'fetchCanceledOrders': True,
|
|
66
73
|
'fetchClosedOrders': True,
|
|
67
74
|
'fetchCrossBorrowRate': False,
|
|
68
75
|
'fetchCrossBorrowRates': False,
|
|
69
76
|
'fetchCurrencies': True,
|
|
70
77
|
'fetchDepositAddress': False,
|
|
71
78
|
'fetchDepositAddresses': False,
|
|
72
|
-
'fetchDeposits':
|
|
79
|
+
'fetchDeposits': True,
|
|
73
80
|
'fetchDepositWithdrawFee': 'emulated',
|
|
74
81
|
'fetchDepositWithdrawFees': False,
|
|
75
|
-
'fetchFundingHistory':
|
|
82
|
+
'fetchFundingHistory': True,
|
|
76
83
|
'fetchFundingRate': False,
|
|
77
84
|
'fetchFundingRateHistory': True,
|
|
78
|
-
'fetchFundingRates':
|
|
85
|
+
'fetchFundingRates': True,
|
|
79
86
|
'fetchIndexOHLCV': False,
|
|
80
87
|
'fetchIsolatedBorrowRate': False,
|
|
81
88
|
'fetchIsolatedBorrowRates': False,
|
|
82
|
-
'fetchLedger':
|
|
89
|
+
'fetchLedger': True,
|
|
83
90
|
'fetchLeverage': False,
|
|
84
91
|
'fetchLeverageTiers': False,
|
|
85
92
|
'fetchLiquidations': False,
|
|
@@ -90,28 +97,29 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
90
97
|
'fetchMyLiquidations': False,
|
|
91
98
|
'fetchMyTrades': True,
|
|
92
99
|
'fetchOHLCV': True,
|
|
93
|
-
'fetchOpenInterest':
|
|
100
|
+
'fetchOpenInterest': True,
|
|
94
101
|
'fetchOpenInterestHistory': False,
|
|
102
|
+
'fetchOpenInterests': True,
|
|
95
103
|
'fetchOpenOrders': True,
|
|
96
104
|
'fetchOrder': True,
|
|
97
105
|
'fetchOrderBook': True,
|
|
98
|
-
'fetchOrders':
|
|
106
|
+
'fetchOrders': True,
|
|
99
107
|
'fetchOrderTrades': False,
|
|
100
108
|
'fetchPosition': True,
|
|
101
109
|
'fetchPositionMode': False,
|
|
102
110
|
'fetchPositions': True,
|
|
103
111
|
'fetchPositionsRisk': False,
|
|
104
112
|
'fetchPremiumIndexOHLCV': False,
|
|
105
|
-
'fetchTicker':
|
|
106
|
-
'fetchTickers':
|
|
113
|
+
'fetchTicker': 'emulated',
|
|
114
|
+
'fetchTickers': True,
|
|
107
115
|
'fetchTime': False,
|
|
108
116
|
'fetchTrades': True,
|
|
109
|
-
'fetchTradingFee':
|
|
117
|
+
'fetchTradingFee': True,
|
|
110
118
|
'fetchTradingFees': False,
|
|
111
119
|
'fetchTransfer': False,
|
|
112
120
|
'fetchTransfers': False,
|
|
113
121
|
'fetchWithdrawal': False,
|
|
114
|
-
'fetchWithdrawals':
|
|
122
|
+
'fetchWithdrawals': True,
|
|
115
123
|
'reduceMargin': True,
|
|
116
124
|
'repayCrossMargin': False,
|
|
117
125
|
'repayIsolatedMargin': False,
|
|
@@ -131,12 +139,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
131
139
|
'1h': '1h',
|
|
132
140
|
'2h': '2h',
|
|
133
141
|
'4h': '4h',
|
|
134
|
-
'
|
|
142
|
+
'8h': '8h',
|
|
135
143
|
'12h': '12h',
|
|
136
144
|
'1d': '1d',
|
|
137
145
|
'3d': '3d',
|
|
138
146
|
'1w': '1w',
|
|
139
|
-
'1M': '
|
|
147
|
+
'1M': '1M',
|
|
140
148
|
},
|
|
141
149
|
'hostname': 'hyperliquid.xyz',
|
|
142
150
|
'urls': {
|
|
@@ -157,7 +165,18 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
157
165
|
'api': {
|
|
158
166
|
'public': {
|
|
159
167
|
'post': {
|
|
160
|
-
'info':
|
|
168
|
+
'info': {
|
|
169
|
+
'cost': 20,
|
|
170
|
+
'byType': {
|
|
171
|
+
'l2Book': 2,
|
|
172
|
+
'allMids': 2,
|
|
173
|
+
'clearinghouseState': 2,
|
|
174
|
+
'orderStatus': 2,
|
|
175
|
+
'spotClearinghouseState': 2,
|
|
176
|
+
'exchangeStatus': 2,
|
|
177
|
+
'candleSnapshot': 4,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
161
180
|
},
|
|
162
181
|
},
|
|
163
182
|
'private': {
|
|
@@ -168,12 +187,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
168
187
|
},
|
|
169
188
|
'fees': {
|
|
170
189
|
'swap': {
|
|
171
|
-
'taker': self.parse_number('0.
|
|
172
|
-
'maker': self.parse_number('0.
|
|
190
|
+
'taker': self.parse_number('0.00045'),
|
|
191
|
+
'maker': self.parse_number('0.00015'),
|
|
173
192
|
},
|
|
174
193
|
'spot': {
|
|
175
|
-
'taker': self.parse_number('0.
|
|
176
|
-
'maker': self.parse_number('0.
|
|
194
|
+
'taker': self.parse_number('0.0007'),
|
|
195
|
+
'maker': self.parse_number('0.0004'),
|
|
177
196
|
},
|
|
178
197
|
},
|
|
179
198
|
'requiredCredentials': {
|
|
@@ -188,7 +207,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
188
207
|
'broad': {
|
|
189
208
|
'Price must be divisible by tick size.': InvalidOrder,
|
|
190
209
|
'Order must have minimum value of $10': InvalidOrder,
|
|
191
|
-
'Insufficient margin to place order.':
|
|
210
|
+
'Insufficient margin to place order.': InsufficientFunds,
|
|
192
211
|
'Reduce only order would increase position.': InvalidOrder,
|
|
193
212
|
'Post only order would have immediately matched,': InvalidOrder,
|
|
194
213
|
'Order could not immediately match against any resting orders.': InvalidOrder,
|
|
@@ -196,6 +215,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
196
215
|
'No liquidity available for market order.': InvalidOrder,
|
|
197
216
|
'Order was never placed, already canceled, or filled.': OrderNotFound,
|
|
198
217
|
'User or API Wallet ': InvalidOrder,
|
|
218
|
+
'Order has invalid size': InvalidOrder,
|
|
219
|
+
'Order price cannot be more than 80% away from the reference price': InvalidOrder,
|
|
220
|
+
'Order has zero size.': InvalidOrder,
|
|
221
|
+
'Insufficient spot balance asset': InsufficientFunds,
|
|
222
|
+
'Insufficient balance for withdrawal': InsufficientFunds,
|
|
223
|
+
'Insufficient balance for token transfer': InsufficientFunds,
|
|
199
224
|
},
|
|
200
225
|
},
|
|
201
226
|
'precisionMode': TICK_SIZE,
|
|
@@ -207,6 +232,114 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
207
232
|
'defaultSlippage': 0.05,
|
|
208
233
|
'zeroAddress': '0x0000000000000000000000000000000000000000',
|
|
209
234
|
},
|
|
235
|
+
'features': {
|
|
236
|
+
'default': {
|
|
237
|
+
'sandbox': True,
|
|
238
|
+
'createOrder': {
|
|
239
|
+
'marginMode': False,
|
|
240
|
+
'triggerPrice': False,
|
|
241
|
+
'triggerPriceType': None,
|
|
242
|
+
'triggerDirection': False,
|
|
243
|
+
'stopLossPrice': False,
|
|
244
|
+
'takeProfitPrice': False,
|
|
245
|
+
'attachedStopLossTakeProfit': {
|
|
246
|
+
'triggerPriceType': {
|
|
247
|
+
'last': False,
|
|
248
|
+
'mark': False,
|
|
249
|
+
'index': False,
|
|
250
|
+
},
|
|
251
|
+
'triggerPrice': True,
|
|
252
|
+
'type': True,
|
|
253
|
+
'price': True,
|
|
254
|
+
},
|
|
255
|
+
'timeInForce': {
|
|
256
|
+
'IOC': True,
|
|
257
|
+
'FOK': False,
|
|
258
|
+
'PO': True,
|
|
259
|
+
'GTD': False,
|
|
260
|
+
},
|
|
261
|
+
'hedged': False,
|
|
262
|
+
'trailing': False,
|
|
263
|
+
'leverage': False,
|
|
264
|
+
'marketBuyByCost': False,
|
|
265
|
+
'marketBuyRequiresPrice': False,
|
|
266
|
+
'selfTradePrevention': False,
|
|
267
|
+
'iceberg': False,
|
|
268
|
+
},
|
|
269
|
+
'createOrders': {
|
|
270
|
+
'max': 1000,
|
|
271
|
+
},
|
|
272
|
+
'fetchMyTrades': {
|
|
273
|
+
'marginMode': False,
|
|
274
|
+
'limit': 2000,
|
|
275
|
+
'daysBack': None,
|
|
276
|
+
'untilDays': None,
|
|
277
|
+
'symbolRequired': True,
|
|
278
|
+
},
|
|
279
|
+
'fetchOrder': {
|
|
280
|
+
'marginMode': False,
|
|
281
|
+
'trigger': False,
|
|
282
|
+
'trailing': False,
|
|
283
|
+
'symbolRequired': True,
|
|
284
|
+
},
|
|
285
|
+
'fetchOpenOrders': {
|
|
286
|
+
'marginMode': False,
|
|
287
|
+
'limit': 2000,
|
|
288
|
+
'trigger': False,
|
|
289
|
+
'trailing': False,
|
|
290
|
+
'symbolRequired': True,
|
|
291
|
+
},
|
|
292
|
+
'fetchOrders': {
|
|
293
|
+
'marginMode': False,
|
|
294
|
+
'limit': 2000,
|
|
295
|
+
'daysBack': None,
|
|
296
|
+
'untilDays': None,
|
|
297
|
+
'trigger': False,
|
|
298
|
+
'trailing': False,
|
|
299
|
+
'symbolRequired': True,
|
|
300
|
+
},
|
|
301
|
+
'fetchClosedOrders': {
|
|
302
|
+
'marginMode': False,
|
|
303
|
+
'limit': 2000,
|
|
304
|
+
'daysBack': None,
|
|
305
|
+
'daysBackCanceled': None,
|
|
306
|
+
'untilDays': None,
|
|
307
|
+
'trigger': False,
|
|
308
|
+
'trailing': False,
|
|
309
|
+
'symbolRequired': True,
|
|
310
|
+
},
|
|
311
|
+
'fetchOHLCV': {
|
|
312
|
+
'limit': 5000,
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
'spot': {
|
|
316
|
+
'extends': 'default',
|
|
317
|
+
},
|
|
318
|
+
'forPerps': {
|
|
319
|
+
'extends': 'default',
|
|
320
|
+
'createOrder': {
|
|
321
|
+
'stopLossPrice': True,
|
|
322
|
+
'takeProfitPrice': True,
|
|
323
|
+
'attachedStopLossTakeProfit': None, # todo, in two orders
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
'swap': {
|
|
327
|
+
'linear': {
|
|
328
|
+
'extends': 'forPerps',
|
|
329
|
+
},
|
|
330
|
+
'inverse': {
|
|
331
|
+
'extends': 'forPerps',
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
'future': {
|
|
335
|
+
'linear': {
|
|
336
|
+
'extends': 'forPerps',
|
|
337
|
+
},
|
|
338
|
+
'inverse': {
|
|
339
|
+
'extends': 'forPerps',
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
},
|
|
210
343
|
})
|
|
211
344
|
|
|
212
345
|
def set_sandbox_mode(self, enabled):
|
|
@@ -216,10 +349,14 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
216
349
|
async def fetch_currencies(self, params={}) -> Currencies:
|
|
217
350
|
"""
|
|
218
351
|
fetches all available currencies on an exchange
|
|
219
|
-
|
|
352
|
+
|
|
353
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-metadata
|
|
354
|
+
|
|
220
355
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
221
356
|
:returns dict: an associative dictionary of currencies
|
|
222
357
|
"""
|
|
358
|
+
if self.check_required_credentials(False):
|
|
359
|
+
await self.handle_builder_fee_approval()
|
|
223
360
|
request: dict = {
|
|
224
361
|
'type': 'meta',
|
|
225
362
|
}
|
|
@@ -245,7 +382,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
245
382
|
id = i
|
|
246
383
|
name = self.safe_string(data, 'name')
|
|
247
384
|
code = self.safe_currency_code(name)
|
|
248
|
-
result[code] = {
|
|
385
|
+
result[code] = self.safe_currency_structure({
|
|
249
386
|
'id': id,
|
|
250
387
|
'name': name,
|
|
251
388
|
'code': code,
|
|
@@ -256,15 +393,27 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
256
393
|
'withdraw': None,
|
|
257
394
|
'networks': None,
|
|
258
395
|
'fee': None,
|
|
259
|
-
|
|
260
|
-
'limits':
|
|
261
|
-
|
|
396
|
+
'type': 'crypto',
|
|
397
|
+
'limits': {
|
|
398
|
+
'amount': {
|
|
399
|
+
'min': None,
|
|
400
|
+
'max': None,
|
|
401
|
+
},
|
|
402
|
+
'withdraw': {
|
|
403
|
+
'min': None,
|
|
404
|
+
'max': None,
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
})
|
|
262
408
|
return result
|
|
263
409
|
|
|
264
410
|
async def fetch_markets(self, params={}) -> List[Market]:
|
|
265
411
|
"""
|
|
266
412
|
retrieves data on all markets for hyperliquid
|
|
267
|
-
|
|
413
|
+
|
|
414
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
|
415
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-spot-asset-contexts
|
|
416
|
+
|
|
268
417
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
269
418
|
:returns dict[]: an array of objects representing market data
|
|
270
419
|
"""
|
|
@@ -280,7 +429,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
280
429
|
async def fetch_swap_markets(self, params={}) -> List[Market]:
|
|
281
430
|
"""
|
|
282
431
|
retrieves data on all swap markets for hyperliquid
|
|
283
|
-
|
|
432
|
+
|
|
433
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
|
434
|
+
|
|
284
435
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
285
436
|
:returns dict[]: an array of objects representing market data
|
|
286
437
|
"""
|
|
@@ -320,22 +471,66 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
320
471
|
#
|
|
321
472
|
#
|
|
322
473
|
meta = self.safe_dict(response, 0, {})
|
|
323
|
-
|
|
324
|
-
assetCtxs = self.
|
|
474
|
+
universe = self.safe_list(meta, 'universe', [])
|
|
475
|
+
assetCtxs = self.safe_list(response, 1, [])
|
|
325
476
|
result = []
|
|
326
|
-
for i in range(0, len(
|
|
477
|
+
for i in range(0, len(universe)):
|
|
327
478
|
data = self.extend(
|
|
328
|
-
self.safe_dict(
|
|
479
|
+
self.safe_dict(universe, i, {}),
|
|
329
480
|
self.safe_dict(assetCtxs, i, {})
|
|
330
481
|
)
|
|
331
482
|
data['baseId'] = i
|
|
332
483
|
result.append(data)
|
|
333
484
|
return self.parse_markets(result)
|
|
334
485
|
|
|
486
|
+
def calculate_price_precision(self, price: float, amountPrecision: float, maxDecimals: float):
|
|
487
|
+
"""
|
|
488
|
+
Helper function to calculate the Hyperliquid DECIMAL_PLACES price precision
|
|
489
|
+
:param float price: the price to use in the calculation
|
|
490
|
+
:param int amountPrecision: the amountPrecision to use in the calculation
|
|
491
|
+
:param int maxDecimals: the maxDecimals to use in the calculation
|
|
492
|
+
:returns int: The calculated price precision
|
|
493
|
+
"""
|
|
494
|
+
pricePrecision = 0
|
|
495
|
+
priceStr = self.number_to_string(price)
|
|
496
|
+
if priceStr is None:
|
|
497
|
+
return 0
|
|
498
|
+
priceSplitted = priceStr.split('.')
|
|
499
|
+
if Precise.string_eq(priceStr, '0'):
|
|
500
|
+
# Significant digits is always hasattr(self, 5) case
|
|
501
|
+
significantDigits = 5
|
|
502
|
+
# Integer digits is always hasattr(self, 0) case(0 doesn't count)
|
|
503
|
+
integerDigits = 0
|
|
504
|
+
# Calculate the price precision
|
|
505
|
+
pricePrecision = min(maxDecimals - amountPrecision, significantDigits - integerDigits)
|
|
506
|
+
elif Precise.string_gt(priceStr, '0') and Precise.string_lt(priceStr, '1'):
|
|
507
|
+
# Significant digits, always hasattr(self, 5) case
|
|
508
|
+
significantDigits = 5
|
|
509
|
+
# Get the part after the decimal separator
|
|
510
|
+
decimalPart = self.safe_string(priceSplitted, 1, '')
|
|
511
|
+
# Count the number of leading zeros in the decimal part
|
|
512
|
+
leadingZeros = 0
|
|
513
|
+
while((leadingZeros <= len(decimalPart)) and (decimalPart[leadingZeros] == '0')):
|
|
514
|
+
leadingZeros = leadingZeros + 1
|
|
515
|
+
# Calculate price precision based on leading zeros and significant digits
|
|
516
|
+
pricePrecision = leadingZeros + significantDigits
|
|
517
|
+
# Calculate the price precision based on maxDecimals - szDecimals and the calculated price precision from the previous step
|
|
518
|
+
pricePrecision = min(maxDecimals - amountPrecision, pricePrecision)
|
|
519
|
+
else:
|
|
520
|
+
# Count the numbers before the decimal separator
|
|
521
|
+
integerPart = self.safe_string(priceSplitted, 0, '')
|
|
522
|
+
# Get significant digits, take the max() of 5 and the integer digits count
|
|
523
|
+
significantDigits = max(5, len(integerPart))
|
|
524
|
+
# Calculate price precision based on maxDecimals - szDecimals and significantDigits - len(integerPart)
|
|
525
|
+
pricePrecision = min(maxDecimals - amountPrecision, significantDigits - len(integerPart))
|
|
526
|
+
return self.parse_to_int(pricePrecision)
|
|
527
|
+
|
|
335
528
|
async def fetch_spot_markets(self, params={}) -> List[Market]:
|
|
336
529
|
"""
|
|
337
530
|
retrieves data on all spot markets for hyperliquid
|
|
338
|
-
|
|
531
|
+
|
|
532
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-spot-asset-contexts
|
|
533
|
+
|
|
339
534
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
340
535
|
:returns dict[]: an array of objects representing market data
|
|
341
536
|
"""
|
|
@@ -346,127 +541,88 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
346
541
|
#
|
|
347
542
|
# [
|
|
348
543
|
# {
|
|
349
|
-
#
|
|
544
|
+
# "tokens": [
|
|
350
545
|
# {
|
|
351
|
-
#
|
|
352
|
-
#
|
|
353
|
-
#
|
|
546
|
+
# "name": "USDC",
|
|
547
|
+
# "szDecimals": 8,
|
|
548
|
+
# "weiDecimals" 8,
|
|
549
|
+
# "index": 0,
|
|
550
|
+
# "tokenId": "0x6d1e7cde53ba9467b783cb7c530ce054",
|
|
551
|
+
# "isCanonical": True,
|
|
552
|
+
# "evmContract":null,
|
|
553
|
+
# "fullName":null
|
|
354
554
|
# },
|
|
355
555
|
# {
|
|
356
|
-
#
|
|
357
|
-
#
|
|
358
|
-
#
|
|
359
|
-
#
|
|
556
|
+
# "name": "PURR",
|
|
557
|
+
# "szDecimals": 0,
|
|
558
|
+
# "weiDecimals": 5,
|
|
559
|
+
# "index": 1,
|
|
560
|
+
# "tokenId": "0xc1fb593aeffbeb02f85e0308e9956a90",
|
|
561
|
+
# "isCanonical": True,
|
|
562
|
+
# "evmContract":null,
|
|
563
|
+
# "fullName":null
|
|
564
|
+
# }
|
|
360
565
|
# ],
|
|
361
|
-
#
|
|
566
|
+
# "universe": [
|
|
362
567
|
# {
|
|
363
|
-
#
|
|
364
|
-
#
|
|
365
|
-
#
|
|
366
|
-
#
|
|
367
|
-
#
|
|
368
|
-
#
|
|
369
|
-
# ],
|
|
568
|
+
# "name": "PURR/USDC",
|
|
569
|
+
# "tokens": [1, 0],
|
|
570
|
+
# "index": 0,
|
|
571
|
+
# "isCanonical": True
|
|
572
|
+
# }
|
|
573
|
+
# ]
|
|
370
574
|
# },
|
|
371
575
|
# [
|
|
372
576
|
# {
|
|
373
|
-
#
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
#
|
|
377
|
-
# }
|
|
378
|
-
# ],
|
|
379
|
-
# ]
|
|
380
|
-
# mainnet
|
|
381
|
-
# [
|
|
382
|
-
# {
|
|
383
|
-
# "canonical_tokens2":[
|
|
384
|
-
# 0,
|
|
385
|
-
# 1
|
|
386
|
-
# ],
|
|
387
|
-
# "spot_infos":[
|
|
388
|
-
# {
|
|
389
|
-
# "name":"PURR/USDC",
|
|
390
|
-
# "tokens":[
|
|
391
|
-
# 1,
|
|
392
|
-
# 0
|
|
393
|
-
# ]
|
|
394
|
-
# }
|
|
395
|
-
# ],
|
|
396
|
-
# "token_id_to_token":[
|
|
397
|
-
# [
|
|
398
|
-
# "0x6d1e7cde53ba9467b783cb7c530ce054",
|
|
399
|
-
# 0
|
|
400
|
-
# ],
|
|
401
|
-
# [
|
|
402
|
-
# "0xc1fb593aeffbeb02f85e0308e9956a90",
|
|
403
|
-
# 1
|
|
404
|
-
# ]
|
|
405
|
-
# ],
|
|
406
|
-
# "token_infos":[
|
|
407
|
-
# {
|
|
408
|
-
# "deployer":null,
|
|
409
|
-
# "spec":{
|
|
410
|
-
# "name":"USDC",
|
|
411
|
-
# "szDecimals":"8",
|
|
412
|
-
# "weiDecimals":"8"
|
|
413
|
-
# },
|
|
414
|
-
# "spots":[
|
|
415
|
-
# ]
|
|
416
|
-
# },
|
|
417
|
-
# {
|
|
418
|
-
# "deployer":null,
|
|
419
|
-
# "spec":{
|
|
420
|
-
# "name":"PURR",
|
|
421
|
-
# "szDecimals":"0",
|
|
422
|
-
# "weiDecimals":"5"
|
|
423
|
-
# },
|
|
424
|
-
# "spots":[
|
|
425
|
-
# 0
|
|
426
|
-
# ]
|
|
427
|
-
# }
|
|
428
|
-
# ]
|
|
429
|
-
# },
|
|
430
|
-
# [
|
|
431
|
-
# {
|
|
432
|
-
# "dayNtlVlm":"35001170.16631",
|
|
433
|
-
# "markPx":"0.15743",
|
|
434
|
-
# "midPx":"0.157555",
|
|
435
|
-
# "prevDayPx":"0.158"
|
|
436
|
-
# }
|
|
577
|
+
# "dayNtlVlm":"8906.0",
|
|
578
|
+
# "markPx":"0.14",
|
|
579
|
+
# "midPx":"0.209265",
|
|
580
|
+
# "prevDayPx":"0.20432"
|
|
581
|
+
# }
|
|
437
582
|
# ]
|
|
438
583
|
# ]
|
|
439
584
|
#
|
|
440
|
-
# response differs depending on the environment(mainnet vs sandbox)
|
|
441
585
|
first = self.safe_dict(response, 0, {})
|
|
442
|
-
|
|
443
|
-
|
|
586
|
+
second = self.safe_list(response, 1, [])
|
|
587
|
+
meta = self.safe_list(first, 'universe', [])
|
|
588
|
+
tokens = self.safe_list(first, 'tokens', [])
|
|
444
589
|
markets = []
|
|
445
590
|
for i in range(0, len(meta)):
|
|
446
591
|
market = self.safe_dict(meta, i, {})
|
|
592
|
+
index = self.safe_integer(market, 'index')
|
|
593
|
+
extraData = self.safe_dict(second, index, {})
|
|
447
594
|
marketName = self.safe_string(market, 'name')
|
|
448
|
-
if marketName.find('/') < 0:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
quote = self.safe_currency_code(quoteId)
|
|
456
|
-
symbol = base + '/' + quote
|
|
595
|
+
# if marketName.find('/') < 0:
|
|
596
|
+
# # there are some weird spot markets in testnet, eg @2
|
|
597
|
+
# continue
|
|
598
|
+
# }
|
|
599
|
+
# marketParts = marketName.split('/')
|
|
600
|
+
# baseName = self.safe_string(marketParts, 0)
|
|
601
|
+
# quoteId = self.safe_string(marketParts, 1)
|
|
457
602
|
fees = self.safe_dict(self.fees, 'spot', {})
|
|
458
603
|
taker = self.safe_number(fees, 'taker')
|
|
459
604
|
maker = self.safe_number(fees, 'maker')
|
|
460
605
|
tokensPos = self.safe_list(market, 'tokens', [])
|
|
461
606
|
baseTokenPos = self.safe_integer(tokensPos, 0)
|
|
462
|
-
|
|
607
|
+
quoteTokenPos = self.safe_integer(tokensPos, 1)
|
|
463
608
|
baseTokenInfo = self.safe_dict(tokens, baseTokenPos, {})
|
|
464
|
-
|
|
609
|
+
quoteTokenInfo = self.safe_dict(tokens, quoteTokenPos, {})
|
|
610
|
+
baseName = self.safe_string(baseTokenInfo, 'name')
|
|
611
|
+
quoteId = self.safe_string(quoteTokenInfo, 'name')
|
|
612
|
+
base = self.safe_currency_code(baseName)
|
|
613
|
+
quote = self.safe_currency_code(quoteId)
|
|
614
|
+
symbol = base + '/' + quote
|
|
465
615
|
innerBaseTokenInfo = self.safe_dict(baseTokenInfo, 'spec', baseTokenInfo)
|
|
466
616
|
# innerQuoteTokenInfo = self.safe_dict(quoteTokenInfo, 'spec', quoteTokenInfo)
|
|
467
|
-
|
|
617
|
+
amountPrecisionStr = self.safe_string(innerBaseTokenInfo, 'szDecimals')
|
|
618
|
+
amountPrecision = int(amountPrecisionStr)
|
|
619
|
+
price = self.safe_number(extraData, 'midPx')
|
|
620
|
+
pricePrecision = 0
|
|
621
|
+
if price is not None:
|
|
622
|
+
pricePrecision = self.calculate_price_precision(price, amountPrecision, 8)
|
|
623
|
+
pricePrecisionStr = self.number_to_string(pricePrecision)
|
|
468
624
|
# quotePrecision = self.parse_number(self.parse_precision(self.safe_string(innerQuoteTokenInfo, 'szDecimals')))
|
|
469
|
-
baseId = self.number_to_string(
|
|
625
|
+
baseId = self.number_to_string(index + 10000)
|
|
470
626
|
markets.append(self.safe_market_structure({
|
|
471
627
|
'id': marketName,
|
|
472
628
|
'symbol': symbol,
|
|
@@ -474,6 +630,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
474
630
|
'quote': quote,
|
|
475
631
|
'settle': None,
|
|
476
632
|
'baseId': baseId,
|
|
633
|
+
'baseName': baseName,
|
|
477
634
|
'quoteId': quoteId,
|
|
478
635
|
'settleId': None,
|
|
479
636
|
'type': 'spot',
|
|
@@ -495,8 +652,8 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
495
652
|
'strike': None,
|
|
496
653
|
'optionType': None,
|
|
497
654
|
'precision': {
|
|
498
|
-
'amount':
|
|
499
|
-
'price':
|
|
655
|
+
'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
|
|
656
|
+
'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
|
|
500
657
|
},
|
|
501
658
|
'limits': {
|
|
502
659
|
'leverage': {
|
|
@@ -512,12 +669,12 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
512
669
|
'max': None,
|
|
513
670
|
},
|
|
514
671
|
'cost': {
|
|
515
|
-
'min':
|
|
672
|
+
'min': self.parse_number('10'),
|
|
516
673
|
'max': None,
|
|
517
674
|
},
|
|
518
675
|
},
|
|
519
676
|
'created': None,
|
|
520
|
-
'info': market,
|
|
677
|
+
'info': self.extend(extraData, market),
|
|
521
678
|
}))
|
|
522
679
|
return markets
|
|
523
680
|
|
|
@@ -543,7 +700,8 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
543
700
|
# }
|
|
544
701
|
#
|
|
545
702
|
quoteId = 'USDC'
|
|
546
|
-
|
|
703
|
+
baseName = self.safe_string(market, 'name')
|
|
704
|
+
base = self.safe_currency_code(baseName)
|
|
547
705
|
quote = self.safe_currency_code(quoteId)
|
|
548
706
|
baseId = self.safe_string(market, 'baseId')
|
|
549
707
|
settleId = 'USDC'
|
|
@@ -557,13 +715,25 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
557
715
|
fees = self.safe_dict(self.fees, 'swap', {})
|
|
558
716
|
taker = self.safe_number(fees, 'taker')
|
|
559
717
|
maker = self.safe_number(fees, 'maker')
|
|
560
|
-
|
|
718
|
+
amountPrecisionStr = self.safe_string(market, 'szDecimals')
|
|
719
|
+
amountPrecision = int(amountPrecisionStr)
|
|
720
|
+
price = self.safe_number(market, 'markPx', 0)
|
|
721
|
+
pricePrecision = 0
|
|
722
|
+
if price is not None:
|
|
723
|
+
pricePrecision = self.calculate_price_precision(price, amountPrecision, 6)
|
|
724
|
+
pricePrecisionStr = self.number_to_string(pricePrecision)
|
|
725
|
+
isDelisted = self.safe_bool(market, 'isDelisted')
|
|
726
|
+
active = True
|
|
727
|
+
if isDelisted is not None:
|
|
728
|
+
active = not isDelisted
|
|
729
|
+
return self.safe_market_structure({
|
|
561
730
|
'id': baseId,
|
|
562
731
|
'symbol': symbol,
|
|
563
732
|
'base': base,
|
|
564
733
|
'quote': quote,
|
|
565
734
|
'settle': settle,
|
|
566
735
|
'baseId': baseId,
|
|
736
|
+
'baseName': baseName,
|
|
567
737
|
'quoteId': quoteId,
|
|
568
738
|
'settleId': settleId,
|
|
569
739
|
'type': 'swap',
|
|
@@ -572,7 +742,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
572
742
|
'swap': swap,
|
|
573
743
|
'future': False,
|
|
574
744
|
'option': False,
|
|
575
|
-
'active':
|
|
745
|
+
'active': active,
|
|
576
746
|
'contract': contract,
|
|
577
747
|
'linear': True,
|
|
578
748
|
'inverse': False,
|
|
@@ -584,13 +754,13 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
584
754
|
'strike': None,
|
|
585
755
|
'optionType': None,
|
|
586
756
|
'precision': {
|
|
587
|
-
'amount': self.parse_number(self.parse_precision(
|
|
588
|
-
'price':
|
|
757
|
+
'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
|
|
758
|
+
'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
|
|
589
759
|
},
|
|
590
760
|
'limits': {
|
|
591
761
|
'leverage': {
|
|
592
762
|
'min': None,
|
|
593
|
-
'max':
|
|
763
|
+
'max': self.safe_integer(market, 'maxLeverage'),
|
|
594
764
|
},
|
|
595
765
|
'amount': {
|
|
596
766
|
'min': None,
|
|
@@ -601,31 +771,37 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
601
771
|
'max': None,
|
|
602
772
|
},
|
|
603
773
|
'cost': {
|
|
604
|
-
'min':
|
|
774
|
+
'min': self.parse_number('10'),
|
|
605
775
|
'max': None,
|
|
606
776
|
},
|
|
607
777
|
},
|
|
608
778
|
'created': None,
|
|
609
779
|
'info': market,
|
|
610
|
-
}
|
|
780
|
+
})
|
|
611
781
|
|
|
612
782
|
async def fetch_balance(self, params={}) -> Balances:
|
|
613
783
|
"""
|
|
614
784
|
query for balance and get the amount of funds available for trading or funds locked in orders
|
|
615
|
-
|
|
785
|
+
|
|
786
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-a-users-token-balances
|
|
787
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-users-perpetuals-account-summary
|
|
788
|
+
|
|
616
789
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
617
790
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
618
791
|
:param str [params.type]: wallet type, ['spot', 'swap'], defaults to swap
|
|
792
|
+
:param str [params.marginMode]: 'cross' or 'isolated', for margin trading, uses self.options.defaultMarginMode if not passed, defaults to None/None/None
|
|
793
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
619
794
|
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
|
620
795
|
"""
|
|
621
796
|
userAddress = None
|
|
622
797
|
userAddress, params = self.handle_public_address('fetchBalance', params)
|
|
623
798
|
type = None
|
|
624
799
|
type, params = self.handle_market_type_and_params('fetchBalance', None, params)
|
|
800
|
+
marginMode = None
|
|
801
|
+
marginMode, params = self.handle_margin_mode_and_params('fetchBalance', params)
|
|
625
802
|
isSpot = (type == 'spot')
|
|
626
|
-
reqType = 'spotClearinghouseState' if (isSpot) else 'clearinghouseState'
|
|
627
803
|
request: dict = {
|
|
628
|
-
'type':
|
|
804
|
+
'type': 'spotClearinghouseState' if (isSpot) else 'clearinghouseState',
|
|
629
805
|
'user': userAddress,
|
|
630
806
|
}
|
|
631
807
|
response = await self.publicPostInfo(self.extend(request, params))
|
|
@@ -672,18 +848,22 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
672
848
|
code = self.safe_currency_code(self.safe_string(balance, 'coin'))
|
|
673
849
|
account = self.account()
|
|
674
850
|
total = self.safe_string(balance, 'total')
|
|
675
|
-
|
|
851
|
+
used = self.safe_string(balance, 'hold')
|
|
676
852
|
account['total'] = total
|
|
677
|
-
account['
|
|
853
|
+
account['used'] = used
|
|
678
854
|
spotBalances[code] = account
|
|
679
855
|
return self.safe_balance(spotBalances)
|
|
680
856
|
data = self.safe_dict(response, 'marginSummary', {})
|
|
857
|
+
usdcBalance = {
|
|
858
|
+
'total': self.safe_number(data, 'accountValue'),
|
|
859
|
+
}
|
|
860
|
+
if (marginMode is not None) and (marginMode == 'isolated'):
|
|
861
|
+
usdcBalance['free'] = self.safe_number(response, 'withdrawable')
|
|
862
|
+
else:
|
|
863
|
+
usdcBalance['used'] = self.safe_number(data, 'totalMarginUsed')
|
|
681
864
|
result: dict = {
|
|
682
865
|
'info': response,
|
|
683
|
-
'USDC':
|
|
684
|
-
'total': self.safe_float(data, 'accountValue'),
|
|
685
|
-
'used': self.safe_float(data, 'totalMarginUsed'),
|
|
686
|
-
},
|
|
866
|
+
'USDC': usdcBalance,
|
|
687
867
|
}
|
|
688
868
|
timestamp = self.safe_integer(response, 'time')
|
|
689
869
|
result['timestamp'] = timestamp
|
|
@@ -693,7 +873,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
693
873
|
async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
|
694
874
|
"""
|
|
695
875
|
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
696
|
-
|
|
876
|
+
|
|
877
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#l2-book-snapshot
|
|
878
|
+
|
|
697
879
|
:param str symbol: unified symbol of the market to fetch the order book for
|
|
698
880
|
:param int [limit]: the maximum amount of order book entries to return
|
|
699
881
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
@@ -703,7 +885,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
703
885
|
market = self.market(symbol)
|
|
704
886
|
request: dict = {
|
|
705
887
|
'type': 'l2Book',
|
|
706
|
-
'coin': market['
|
|
888
|
+
'coin': market['baseName'] if market['swap'] else market['id'],
|
|
707
889
|
}
|
|
708
890
|
response = await self.publicPostInfo(self.extend(request, params))
|
|
709
891
|
#
|
|
@@ -736,10 +918,181 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
736
918
|
timestamp = self.safe_integer(response, 'time')
|
|
737
919
|
return self.parse_order_book(result, market['symbol'], timestamp, 'bids', 'asks', 'px', 'sz')
|
|
738
920
|
|
|
921
|
+
async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
922
|
+
"""
|
|
923
|
+
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
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
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/spot#retrieve-spot-asset-contexts
|
|
927
|
+
|
|
928
|
+
:param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
929
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
930
|
+
:param str [params.type]: 'spot' or 'swap', by default fetches both
|
|
931
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
932
|
+
"""
|
|
933
|
+
await self.load_markets()
|
|
934
|
+
symbols = self.market_symbols(symbols)
|
|
935
|
+
# at self stage, to get tickers data, we use fetchMarkets endpoints
|
|
936
|
+
response = []
|
|
937
|
+
type = self.safe_string(params, 'type')
|
|
938
|
+
params = self.omit(params, 'type')
|
|
939
|
+
if type == 'spot':
|
|
940
|
+
response = await self.fetch_spot_markets(params)
|
|
941
|
+
elif type == 'swap':
|
|
942
|
+
response = await self.fetch_swap_markets(params)
|
|
943
|
+
else:
|
|
944
|
+
response = await self.fetch_markets(params)
|
|
945
|
+
# same response "fetchMarkets"
|
|
946
|
+
result: dict = {}
|
|
947
|
+
for i in range(0, len(response)):
|
|
948
|
+
market = response[i]
|
|
949
|
+
info = market['info']
|
|
950
|
+
ticker = self.parse_ticker(info, market)
|
|
951
|
+
symbol = self.safe_string(ticker, 'symbol')
|
|
952
|
+
result[symbol] = ticker
|
|
953
|
+
return self.filter_by_array_tickers(result, 'symbol', symbols)
|
|
954
|
+
|
|
955
|
+
async def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
|
|
956
|
+
"""
|
|
957
|
+
retrieves data on all swap markets for hyperliquid
|
|
958
|
+
|
|
959
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-perpetuals-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
|
960
|
+
|
|
961
|
+
:param str[] [symbols]: list of unified market symbols
|
|
962
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
963
|
+
:returns dict[]: an array of objects representing market data
|
|
964
|
+
"""
|
|
965
|
+
request: dict = {
|
|
966
|
+
'type': 'metaAndAssetCtxs',
|
|
967
|
+
}
|
|
968
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
|
969
|
+
#
|
|
970
|
+
# [
|
|
971
|
+
# {
|
|
972
|
+
# "universe": [
|
|
973
|
+
# {
|
|
974
|
+
# "maxLeverage": 50,
|
|
975
|
+
# "name": "SOL",
|
|
976
|
+
# "onlyIsolated": False,
|
|
977
|
+
# "szDecimals": 2
|
|
978
|
+
# }
|
|
979
|
+
# ]
|
|
980
|
+
# },
|
|
981
|
+
# [
|
|
982
|
+
# {
|
|
983
|
+
# "dayNtlVlm": "9450588.2273",
|
|
984
|
+
# "funding": "0.0000198",
|
|
985
|
+
# "impactPxs": [
|
|
986
|
+
# "108.04",
|
|
987
|
+
# "108.06"
|
|
988
|
+
# ],
|
|
989
|
+
# "markPx": "108.04",
|
|
990
|
+
# "midPx": "108.05",
|
|
991
|
+
# "openInterest": "10764.48",
|
|
992
|
+
# "oraclePx": "107.99",
|
|
993
|
+
# "premium": "0.00055561",
|
|
994
|
+
# "prevDayPx": "111.81"
|
|
995
|
+
# }
|
|
996
|
+
# ]
|
|
997
|
+
# ]
|
|
998
|
+
#
|
|
999
|
+
#
|
|
1000
|
+
meta = self.safe_dict(response, 0, {})
|
|
1001
|
+
universe = self.safe_list(meta, 'universe', [])
|
|
1002
|
+
assetCtxs = self.safe_list(response, 1, [])
|
|
1003
|
+
result = []
|
|
1004
|
+
for i in range(0, len(universe)):
|
|
1005
|
+
data = self.extend(
|
|
1006
|
+
self.safe_dict(universe, i, {}),
|
|
1007
|
+
self.safe_dict(assetCtxs, i, {})
|
|
1008
|
+
)
|
|
1009
|
+
result.append(data)
|
|
1010
|
+
return self.parse_funding_rates(result, symbols)
|
|
1011
|
+
|
|
1012
|
+
def parse_funding_rate(self, info, market: Market = None) -> FundingRate:
|
|
1013
|
+
#
|
|
1014
|
+
# {
|
|
1015
|
+
# "maxLeverage": "50",
|
|
1016
|
+
# "name": "ETH",
|
|
1017
|
+
# "onlyIsolated": False,
|
|
1018
|
+
# "szDecimals": "4",
|
|
1019
|
+
# "dayNtlVlm": "1709813.11535",
|
|
1020
|
+
# "funding": "0.00004807",
|
|
1021
|
+
# "impactPxs": [
|
|
1022
|
+
# "2369.3",
|
|
1023
|
+
# "2369.6"
|
|
1024
|
+
# ],
|
|
1025
|
+
# "markPx": "2369.6",
|
|
1026
|
+
# "midPx": "2369.45",
|
|
1027
|
+
# "openInterest": "1815.4712",
|
|
1028
|
+
# "oraclePx": "2367.3",
|
|
1029
|
+
# "premium": "0.00090821",
|
|
1030
|
+
# "prevDayPx": "2381.5"
|
|
1031
|
+
# }
|
|
1032
|
+
#
|
|
1033
|
+
base = self.safe_string(info, 'name')
|
|
1034
|
+
marketId = self.coin_to_market_id(base)
|
|
1035
|
+
symbol = self.safe_symbol(marketId, market)
|
|
1036
|
+
funding = self.safe_number(info, 'funding')
|
|
1037
|
+
markPx = self.safe_number(info, 'markPx')
|
|
1038
|
+
oraclePx = self.safe_number(info, 'oraclePx')
|
|
1039
|
+
fundingTimestamp = (int(math.floor(self.milliseconds()) / 60 / 60 / 1000) + 1) * 60 * 60 * 1000
|
|
1040
|
+
return {
|
|
1041
|
+
'info': info,
|
|
1042
|
+
'symbol': symbol,
|
|
1043
|
+
'markPrice': markPx,
|
|
1044
|
+
'indexPrice': oraclePx,
|
|
1045
|
+
'interestRate': None,
|
|
1046
|
+
'estimatedSettlePrice': None,
|
|
1047
|
+
'timestamp': None,
|
|
1048
|
+
'datetime': None,
|
|
1049
|
+
'fundingRate': funding,
|
|
1050
|
+
'fundingTimestamp': fundingTimestamp,
|
|
1051
|
+
'fundingDatetime': self.iso8601(fundingTimestamp),
|
|
1052
|
+
'nextFundingRate': None,
|
|
1053
|
+
'nextFundingTimestamp': None,
|
|
1054
|
+
'nextFundingDatetime': None,
|
|
1055
|
+
'previousFundingRate': None,
|
|
1056
|
+
'previousFundingTimestamp': None,
|
|
1057
|
+
'previousFundingDatetime': None,
|
|
1058
|
+
'interval': '1h',
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
|
|
1062
|
+
#
|
|
1063
|
+
# {
|
|
1064
|
+
# "prevDayPx": "3400.5",
|
|
1065
|
+
# "dayNtlVlm": "511297257.47936022",
|
|
1066
|
+
# "markPx": "3464.7",
|
|
1067
|
+
# "midPx": "3465.05",
|
|
1068
|
+
# "oraclePx": "3460.1", # only in swap
|
|
1069
|
+
# "openInterest": "64638.1108", # only in swap
|
|
1070
|
+
# "premium": "0.00141614", # only in swap
|
|
1071
|
+
# "funding": "0.00008727", # only in swap
|
|
1072
|
+
# "impactPxs": ["3465.0", "3465.1"], # only in swap
|
|
1073
|
+
# "coin": "PURR", # only in spot
|
|
1074
|
+
# "circulatingSupply": "998949190.03400207", # only in spot
|
|
1075
|
+
# },
|
|
1076
|
+
#
|
|
1077
|
+
bidAsk = self.safe_list(ticker, 'impactPxs')
|
|
1078
|
+
return self.safe_ticker({
|
|
1079
|
+
'symbol': market['symbol'],
|
|
1080
|
+
'timestamp': None,
|
|
1081
|
+
'datetime': None,
|
|
1082
|
+
'previousClose': self.safe_number(ticker, 'prevDayPx'),
|
|
1083
|
+
'close': self.safe_number(ticker, 'midPx'),
|
|
1084
|
+
'bid': self.safe_number(bidAsk, 0),
|
|
1085
|
+
'ask': self.safe_number(bidAsk, 1),
|
|
1086
|
+
'quoteVolume': self.safe_number(ticker, 'dayNtlVlm'),
|
|
1087
|
+
'info': ticker,
|
|
1088
|
+
}, market)
|
|
1089
|
+
|
|
739
1090
|
async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
740
1091
|
"""
|
|
741
1092
|
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
742
|
-
|
|
1093
|
+
|
|
1094
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#candle-snapshot
|
|
1095
|
+
|
|
743
1096
|
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
744
1097
|
:param str timeframe: the length of time each candle represents, support '1m', '15m', '1h', '1d'
|
|
745
1098
|
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
@@ -751,16 +1104,22 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
751
1104
|
await self.load_markets()
|
|
752
1105
|
market = self.market(symbol)
|
|
753
1106
|
until = self.safe_integer(params, 'until', self.milliseconds())
|
|
1107
|
+
useTail = since is None
|
|
1108
|
+
originalSince = since
|
|
754
1109
|
if since is None:
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
1110
|
+
if limit is not None:
|
|
1111
|
+
# optimization if limit is provided
|
|
1112
|
+
timeframeInMilliseconds = self.parse_timeframe(timeframe) * 1000
|
|
1113
|
+
since = self.sum(until, timeframeInMilliseconds * limit * -1)
|
|
1114
|
+
useTail = False
|
|
1115
|
+
else:
|
|
1116
|
+
since = 0
|
|
758
1117
|
params = self.omit(params, ['until'])
|
|
759
1118
|
request: dict = {
|
|
760
1119
|
'type': 'candleSnapshot',
|
|
761
1120
|
'req': {
|
|
762
|
-
'coin': market['
|
|
763
|
-
'interval': timeframe,
|
|
1121
|
+
'coin': market['baseName'] if market['swap'] else market['id'],
|
|
1122
|
+
'interval': self.safe_string(self.timeframes, timeframe, timeframe),
|
|
764
1123
|
'startTime': since,
|
|
765
1124
|
'endTime': until,
|
|
766
1125
|
},
|
|
@@ -782,7 +1141,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
782
1141
|
# }
|
|
783
1142
|
# ]
|
|
784
1143
|
#
|
|
785
|
-
return self.parse_ohlcvs(response, market, timeframe,
|
|
1144
|
+
return self.parse_ohlcvs(response, market, timeframe, originalSince, limit, useTail)
|
|
786
1145
|
|
|
787
1146
|
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
|
788
1147
|
#
|
|
@@ -808,11 +1167,13 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
808
1167
|
self.safe_number(ohlcv, 'v'),
|
|
809
1168
|
]
|
|
810
1169
|
|
|
811
|
-
async def fetch_trades(self, symbol: Str
|
|
1170
|
+
async def fetch_trades(self, symbol: Str, since: Int = None, limit: Int = None, params={}):
|
|
812
1171
|
"""
|
|
813
1172
|
get the list of most recent trades for a particular symbol
|
|
814
|
-
|
|
815
|
-
|
|
1173
|
+
|
|
1174
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills
|
|
1175
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills-by-time
|
|
1176
|
+
|
|
816
1177
|
:param str symbol: unified market symbol
|
|
817
1178
|
:param int [since]: the earliest time in ms to fetch trades for
|
|
818
1179
|
:param int [limit]: the maximum number of trades structures to retrieve
|
|
@@ -820,6 +1181,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
820
1181
|
:param int [params.until]: timestamp in ms of the latest trade
|
|
821
1182
|
:param str [params.address]: wallet address that made trades
|
|
822
1183
|
:param str [params.user]: wallet address that made trades
|
|
1184
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
823
1185
|
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
824
1186
|
"""
|
|
825
1187
|
userAddress = None
|
|
@@ -863,15 +1225,17 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
863
1225
|
|
|
864
1226
|
def amount_to_precision(self, symbol, amount):
|
|
865
1227
|
market = self.market(symbol)
|
|
866
|
-
|
|
867
|
-
return super(hyperliquid, self).amount_to_precision(symbol, amount)
|
|
868
|
-
return self.decimal_to_precision(amount, ROUND, self.markets[symbol]['precision']['amount'], self.precisionMode)
|
|
1228
|
+
return self.decimal_to_precision(amount, ROUND, market['precision']['amount'], self.precisionMode, self.paddingMode)
|
|
869
1229
|
|
|
870
1230
|
def price_to_precision(self, symbol: str, price) -> str:
|
|
871
1231
|
market = self.market(symbol)
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1232
|
+
priceStr = self.number_to_string(price)
|
|
1233
|
+
integerPart = priceStr.split('.')[0]
|
|
1234
|
+
significantDigits = max(5, len(integerPart))
|
|
1235
|
+
result = self.decimal_to_precision(price, ROUND, significantDigits, SIGNIFICANT_DIGITS, self.paddingMode)
|
|
1236
|
+
maxDecimals = 8 if market['spot'] else 6
|
|
1237
|
+
subtractedValue = maxDecimals - self.precision_from_string(self.safe_string(market['precision'], 'amount'))
|
|
1238
|
+
return self.decimal_to_precision(result, ROUND, subtractedValue, DECIMAL_PLACES, self.paddingMode)
|
|
875
1239
|
|
|
876
1240
|
def hash_message(self, message):
|
|
877
1241
|
return '0x' + self.hash(message, 'keccak', 'hex')
|
|
@@ -963,7 +1327,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
963
1327
|
signature = self.sign_message(msg, self.privateKey)
|
|
964
1328
|
return signature
|
|
965
1329
|
|
|
966
|
-
def
|
|
1330
|
+
def build_usd_send_sig(self, message):
|
|
967
1331
|
messageTypes: dict = {
|
|
968
1332
|
'HyperliquidTransaction:UsdSend': [
|
|
969
1333
|
{'name': 'hyperliquidChain', 'type': 'string'},
|
|
@@ -974,6 +1338,17 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
974
1338
|
}
|
|
975
1339
|
return self.sign_user_signed_action(messageTypes, message)
|
|
976
1340
|
|
|
1341
|
+
def build_usd_class_send_sig(self, message):
|
|
1342
|
+
messageTypes: dict = {
|
|
1343
|
+
'HyperliquidTransaction:UsdClassTransfer': [
|
|
1344
|
+
{'name': 'hyperliquidChain', 'type': 'string'},
|
|
1345
|
+
{'name': 'amount', 'type': 'string'},
|
|
1346
|
+
{'name': 'toPerp', 'type': 'bool'},
|
|
1347
|
+
{'name': 'nonce', 'type': 'uint64'},
|
|
1348
|
+
],
|
|
1349
|
+
}
|
|
1350
|
+
return self.sign_user_signed_action(messageTypes, message)
|
|
1351
|
+
|
|
977
1352
|
def build_withdraw_sig(self, message):
|
|
978
1353
|
messageTypes: dict = {
|
|
979
1354
|
'HyperliquidTransaction:Withdraw': [
|
|
@@ -985,15 +1360,78 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
985
1360
|
}
|
|
986
1361
|
return self.sign_user_signed_action(messageTypes, message)
|
|
987
1362
|
|
|
1363
|
+
def build_approve_builder_fee_sig(self, message):
|
|
1364
|
+
messageTypes: dict = {
|
|
1365
|
+
'HyperliquidTransaction:ApproveBuilderFee': [
|
|
1366
|
+
{'name': 'hyperliquidChain', 'type': 'string'},
|
|
1367
|
+
{'name': 'maxFeeRate', 'type': 'string'},
|
|
1368
|
+
{'name': 'builder', 'type': 'address'},
|
|
1369
|
+
{'name': 'nonce', 'type': 'uint64'},
|
|
1370
|
+
],
|
|
1371
|
+
}
|
|
1372
|
+
return self.sign_user_signed_action(messageTypes, message)
|
|
1373
|
+
|
|
1374
|
+
async def approve_builder_fee(self, builder: str, maxFeeRate: str):
|
|
1375
|
+
nonce = self.milliseconds()
|
|
1376
|
+
isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
|
|
1377
|
+
payload: dict = {
|
|
1378
|
+
'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
|
|
1379
|
+
'maxFeeRate': maxFeeRate,
|
|
1380
|
+
'builder': builder,
|
|
1381
|
+
'nonce': nonce,
|
|
1382
|
+
}
|
|
1383
|
+
sig = self.build_approve_builder_fee_sig(payload)
|
|
1384
|
+
action = {
|
|
1385
|
+
'hyperliquidChain': payload['hyperliquidChain'],
|
|
1386
|
+
'signatureChainId': '0x66eee',
|
|
1387
|
+
'maxFeeRate': payload['maxFeeRate'],
|
|
1388
|
+
'builder': payload['builder'],
|
|
1389
|
+
'nonce': nonce,
|
|
1390
|
+
'type': 'approveBuilderFee',
|
|
1391
|
+
}
|
|
1392
|
+
request: dict = {
|
|
1393
|
+
'action': action,
|
|
1394
|
+
'nonce': nonce,
|
|
1395
|
+
'signature': sig,
|
|
1396
|
+
'vaultAddress': None,
|
|
1397
|
+
}
|
|
1398
|
+
#
|
|
1399
|
+
# {
|
|
1400
|
+
# "status": "ok",
|
|
1401
|
+
# "response": {
|
|
1402
|
+
# "type": "default"
|
|
1403
|
+
# }
|
|
1404
|
+
# }
|
|
1405
|
+
#
|
|
1406
|
+
return await self.privatePostExchange(request)
|
|
1407
|
+
|
|
1408
|
+
async def handle_builder_fee_approval(self):
|
|
1409
|
+
buildFee = self.safe_bool(self.options, 'builderFee', True)
|
|
1410
|
+
if not buildFee:
|
|
1411
|
+
return False # skip if builder fee is not enabled
|
|
1412
|
+
approvedBuilderFee = self.safe_bool(self.options, 'approvedBuilderFee', False)
|
|
1413
|
+
if approvedBuilderFee:
|
|
1414
|
+
return True # skip if builder fee is already approved
|
|
1415
|
+
try:
|
|
1416
|
+
builder = self.safe_string(self.options, 'builder', '0x6530512A6c89C7cfCEbC3BA7fcD9aDa5f30827a6')
|
|
1417
|
+
maxFeeRate = self.safe_string(self.options, 'feeRate', '0.01%')
|
|
1418
|
+
await self.approve_builder_fee(builder, maxFeeRate)
|
|
1419
|
+
self.options['approvedBuilderFee'] = True
|
|
1420
|
+
except Exception as e:
|
|
1421
|
+
self.options['builderFee'] = False # disable builder fee if an error occurs
|
|
1422
|
+
return True
|
|
1423
|
+
|
|
988
1424
|
async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
989
1425
|
"""
|
|
990
1426
|
create a trade order
|
|
991
|
-
|
|
1427
|
+
|
|
1428
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
|
1429
|
+
|
|
992
1430
|
:param str symbol: unified symbol of the market to create an order in
|
|
993
1431
|
:param str type: 'market' or 'limit'
|
|
994
1432
|
:param str side: 'buy' or 'sell'
|
|
995
1433
|
:param float amount: how much of currency you want to trade in units of base currency
|
|
996
|
-
:param float [price]: the price at which the order is to be
|
|
1434
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
|
997
1435
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
998
1436
|
:param str [params.timeInForce]: 'Gtc', 'Ioc', 'Alo'
|
|
999
1437
|
:param bool [params.postOnly]: True or False whether the order is post-only
|
|
@@ -1002,140 +1440,28 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1002
1440
|
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1003
1441
|
:param str [params.slippage]: the slippage for market order
|
|
1004
1442
|
:param str [params.vaultAddress]: the vault address for order
|
|
1443
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1005
1444
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1006
1445
|
"""
|
|
1007
1446
|
await self.load_markets()
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
symbol = market['symbol']
|
|
1012
|
-
order = {
|
|
1013
|
-
'symbol': symbol,
|
|
1014
|
-
'type': type,
|
|
1015
|
-
'side': side,
|
|
1016
|
-
'amount': amount,
|
|
1017
|
-
'price': price,
|
|
1018
|
-
'params': params,
|
|
1019
|
-
}
|
|
1020
|
-
globalParams: dict = {}
|
|
1021
|
-
if vaultAddress is not None:
|
|
1022
|
-
globalParams['vaultAddress'] = vaultAddress
|
|
1023
|
-
response = await self.create_orders([order], globalParams)
|
|
1024
|
-
first = self.safe_dict(response, 0)
|
|
1025
|
-
return first
|
|
1447
|
+
order, globalParams = self.parse_create_edit_order_args(None, symbol, type, side, amount, price, params)
|
|
1448
|
+
orders = await self.create_orders([order], globalParams)
|
|
1449
|
+
return orders[0]
|
|
1026
1450
|
|
|
1027
1451
|
async def create_orders(self, orders: List[OrderRequest], params={}):
|
|
1028
1452
|
"""
|
|
1029
1453
|
create a list of trade orders
|
|
1030
|
-
|
|
1454
|
+
|
|
1455
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
|
1456
|
+
|
|
1031
1457
|
: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
|
|
1458
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1032
1459
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1033
1460
|
"""
|
|
1034
|
-
self.check_required_credentials()
|
|
1035
1461
|
await self.load_markets()
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
for i in range(0, len(orders)):
|
|
1040
|
-
rawOrder = orders[i]
|
|
1041
|
-
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1042
|
-
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
|
1043
|
-
if clientOrderId is not None:
|
|
1044
|
-
hasClientOrderId = True
|
|
1045
|
-
if hasClientOrderId:
|
|
1046
|
-
for i in range(0, len(orders)):
|
|
1047
|
-
rawOrder = orders[i]
|
|
1048
|
-
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1049
|
-
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
|
1050
|
-
if clientOrderId is None:
|
|
1051
|
-
raise ArgumentsRequired(self.id + ' createOrders() all orders must have clientOrderId if at least one has a clientOrderId')
|
|
1052
|
-
params = self.omit(params, ['slippage', 'clientOrderId', 'client_id', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce'])
|
|
1053
|
-
nonce = self.milliseconds()
|
|
1054
|
-
orderReq = []
|
|
1055
|
-
for i in range(0, len(orders)):
|
|
1056
|
-
rawOrder = orders[i]
|
|
1057
|
-
marketId = self.safe_string(rawOrder, 'symbol')
|
|
1058
|
-
market = self.market(marketId)
|
|
1059
|
-
symbol = market['symbol']
|
|
1060
|
-
type = self.safe_string_upper(rawOrder, 'type')
|
|
1061
|
-
isMarket = (type == 'MARKET')
|
|
1062
|
-
side = self.safe_string_upper(rawOrder, 'side')
|
|
1063
|
-
isBuy = (side == 'BUY')
|
|
1064
|
-
amount = self.safe_string(rawOrder, 'amount')
|
|
1065
|
-
price = self.safe_string(rawOrder, 'price')
|
|
1066
|
-
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1067
|
-
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
|
1068
|
-
slippage = self.safe_string(orderParams, 'slippage', defaultSlippage)
|
|
1069
|
-
defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
|
|
1070
|
-
postOnly = self.safe_bool(orderParams, 'postOnly', False)
|
|
1071
|
-
if postOnly:
|
|
1072
|
-
defaultTimeInForce = 'alo'
|
|
1073
|
-
timeInForce = self.safe_string_lower(orderParams, 'timeInForce', defaultTimeInForce)
|
|
1074
|
-
timeInForce = self.capitalize(timeInForce)
|
|
1075
|
-
triggerPrice = self.safe_string_2(orderParams, 'triggerPrice', 'stopPrice')
|
|
1076
|
-
stopLossPrice = self.safe_string(orderParams, 'stopLossPrice', triggerPrice)
|
|
1077
|
-
takeProfitPrice = self.safe_string(orderParams, 'takeProfitPrice')
|
|
1078
|
-
isTrigger = (stopLossPrice or takeProfitPrice)
|
|
1079
|
-
px = None
|
|
1080
|
-
if isMarket:
|
|
1081
|
-
if price is None:
|
|
1082
|
-
raise ArgumentsRequired(self.id + ' market orders require price to calculate the max slippage price. Default slippage can be set in options(default is 5%).')
|
|
1083
|
-
px = Precise.string_mul(price, Precise.string_add('1', slippage)) if (isBuy) else Precise.string_mul(price, Precise.string_sub('1', slippage))
|
|
1084
|
-
px = self.price_to_precision(symbol, px) # round after adding slippage
|
|
1085
|
-
else:
|
|
1086
|
-
px = self.price_to_precision(symbol, price)
|
|
1087
|
-
sz = self.amount_to_precision(symbol, amount)
|
|
1088
|
-
reduceOnly = self.safe_bool(orderParams, 'reduceOnly', False)
|
|
1089
|
-
orderType: dict = {}
|
|
1090
|
-
if isTrigger:
|
|
1091
|
-
isTp = False
|
|
1092
|
-
if takeProfitPrice is not None:
|
|
1093
|
-
triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
|
|
1094
|
-
isTp = True
|
|
1095
|
-
else:
|
|
1096
|
-
triggerPrice = self.price_to_precision(symbol, stopLossPrice)
|
|
1097
|
-
orderType['trigger'] = {
|
|
1098
|
-
'isMarket': isMarket,
|
|
1099
|
-
'triggerPx': triggerPrice,
|
|
1100
|
-
'tpsl': 'tp' if (isTp) else 'sl',
|
|
1101
|
-
}
|
|
1102
|
-
else:
|
|
1103
|
-
orderType['limit'] = {
|
|
1104
|
-
'tif': timeInForce,
|
|
1105
|
-
}
|
|
1106
|
-
orderParams = self.omit(orderParams, ['clientOrderId', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce', 'client_id', 'reduceOnly', 'postOnly'])
|
|
1107
|
-
orderObj: dict = {
|
|
1108
|
-
'a': self.parse_to_int(market['baseId']),
|
|
1109
|
-
'b': isBuy,
|
|
1110
|
-
'p': px,
|
|
1111
|
-
's': sz,
|
|
1112
|
-
'r': reduceOnly,
|
|
1113
|
-
't': orderType,
|
|
1114
|
-
# 'c': clientOrderId,
|
|
1115
|
-
}
|
|
1116
|
-
if clientOrderId is not None:
|
|
1117
|
-
orderObj['c'] = clientOrderId
|
|
1118
|
-
orderReq.append(self.extend(orderObj, orderParams))
|
|
1119
|
-
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
|
1120
|
-
orderAction: dict = {
|
|
1121
|
-
'type': 'order',
|
|
1122
|
-
'orders': orderReq,
|
|
1123
|
-
'grouping': 'na',
|
|
1124
|
-
# 'brokerCode': 1, # cant
|
|
1125
|
-
}
|
|
1126
|
-
if vaultAddress is None:
|
|
1127
|
-
orderAction['brokerCode'] = 1
|
|
1128
|
-
signature = self.sign_l1_action(orderAction, nonce, vaultAddress)
|
|
1129
|
-
request: dict = {
|
|
1130
|
-
'action': orderAction,
|
|
1131
|
-
'nonce': nonce,
|
|
1132
|
-
'signature': signature,
|
|
1133
|
-
# 'vaultAddress': vaultAddress,
|
|
1134
|
-
}
|
|
1135
|
-
if vaultAddress is not None:
|
|
1136
|
-
params = self.omit(params, 'vaultAddress')
|
|
1137
|
-
request['vaultAddress'] = vaultAddress
|
|
1138
|
-
response = await self.privatePostExchange(self.extend(request, params))
|
|
1462
|
+
await self.handle_builder_fee_approval()
|
|
1463
|
+
request = self.create_orders_request(orders, params)
|
|
1464
|
+
response = await self.privatePostExchange(request)
|
|
1139
1465
|
#
|
|
1140
1466
|
# {
|
|
1141
1467
|
# "status": "ok",
|
|
@@ -1158,36 +1484,235 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1158
1484
|
statuses = self.safe_list(data, 'statuses', [])
|
|
1159
1485
|
return self.parse_orders(statuses, None)
|
|
1160
1486
|
|
|
1487
|
+
def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: str, price: Str = None, params={}):
|
|
1488
|
+
market = self.market(symbol)
|
|
1489
|
+
type = type.upper()
|
|
1490
|
+
side = side.upper()
|
|
1491
|
+
isMarket = (type == 'MARKET')
|
|
1492
|
+
isBuy = (side == 'BUY')
|
|
1493
|
+
clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_id')
|
|
1494
|
+
slippage = self.safe_string(params, 'slippage')
|
|
1495
|
+
defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
|
|
1496
|
+
postOnly = self.safe_bool(params, 'postOnly', False)
|
|
1497
|
+
if postOnly:
|
|
1498
|
+
defaultTimeInForce = 'alo'
|
|
1499
|
+
timeInForce = self.safe_string_lower(params, 'timeInForce', defaultTimeInForce)
|
|
1500
|
+
timeInForce = self.capitalize(timeInForce)
|
|
1501
|
+
triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
|
|
1502
|
+
stopLossPrice = self.safe_string(params, 'stopLossPrice', triggerPrice)
|
|
1503
|
+
takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
|
|
1504
|
+
isTrigger = (stopLossPrice or takeProfitPrice)
|
|
1505
|
+
px = None
|
|
1506
|
+
if isMarket:
|
|
1507
|
+
if price is None:
|
|
1508
|
+
raise ArgumentsRequired(self.id + ' market orders require price to calculate the max slippage price. Default slippage can be set in options(default is 5%).')
|
|
1509
|
+
px = Precise.string_mul(price, Precise.string_add('1', slippage)) if (isBuy) else Precise.string_mul(price, Precise.string_sub('1', slippage))
|
|
1510
|
+
px = self.price_to_precision(symbol, px) # round after adding slippage
|
|
1511
|
+
else:
|
|
1512
|
+
px = self.price_to_precision(symbol, price)
|
|
1513
|
+
sz = self.amount_to_precision(symbol, amount)
|
|
1514
|
+
reduceOnly = self.safe_bool(params, 'reduceOnly', False)
|
|
1515
|
+
orderType: dict = {}
|
|
1516
|
+
if isTrigger:
|
|
1517
|
+
isTp = False
|
|
1518
|
+
if takeProfitPrice is not None:
|
|
1519
|
+
triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
|
|
1520
|
+
isTp = True
|
|
1521
|
+
else:
|
|
1522
|
+
triggerPrice = self.price_to_precision(symbol, stopLossPrice)
|
|
1523
|
+
orderType['trigger'] = {
|
|
1524
|
+
'isMarket': isMarket,
|
|
1525
|
+
'triggerPx': triggerPrice,
|
|
1526
|
+
'tpsl': 'tp' if (isTp) else 'sl',
|
|
1527
|
+
}
|
|
1528
|
+
else:
|
|
1529
|
+
orderType['limit'] = {
|
|
1530
|
+
'tif': timeInForce,
|
|
1531
|
+
}
|
|
1532
|
+
params = self.omit(params, ['clientOrderId', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce', 'client_id', 'reduceOnly', 'postOnly'])
|
|
1533
|
+
orderObj: dict = {
|
|
1534
|
+
'a': self.parse_to_int(market['baseId']),
|
|
1535
|
+
'b': isBuy,
|
|
1536
|
+
'p': px,
|
|
1537
|
+
's': sz,
|
|
1538
|
+
'r': reduceOnly,
|
|
1539
|
+
't': orderType,
|
|
1540
|
+
# 'c': clientOrderId,
|
|
1541
|
+
}
|
|
1542
|
+
if clientOrderId is not None:
|
|
1543
|
+
orderObj['c'] = clientOrderId
|
|
1544
|
+
return orderObj
|
|
1545
|
+
|
|
1546
|
+
def create_orders_request(self, orders, params={}) -> dict:
|
|
1547
|
+
"""
|
|
1548
|
+
create a list of trade orders
|
|
1549
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
|
1550
|
+
: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
|
|
1551
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1552
|
+
"""
|
|
1553
|
+
self.check_required_credentials()
|
|
1554
|
+
defaultSlippage = self.safe_string(self.options, 'defaultSlippage')
|
|
1555
|
+
defaultSlippage = self.safe_string(params, 'slippage', defaultSlippage)
|
|
1556
|
+
hasClientOrderId = False
|
|
1557
|
+
for i in range(0, len(orders)):
|
|
1558
|
+
rawOrder = orders[i]
|
|
1559
|
+
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1560
|
+
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
|
1561
|
+
if clientOrderId is not None:
|
|
1562
|
+
hasClientOrderId = True
|
|
1563
|
+
if hasClientOrderId:
|
|
1564
|
+
for i in range(0, len(orders)):
|
|
1565
|
+
rawOrder = orders[i]
|
|
1566
|
+
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1567
|
+
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
|
1568
|
+
if clientOrderId is None:
|
|
1569
|
+
raise ArgumentsRequired(self.id + ' createOrders() all orders must have clientOrderId if at least one has a clientOrderId')
|
|
1570
|
+
params = self.omit(params, ['slippage', 'clientOrderId', 'client_id', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce'])
|
|
1571
|
+
nonce = self.milliseconds()
|
|
1572
|
+
orderReq = []
|
|
1573
|
+
grouping = 'na'
|
|
1574
|
+
for i in range(0, len(orders)):
|
|
1575
|
+
rawOrder = orders[i]
|
|
1576
|
+
marketId = self.safe_string(rawOrder, 'symbol')
|
|
1577
|
+
market = self.market(marketId)
|
|
1578
|
+
symbol = market['symbol']
|
|
1579
|
+
type = self.safe_string_upper(rawOrder, 'type')
|
|
1580
|
+
side = self.safe_string_upper(rawOrder, 'side')
|
|
1581
|
+
amount = self.safe_string(rawOrder, 'amount')
|
|
1582
|
+
price = self.safe_string(rawOrder, 'price')
|
|
1583
|
+
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1584
|
+
slippage = self.safe_string(orderParams, 'slippage', defaultSlippage)
|
|
1585
|
+
orderParams['slippage'] = slippage
|
|
1586
|
+
stopLoss = self.safe_value(orderParams, 'stopLoss')
|
|
1587
|
+
takeProfit = self.safe_value(orderParams, 'takeProfit')
|
|
1588
|
+
isTrigger = (stopLoss or takeProfit)
|
|
1589
|
+
orderParams = self.omit(orderParams, ['stopLoss', 'takeProfit'])
|
|
1590
|
+
mainOrderObj: dict = self.create_order_request(symbol, type, side, amount, price, orderParams)
|
|
1591
|
+
orderReq.append(mainOrderObj)
|
|
1592
|
+
if isTrigger:
|
|
1593
|
+
# grouping opposed orders for sl/tp
|
|
1594
|
+
stopLossOrderTriggerPrice = self.safe_string_n(stopLoss, ['triggerPrice', 'stopPrice'])
|
|
1595
|
+
stopLossOrderType = self.safe_string(stopLoss, 'type')
|
|
1596
|
+
stopLossOrderLimitPrice = self.safe_string_n(stopLoss, ['price', 'stopLossPrice'], stopLossOrderTriggerPrice)
|
|
1597
|
+
takeProfitOrderTriggerPrice = self.safe_string_n(takeProfit, ['triggerPrice', 'stopPrice'])
|
|
1598
|
+
takeProfitOrderType = self.safe_string(takeProfit, 'type')
|
|
1599
|
+
takeProfitOrderLimitPrice = self.safe_string_n(takeProfit, ['price', 'takeProfitPrice'], takeProfitOrderTriggerPrice)
|
|
1600
|
+
grouping = 'normalTpsl'
|
|
1601
|
+
orderParams = self.omit(orderParams, ['stopLoss', 'takeProfit'])
|
|
1602
|
+
triggerOrderSide = ''
|
|
1603
|
+
if side == 'BUY':
|
|
1604
|
+
triggerOrderSide = 'sell'
|
|
1605
|
+
else:
|
|
1606
|
+
triggerOrderSide = 'buy'
|
|
1607
|
+
if takeProfit is not None:
|
|
1608
|
+
orderObj: dict = self.create_order_request(symbol, takeProfitOrderType, triggerOrderSide, amount, takeProfitOrderLimitPrice, self.extend(orderParams, {
|
|
1609
|
+
'takeProfitPrice': takeProfitOrderTriggerPrice,
|
|
1610
|
+
'reduceOnly': True,
|
|
1611
|
+
}))
|
|
1612
|
+
orderReq.append(orderObj)
|
|
1613
|
+
if stopLoss is not None:
|
|
1614
|
+
orderObj: dict = self.create_order_request(symbol, stopLossOrderType, triggerOrderSide, amount, stopLossOrderLimitPrice, self.extend(orderParams, {
|
|
1615
|
+
'stopLossPrice': stopLossOrderTriggerPrice,
|
|
1616
|
+
'reduceOnly': True,
|
|
1617
|
+
}))
|
|
1618
|
+
orderReq.append(orderObj)
|
|
1619
|
+
vaultAddress = None
|
|
1620
|
+
vaultAddress, params = self.handle_option_and_params(params, 'createOrder', 'vaultAddress')
|
|
1621
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
1622
|
+
orderAction: dict = {
|
|
1623
|
+
'type': 'order',
|
|
1624
|
+
'orders': orderReq,
|
|
1625
|
+
'grouping': grouping,
|
|
1626
|
+
}
|
|
1627
|
+
if self.safe_bool(self.options, 'approvedBuilderFee', False):
|
|
1628
|
+
wallet = self.safe_string_lower(self.options, 'builder', '0x6530512A6c89C7cfCEbC3BA7fcD9aDa5f30827a6')
|
|
1629
|
+
orderAction['builder'] = {'b': wallet, 'f': self.safe_integer(self.options, 'feeInt', 10)}
|
|
1630
|
+
signature = self.sign_l1_action(orderAction, nonce, vaultAddress)
|
|
1631
|
+
request: dict = {
|
|
1632
|
+
'action': orderAction,
|
|
1633
|
+
'nonce': nonce,
|
|
1634
|
+
'signature': signature,
|
|
1635
|
+
# 'vaultAddress': vaultAddress,
|
|
1636
|
+
}
|
|
1637
|
+
if vaultAddress is not None:
|
|
1638
|
+
params = self.omit(params, 'vaultAddress')
|
|
1639
|
+
request['vaultAddress'] = vaultAddress
|
|
1640
|
+
return request
|
|
1641
|
+
|
|
1161
1642
|
async def cancel_order(self, id: str, symbol: Str = None, params={}):
|
|
1162
1643
|
"""
|
|
1163
1644
|
cancels an open order
|
|
1164
|
-
|
|
1165
|
-
|
|
1645
|
+
|
|
1646
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
|
1647
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
|
1648
|
+
|
|
1166
1649
|
:param str id: order id
|
|
1167
1650
|
:param str symbol: unified symbol of the market the order was made in
|
|
1168
1651
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1169
1652
|
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1170
1653
|
:param str [params.vaultAddress]: the vault address for order
|
|
1654
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1171
1655
|
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1172
1656
|
"""
|
|
1173
|
-
|
|
1657
|
+
orders = await self.cancel_orders([id], symbol, params)
|
|
1658
|
+
return self.safe_dict(orders, 0)
|
|
1174
1659
|
|
|
1175
1660
|
async def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
|
|
1176
1661
|
"""
|
|
1177
1662
|
cancel multiple orders
|
|
1178
|
-
|
|
1179
|
-
|
|
1663
|
+
|
|
1664
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
|
1665
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
|
1666
|
+
|
|
1180
1667
|
:param str[] ids: order ids
|
|
1181
1668
|
:param str [symbol]: unified market symbol
|
|
1182
1669
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1183
1670
|
:param string|str[] [params.clientOrderId]: client order ids,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1184
1671
|
:param str [params.vaultAddress]: the vault address
|
|
1672
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1185
1673
|
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1186
1674
|
"""
|
|
1187
1675
|
self.check_required_credentials()
|
|
1188
1676
|
if symbol is None:
|
|
1189
1677
|
raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
|
|
1190
1678
|
await self.load_markets()
|
|
1679
|
+
request = self.cancel_orders_request(ids, symbol, params)
|
|
1680
|
+
response = await self.privatePostExchange(request)
|
|
1681
|
+
#
|
|
1682
|
+
# {
|
|
1683
|
+
# "status":"ok",
|
|
1684
|
+
# "response":{
|
|
1685
|
+
# "type":"cancel",
|
|
1686
|
+
# "data":{
|
|
1687
|
+
# "statuses":[
|
|
1688
|
+
# "success"
|
|
1689
|
+
# ]
|
|
1690
|
+
# }
|
|
1691
|
+
# }
|
|
1692
|
+
# }
|
|
1693
|
+
#
|
|
1694
|
+
innerResponse = self.safe_dict(response, 'response')
|
|
1695
|
+
data = self.safe_dict(innerResponse, 'data')
|
|
1696
|
+
statuses = self.safe_list(data, 'statuses')
|
|
1697
|
+
orders = []
|
|
1698
|
+
for i in range(0, len(statuses)):
|
|
1699
|
+
status = statuses[i]
|
|
1700
|
+
orders.append(self.safe_order({
|
|
1701
|
+
'info': status,
|
|
1702
|
+
'status': status,
|
|
1703
|
+
}))
|
|
1704
|
+
return orders
|
|
1705
|
+
|
|
1706
|
+
def cancel_orders_request(self, ids: List[str], symbol: Str = None, params={}) -> dict:
|
|
1707
|
+
"""
|
|
1708
|
+
build the request payload for cancelling multiple orders
|
|
1709
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
|
1710
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
|
1711
|
+
:param str[] ids: order ids
|
|
1712
|
+
:param str symbol: unified market symbol
|
|
1713
|
+
:param dict [params]:
|
|
1714
|
+
:returns dict: the raw request object to be sent to the exchange
|
|
1715
|
+
"""
|
|
1191
1716
|
market = self.market(symbol)
|
|
1192
1717
|
clientOrderId = self.safe_value_2(params, 'clientOrderId', 'client_id')
|
|
1193
1718
|
params = self.omit(params, ['clientOrderId', 'client_id'])
|
|
@@ -1219,37 +1744,28 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1219
1744
|
'o': self.parse_to_numeric(ids[i]),
|
|
1220
1745
|
})
|
|
1221
1746
|
cancelAction['cancels'] = cancelReq
|
|
1222
|
-
vaultAddress =
|
|
1747
|
+
vaultAddress = None
|
|
1748
|
+
vaultAddress, params = self.handle_option_and_params_2(params, 'cancelOrders', 'vaultAddress', 'subAccountAddress')
|
|
1749
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
1223
1750
|
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
|
1224
1751
|
request['action'] = cancelAction
|
|
1225
1752
|
request['signature'] = signature
|
|
1226
1753
|
if vaultAddress is not None:
|
|
1227
1754
|
params = self.omit(params, 'vaultAddress')
|
|
1228
1755
|
request['vaultAddress'] = vaultAddress
|
|
1229
|
-
|
|
1230
|
-
#
|
|
1231
|
-
# {
|
|
1232
|
-
# "status":"ok",
|
|
1233
|
-
# "response":{
|
|
1234
|
-
# "type":"cancel",
|
|
1235
|
-
# "data":{
|
|
1236
|
-
# "statuses":[
|
|
1237
|
-
# "success"
|
|
1238
|
-
# ]
|
|
1239
|
-
# }
|
|
1240
|
-
# }
|
|
1241
|
-
# }
|
|
1242
|
-
#
|
|
1243
|
-
return response
|
|
1756
|
+
return request
|
|
1244
1757
|
|
|
1245
1758
|
async def cancel_orders_for_symbols(self, orders: List[CancellationRequest], params={}):
|
|
1246
1759
|
"""
|
|
1247
1760
|
cancel multiple orders for multiple symbols
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1761
|
+
|
|
1762
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
|
1763
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
|
1764
|
+
|
|
1765
|
+
: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"}]
|
|
1251
1766
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1252
1767
|
:param str [params.vaultAddress]: the vault address
|
|
1768
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1253
1769
|
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1254
1770
|
"""
|
|
1255
1771
|
self.check_required_credentials()
|
|
@@ -1285,14 +1801,16 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1285
1801
|
cancelReq.append(cancelObj)
|
|
1286
1802
|
cancelAction['type'] = 'cancelByCloid' if cancelByCloid else 'cancel'
|
|
1287
1803
|
cancelAction['cancels'] = cancelReq
|
|
1288
|
-
vaultAddress =
|
|
1804
|
+
vaultAddress = None
|
|
1805
|
+
vaultAddress, params = self.handle_option_and_params_2(params, 'cancelOrdersForSymbols', 'vaultAddress', 'subAccountAddress')
|
|
1806
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
1289
1807
|
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
|
1290
1808
|
request['action'] = cancelAction
|
|
1291
1809
|
request['signature'] = signature
|
|
1292
1810
|
if vaultAddress is not None:
|
|
1293
1811
|
params = self.omit(params, 'vaultAddress')
|
|
1294
1812
|
request['vaultAddress'] = vaultAddress
|
|
1295
|
-
response = await self.privatePostExchange(
|
|
1813
|
+
response = await self.privatePostExchange(request)
|
|
1296
1814
|
#
|
|
1297
1815
|
# {
|
|
1298
1816
|
# "status":"ok",
|
|
@@ -1306,7 +1824,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1306
1824
|
# }
|
|
1307
1825
|
# }
|
|
1308
1826
|
#
|
|
1309
|
-
return response
|
|
1827
|
+
return [self.safe_order({'info': response})]
|
|
1310
1828
|
|
|
1311
1829
|
async def cancel_all_orders_after(self, timeout: Int, params={}):
|
|
1312
1830
|
"""
|
|
@@ -1314,6 +1832,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1314
1832
|
:param number timeout: time in milliseconds, 0 represents cancel the timer
|
|
1315
1833
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1316
1834
|
:param str [params.vaultAddress]: the vault address
|
|
1835
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1317
1836
|
:returns dict: the api result
|
|
1318
1837
|
"""
|
|
1319
1838
|
self.check_required_credentials()
|
|
@@ -1328,14 +1847,16 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1328
1847
|
'type': 'scheduleCancel',
|
|
1329
1848
|
'time': nonce + timeout,
|
|
1330
1849
|
}
|
|
1331
|
-
vaultAddress =
|
|
1850
|
+
vaultAddress = None
|
|
1851
|
+
vaultAddress, params = self.handle_option_and_params_2(params, 'cancelAllOrdersAfter', 'vaultAddress', 'subAccountAddress')
|
|
1852
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
1332
1853
|
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
|
1333
1854
|
request['action'] = cancelAction
|
|
1334
1855
|
request['signature'] = signature
|
|
1335
1856
|
if vaultAddress is not None:
|
|
1336
1857
|
params = self.omit(params, 'vaultAddress')
|
|
1337
1858
|
request['vaultAddress'] = vaultAddress
|
|
1338
|
-
response = await self.privatePostExchange(
|
|
1859
|
+
response = await self.privatePostExchange(request)
|
|
1339
1860
|
#
|
|
1340
1861
|
# {
|
|
1341
1862
|
# "status":"err",
|
|
@@ -1344,96 +1865,102 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1344
1865
|
#
|
|
1345
1866
|
return response
|
|
1346
1867
|
|
|
1347
|
-
|
|
1348
|
-
"""
|
|
1349
|
-
edit a trade order
|
|
1350
|
-
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-an-order
|
|
1351
|
-
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
|
|
1352
|
-
:param str id: cancel order id
|
|
1353
|
-
:param str symbol: unified symbol of the market to create an order in
|
|
1354
|
-
:param str type: 'market' or 'limit'
|
|
1355
|
-
:param str side: 'buy' or 'sell'
|
|
1356
|
-
:param float amount: how much of currency you want to trade in units of base currency
|
|
1357
|
-
:param float [price]: the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
|
|
1358
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1359
|
-
:param str [params.timeInForce]: 'Gtc', 'Ioc', 'Alo'
|
|
1360
|
-
:param bool [params.postOnly]: True or False whether the order is post-only
|
|
1361
|
-
:param bool [params.reduceOnly]: True or False whether the order is reduce-only
|
|
1362
|
-
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
|
1363
|
-
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1364
|
-
:param str [params.vaultAddress]: the vault address for order
|
|
1365
|
-
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1366
|
-
"""
|
|
1868
|
+
def edit_orders_request(self, orders, params={}):
|
|
1367
1869
|
self.check_required_credentials()
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1870
|
+
hasClientOrderId = False
|
|
1871
|
+
for i in range(0, len(orders)):
|
|
1872
|
+
rawOrder = orders[i]
|
|
1873
|
+
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1874
|
+
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
|
1875
|
+
if clientOrderId is not None:
|
|
1876
|
+
hasClientOrderId = True
|
|
1877
|
+
if hasClientOrderId:
|
|
1878
|
+
for i in range(0, len(orders)):
|
|
1879
|
+
rawOrder = orders[i]
|
|
1880
|
+
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1881
|
+
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
|
1882
|
+
if clientOrderId is None:
|
|
1883
|
+
raise ArgumentsRequired(self.id + ' editOrders() all orders must have clientOrderId if at least one has a clientOrderId')
|
|
1884
|
+
params = self.omit(params, ['slippage', 'clientOrderId', 'client_id', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce'])
|
|
1885
|
+
modifies = []
|
|
1886
|
+
for i in range(0, len(orders)):
|
|
1887
|
+
rawOrder = orders[i]
|
|
1888
|
+
id = self.safe_string(rawOrder, 'id')
|
|
1889
|
+
marketId = self.safe_string(rawOrder, 'symbol')
|
|
1890
|
+
market = self.market(marketId)
|
|
1891
|
+
symbol = market['symbol']
|
|
1892
|
+
type = self.safe_string_upper(rawOrder, 'type')
|
|
1893
|
+
isMarket = (type == 'MARKET')
|
|
1894
|
+
side = self.safe_string_upper(rawOrder, 'side')
|
|
1895
|
+
isBuy = (side == 'BUY')
|
|
1896
|
+
amount = self.safe_string(rawOrder, 'amount')
|
|
1897
|
+
price = self.safe_string(rawOrder, 'price')
|
|
1898
|
+
orderParams = self.safe_dict(rawOrder, 'params', {})
|
|
1899
|
+
defaultSlippage = self.safe_string(self.options, 'defaultSlippage')
|
|
1900
|
+
slippage = self.safe_string(orderParams, 'slippage', defaultSlippage)
|
|
1901
|
+
defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
|
|
1902
|
+
postOnly = self.safe_bool(orderParams, 'postOnly', False)
|
|
1903
|
+
if postOnly:
|
|
1904
|
+
defaultTimeInForce = 'alo'
|
|
1905
|
+
timeInForce = self.safe_string_lower(orderParams, 'timeInForce', defaultTimeInForce)
|
|
1906
|
+
timeInForce = self.capitalize(timeInForce)
|
|
1907
|
+
clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
|
|
1908
|
+
triggerPrice = self.safe_string_2(orderParams, 'triggerPrice', 'stopPrice')
|
|
1909
|
+
stopLossPrice = self.safe_string(orderParams, 'stopLossPrice', triggerPrice)
|
|
1910
|
+
takeProfitPrice = self.safe_string(orderParams, 'takeProfitPrice')
|
|
1911
|
+
isTrigger = (stopLossPrice or takeProfitPrice)
|
|
1912
|
+
reduceOnly = self.safe_bool(orderParams, 'reduceOnly', False)
|
|
1913
|
+
orderParams = self.omit(orderParams, ['slippage', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'clientOrderId', 'client_id', 'postOnly', 'reduceOnly'])
|
|
1914
|
+
px = self.number_to_string(price)
|
|
1915
|
+
if isMarket:
|
|
1916
|
+
px = Precise.string_mul(px, Precise.string_add('1', slippage)) if (isBuy) else Precise.string_mul(px, Precise.string_sub('1', slippage))
|
|
1917
|
+
px = self.price_to_precision(symbol, px)
|
|
1403
1918
|
else:
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1919
|
+
px = self.price_to_precision(symbol, px)
|
|
1920
|
+
sz = self.amount_to_precision(symbol, amount)
|
|
1921
|
+
orderType: dict = {}
|
|
1922
|
+
if isTrigger:
|
|
1923
|
+
isTp = False
|
|
1924
|
+
if takeProfitPrice is not None:
|
|
1925
|
+
triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
|
|
1926
|
+
isTp = True
|
|
1927
|
+
else:
|
|
1928
|
+
triggerPrice = self.price_to_precision(symbol, stopLossPrice)
|
|
1929
|
+
orderType['trigger'] = {
|
|
1930
|
+
'isMarket': isMarket,
|
|
1931
|
+
'triggerPx': triggerPrice,
|
|
1932
|
+
'tpsl': 'tp' if (isTp) else 'sl',
|
|
1933
|
+
}
|
|
1934
|
+
else:
|
|
1935
|
+
orderType['limit'] = {
|
|
1936
|
+
'tif': timeInForce,
|
|
1937
|
+
}
|
|
1938
|
+
if triggerPrice is None:
|
|
1939
|
+
triggerPrice = '0'
|
|
1940
|
+
orderReq: dict = {
|
|
1941
|
+
'a': self.parse_to_int(market['baseId']),
|
|
1942
|
+
'b': isBuy,
|
|
1943
|
+
'p': px,
|
|
1944
|
+
's': sz,
|
|
1945
|
+
'r': reduceOnly,
|
|
1946
|
+
't': orderType,
|
|
1947
|
+
# 'c': clientOrderId,
|
|
1409
1948
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1949
|
+
if clientOrderId is not None:
|
|
1950
|
+
orderReq['c'] = clientOrderId
|
|
1951
|
+
modifyReq: dict = {
|
|
1952
|
+
'oid': self.parse_to_int(id),
|
|
1953
|
+
'order': orderReq,
|
|
1413
1954
|
}
|
|
1414
|
-
|
|
1415
|
-
triggerPrice = '0'
|
|
1955
|
+
modifies.append(modifyReq)
|
|
1416
1956
|
nonce = self.milliseconds()
|
|
1417
|
-
orderReq: dict = {
|
|
1418
|
-
'a': self.parse_to_int(market['baseId']),
|
|
1419
|
-
'b': isBuy,
|
|
1420
|
-
'p': px,
|
|
1421
|
-
's': sz,
|
|
1422
|
-
'r': reduceOnly,
|
|
1423
|
-
't': orderType,
|
|
1424
|
-
# 'c': clientOrderId,
|
|
1425
|
-
}
|
|
1426
|
-
if clientOrderId is not None:
|
|
1427
|
-
orderReq['c'] = clientOrderId
|
|
1428
|
-
modifyReq: dict = {
|
|
1429
|
-
'oid': self.parse_to_int(id),
|
|
1430
|
-
'order': orderReq,
|
|
1431
|
-
}
|
|
1432
1957
|
modifyAction: dict = {
|
|
1433
1958
|
'type': 'batchModify',
|
|
1434
|
-
'modifies':
|
|
1959
|
+
'modifies': modifies,
|
|
1435
1960
|
}
|
|
1436
|
-
vaultAddress =
|
|
1961
|
+
vaultAddress = None
|
|
1962
|
+
vaultAddress, params = self.handle_option_and_params(params, 'editOrder', 'vaultAddress')
|
|
1963
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
1437
1964
|
signature = self.sign_l1_action(modifyAction, nonce, vaultAddress)
|
|
1438
1965
|
request: dict = {
|
|
1439
1966
|
'action': modifyAction,
|
|
@@ -1442,9 +1969,51 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1442
1969
|
# 'vaultAddress': vaultAddress,
|
|
1443
1970
|
}
|
|
1444
1971
|
if vaultAddress is not None:
|
|
1445
|
-
params = self.omit(params, 'vaultAddress')
|
|
1446
1972
|
request['vaultAddress'] = vaultAddress
|
|
1447
|
-
|
|
1973
|
+
return request
|
|
1974
|
+
|
|
1975
|
+
async def edit_order(self, id: str, symbol: str, type: str, side: str, amount: Num = None, price: Num = None, params={}):
|
|
1976
|
+
"""
|
|
1977
|
+
edit a trade order
|
|
1978
|
+
|
|
1979
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
|
|
1980
|
+
|
|
1981
|
+
:param str id: cancel order id
|
|
1982
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1983
|
+
:param str type: 'market' or 'limit'
|
|
1984
|
+
:param str side: 'buy' or 'sell'
|
|
1985
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
|
1986
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
|
1987
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1988
|
+
:param str [params.timeInForce]: 'Gtc', 'Ioc', 'Alo'
|
|
1989
|
+
:param bool [params.postOnly]: True or False whether the order is post-only
|
|
1990
|
+
:param bool [params.reduceOnly]: True or False whether the order is reduce-only
|
|
1991
|
+
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
|
1992
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1993
|
+
:param str [params.vaultAddress]: the vault address for order
|
|
1994
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1995
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1996
|
+
"""
|
|
1997
|
+
await self.load_markets()
|
|
1998
|
+
if id is None:
|
|
1999
|
+
raise ArgumentsRequired(self.id + ' editOrder() requires an id argument')
|
|
2000
|
+
order, globalParams = self.parse_create_edit_order_args(id, symbol, type, side, amount, price, params)
|
|
2001
|
+
orders = await self.edit_orders([order], globalParams)
|
|
2002
|
+
return orders[0]
|
|
2003
|
+
|
|
2004
|
+
async def edit_orders(self, orders: List[OrderRequest], params={}):
|
|
2005
|
+
"""
|
|
2006
|
+
edit a list of trade orders
|
|
2007
|
+
|
|
2008
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
|
|
2009
|
+
|
|
2010
|
+
: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
|
|
2011
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2012
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2013
|
+
"""
|
|
2014
|
+
await self.load_markets()
|
|
2015
|
+
request = self.edit_orders_request(orders, params)
|
|
2016
|
+
response = await self.privatePostExchange(request)
|
|
1448
2017
|
#
|
|
1449
2018
|
# {
|
|
1450
2019
|
# "status": "ok",
|
|
@@ -1483,13 +2052,52 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1483
2052
|
responseObject = self.safe_dict(response, 'response', {})
|
|
1484
2053
|
dataObject = self.safe_dict(responseObject, 'data', {})
|
|
1485
2054
|
statuses = self.safe_list(dataObject, 'statuses', [])
|
|
1486
|
-
|
|
1487
|
-
|
|
2055
|
+
return self.parse_orders(statuses)
|
|
2056
|
+
|
|
2057
|
+
async def create_vault(self, name: str, description: str, initialUsd: int, params={}):
|
|
2058
|
+
"""
|
|
2059
|
+
creates a value
|
|
2060
|
+
:param str name: The name of the vault
|
|
2061
|
+
:param str description: The description of the vault
|
|
2062
|
+
:param number initialUsd: The initialUsd of the vault
|
|
2063
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2064
|
+
:returns dict: the api result
|
|
2065
|
+
"""
|
|
2066
|
+
self.check_required_credentials()
|
|
2067
|
+
await self.load_markets()
|
|
2068
|
+
nonce = self.milliseconds()
|
|
2069
|
+
request: dict = {
|
|
2070
|
+
'nonce': nonce,
|
|
2071
|
+
}
|
|
2072
|
+
usd = self.parse_to_int(Precise.string_mul(self.number_to_string(initialUsd), '1000000'))
|
|
2073
|
+
action: dict = {
|
|
2074
|
+
'type': 'createVault',
|
|
2075
|
+
'name': name,
|
|
2076
|
+
'description': description,
|
|
2077
|
+
'initialUsd': usd,
|
|
2078
|
+
'nonce': nonce,
|
|
2079
|
+
}
|
|
2080
|
+
signature = self.sign_l1_action(action, nonce)
|
|
2081
|
+
request['action'] = action
|
|
2082
|
+
request['signature'] = signature
|
|
2083
|
+
response = await self.privatePostExchange(self.extend(request, params))
|
|
2084
|
+
#
|
|
2085
|
+
# {
|
|
2086
|
+
# "status": "ok",
|
|
2087
|
+
# "response": {
|
|
2088
|
+
# "type": "createVault",
|
|
2089
|
+
# "data": "0x04fddcbc9ce80219301bd16f18491bedf2a8c2b8"
|
|
2090
|
+
# }
|
|
2091
|
+
# }
|
|
2092
|
+
#
|
|
2093
|
+
return response
|
|
1488
2094
|
|
|
1489
2095
|
async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1490
2096
|
"""
|
|
1491
2097
|
fetches historical funding rate prices
|
|
1492
|
-
|
|
2098
|
+
|
|
2099
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-historical-funding-rates
|
|
2100
|
+
|
|
1493
2101
|
:param str symbol: unified symbol of the market to fetch the funding rate history for
|
|
1494
2102
|
:param int [since]: timestamp in ms of the earliest funding rate to fetch
|
|
1495
2103
|
:param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
|
|
@@ -1498,15 +2106,18 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1498
2106
|
:returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
|
|
1499
2107
|
"""
|
|
1500
2108
|
await self.load_markets()
|
|
2109
|
+
if symbol is None:
|
|
2110
|
+
raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
|
|
1501
2111
|
market = self.market(symbol)
|
|
1502
2112
|
request: dict = {
|
|
1503
2113
|
'type': 'fundingHistory',
|
|
1504
|
-
'coin': market['
|
|
2114
|
+
'coin': market['baseName'],
|
|
1505
2115
|
}
|
|
1506
2116
|
if since is not None:
|
|
1507
2117
|
request['startTime'] = since
|
|
1508
2118
|
else:
|
|
1509
|
-
|
|
2119
|
+
maxLimit = 500 if (limit is None) else limit
|
|
2120
|
+
request['startTime'] = self.milliseconds() - maxLimit * 60 * 60 * 1000
|
|
1510
2121
|
until = self.safe_integer(params, 'until')
|
|
1511
2122
|
params = self.omit(params, 'until')
|
|
1512
2123
|
if until is not None:
|
|
@@ -1539,13 +2150,16 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1539
2150
|
async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1540
2151
|
"""
|
|
1541
2152
|
fetch all unfilled currently open orders
|
|
1542
|
-
|
|
2153
|
+
|
|
2154
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-open-orders
|
|
2155
|
+
|
|
1543
2156
|
:param str symbol: unified market symbol
|
|
1544
2157
|
:param int [since]: the earliest time in ms to fetch open orders for
|
|
1545
2158
|
:param int [limit]: the maximum number of open orders structures to retrieve
|
|
1546
2159
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1547
2160
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
1548
2161
|
:param str [params.method]: 'openOrders' or 'frontendOpenOrders' default is 'frontendOpenOrders'
|
|
2162
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1549
2163
|
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1550
2164
|
"""
|
|
1551
2165
|
userAddress = None
|
|
@@ -1572,7 +2186,14 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1572
2186
|
# }
|
|
1573
2187
|
# ]
|
|
1574
2188
|
#
|
|
1575
|
-
|
|
2189
|
+
orderWithStatus = []
|
|
2190
|
+
for i in range(0, len(response)):
|
|
2191
|
+
order = response[i]
|
|
2192
|
+
extendOrder = {}
|
|
2193
|
+
if self.safe_string(order, 'status') is None:
|
|
2194
|
+
extendOrder['ccxtStatus'] = 'open'
|
|
2195
|
+
orderWithStatus.append(self.extend(order, extendOrder))
|
|
2196
|
+
return self.parse_orders(orderWithStatus, market, since, limit)
|
|
1576
2197
|
|
|
1577
2198
|
async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1578
2199
|
"""
|
|
@@ -1584,8 +2205,54 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1584
2205
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
1585
2206
|
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1586
2207
|
"""
|
|
2208
|
+
await self.load_markets()
|
|
2209
|
+
orders = await self.fetch_orders(symbol, None, None, params) # don't filter here because we don't want to catch open orders
|
|
2210
|
+
closedOrders = self.filter_by_array(orders, 'status', ['closed'], False)
|
|
2211
|
+
return self.filter_by_symbol_since_limit(closedOrders, symbol, since, limit)
|
|
2212
|
+
|
|
2213
|
+
async def fetch_canceled_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
2214
|
+
"""
|
|
2215
|
+
fetch all canceled orders
|
|
2216
|
+
:param str symbol: unified market symbol
|
|
2217
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
|
2218
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
|
2219
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2220
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
2221
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2222
|
+
"""
|
|
2223
|
+
await self.load_markets()
|
|
2224
|
+
orders = await self.fetch_orders(symbol, None, None, params) # don't filter here because we don't want to catch open orders
|
|
2225
|
+
closedOrders = self.filter_by_array(orders, 'status', ['canceled'], False)
|
|
2226
|
+
return self.filter_by_symbol_since_limit(closedOrders, symbol, since, limit)
|
|
2227
|
+
|
|
2228
|
+
async def fetch_canceled_and_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
2229
|
+
"""
|
|
2230
|
+
fetch all closed and canceled orders
|
|
2231
|
+
:param str symbol: unified market symbol
|
|
2232
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
|
2233
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
|
2234
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2235
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
2236
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2237
|
+
"""
|
|
2238
|
+
await self.load_markets()
|
|
2239
|
+
orders = await self.fetch_orders(symbol, None, None, params) # don't filter here because we don't want to catch open orders
|
|
2240
|
+
closedOrders = self.filter_by_array(orders, 'status', ['canceled', 'closed', 'rejected'], False)
|
|
2241
|
+
return self.filter_by_symbol_since_limit(closedOrders, symbol, since, limit)
|
|
2242
|
+
|
|
2243
|
+
async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
2244
|
+
"""
|
|
2245
|
+
fetch all orders
|
|
2246
|
+
:param str symbol: unified market symbol
|
|
2247
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
|
2248
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
|
2249
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2250
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
2251
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
2252
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2253
|
+
"""
|
|
1587
2254
|
userAddress = None
|
|
1588
|
-
userAddress, params = self.handle_public_address('
|
|
2255
|
+
userAddress, params = self.handle_public_address('fetchOrders', params)
|
|
1589
2256
|
await self.load_markets()
|
|
1590
2257
|
market = self.safe_market(symbol)
|
|
1591
2258
|
request: dict = {
|
|
@@ -1611,21 +2278,33 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1611
2278
|
async def fetch_order(self, id: str, symbol: Str = None, params={}):
|
|
1612
2279
|
"""
|
|
1613
2280
|
fetches information on an order made by the user
|
|
1614
|
-
|
|
2281
|
+
|
|
2282
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-order-status-by-oid-or-cloid
|
|
2283
|
+
|
|
2284
|
+
:param str id: order id
|
|
1615
2285
|
:param str symbol: unified symbol of the market the order was made in
|
|
1616
2286
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2287
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1617
2288
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
2289
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1618
2290
|
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1619
2291
|
"""
|
|
1620
2292
|
userAddress = None
|
|
1621
2293
|
userAddress, params = self.handle_public_address('fetchOrder', params)
|
|
1622
2294
|
await self.load_markets()
|
|
1623
2295
|
market = self.safe_market(symbol)
|
|
2296
|
+
clientOrderId = self.safe_string(params, 'clientOrderId')
|
|
1624
2297
|
request: dict = {
|
|
1625
2298
|
'type': 'orderStatus',
|
|
1626
|
-
'oid': self.parse_to_numeric(id),
|
|
2299
|
+
# 'oid': id if isClientOrderId else self.parse_to_numeric(id),
|
|
1627
2300
|
'user': userAddress,
|
|
1628
2301
|
}
|
|
2302
|
+
if clientOrderId is not None:
|
|
2303
|
+
params = self.omit(params, 'clientOrderId')
|
|
2304
|
+
request['oid'] = clientOrderId
|
|
2305
|
+
else:
|
|
2306
|
+
isClientOrderId = len(id) >= 34
|
|
2307
|
+
request['oid'] = id if isClientOrderId else self.parse_to_numeric(id)
|
|
1629
2308
|
response = await self.publicPostInfo(self.extend(request, params))
|
|
1630
2309
|
#
|
|
1631
2310
|
# {
|
|
@@ -1658,6 +2337,10 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1658
2337
|
return self.parse_order(data, market)
|
|
1659
2338
|
|
|
1660
2339
|
def parse_order(self, order: dict, market: Market = None) -> Order:
|
|
2340
|
+
#
|
|
2341
|
+
# createOrdersWs error
|
|
2342
|
+
#
|
|
2343
|
+
# {error: 'Insufficient margin to place order. asset=159'}
|
|
1661
2344
|
#
|
|
1662
2345
|
# fetchOpenOrders
|
|
1663
2346
|
#
|
|
@@ -1749,26 +2432,36 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1749
2432
|
# "triggerPx": "0.6"
|
|
1750
2433
|
# }
|
|
1751
2434
|
#
|
|
2435
|
+
error = self.safe_string(order, 'error')
|
|
2436
|
+
if error is not None:
|
|
2437
|
+
return self.safe_order({
|
|
2438
|
+
'info': order,
|
|
2439
|
+
'status': 'rejected',
|
|
2440
|
+
})
|
|
1752
2441
|
entry = self.safe_dict_n(order, ['order', 'resting', 'filled'])
|
|
1753
2442
|
if entry is None:
|
|
1754
2443
|
entry = order
|
|
1755
2444
|
coin = self.safe_string(entry, 'coin')
|
|
1756
2445
|
marketId = None
|
|
1757
2446
|
if coin is not None:
|
|
1758
|
-
|
|
1759
|
-
marketId = coin
|
|
1760
|
-
else:
|
|
1761
|
-
marketId = coin + '/USDC:USDC'
|
|
2447
|
+
marketId = self.coin_to_market_id(coin)
|
|
1762
2448
|
if self.safe_string(entry, 'id') is None:
|
|
1763
2449
|
market = self.safe_market(marketId, None)
|
|
1764
2450
|
else:
|
|
1765
2451
|
market = self.safe_market(marketId, market)
|
|
1766
2452
|
symbol = market['symbol']
|
|
1767
|
-
timestamp = self.
|
|
1768
|
-
status = self.
|
|
2453
|
+
timestamp = self.safe_integer(entry, 'timestamp')
|
|
2454
|
+
status = self.safe_string_2(order, 'status', 'ccxtStatus')
|
|
2455
|
+
order = self.omit(order, ['ccxtStatus'])
|
|
1769
2456
|
side = self.safe_string(entry, 'side')
|
|
1770
2457
|
if side is not None:
|
|
1771
2458
|
side = 'sell' if (side == 'A') else 'buy'
|
|
2459
|
+
totalAmount = self.safe_string_2(entry, 'origSz', 'totalSz')
|
|
2460
|
+
remaining = self.safe_string(entry, 'sz')
|
|
2461
|
+
tif = self.safe_string_upper(entry, 'tif')
|
|
2462
|
+
postOnly = None
|
|
2463
|
+
if tif is not None:
|
|
2464
|
+
postOnly = (tif == 'ALO')
|
|
1772
2465
|
return self.safe_order({
|
|
1773
2466
|
'info': order,
|
|
1774
2467
|
'id': self.safe_string(entry, 'oid'),
|
|
@@ -1776,30 +2469,40 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1776
2469
|
'timestamp': timestamp,
|
|
1777
2470
|
'datetime': self.iso8601(timestamp),
|
|
1778
2471
|
'lastTradeTimestamp': None,
|
|
1779
|
-
'lastUpdateTimestamp':
|
|
2472
|
+
'lastUpdateTimestamp': self.safe_integer(order, 'statusTimestamp'),
|
|
1780
2473
|
'symbol': symbol,
|
|
1781
2474
|
'type': self.parse_order_type(self.safe_string_lower(entry, 'orderType')),
|
|
1782
|
-
'timeInForce':
|
|
1783
|
-
'postOnly':
|
|
2475
|
+
'timeInForce': tif,
|
|
2476
|
+
'postOnly': postOnly,
|
|
1784
2477
|
'reduceOnly': self.safe_bool(entry, 'reduceOnly'),
|
|
1785
2478
|
'side': side,
|
|
1786
|
-
'price': self.
|
|
2479
|
+
'price': self.safe_string(entry, 'limitPx'),
|
|
1787
2480
|
'triggerPrice': self.safe_number(entry, 'triggerPx') if self.safe_bool(entry, 'isTrigger') else None,
|
|
1788
|
-
'amount':
|
|
2481
|
+
'amount': totalAmount,
|
|
1789
2482
|
'cost': None,
|
|
1790
|
-
'average': self.
|
|
1791
|
-
'filled':
|
|
1792
|
-
'remaining':
|
|
2483
|
+
'average': self.safe_string(entry, 'avgPx'),
|
|
2484
|
+
'filled': Precise.string_sub(totalAmount, remaining),
|
|
2485
|
+
'remaining': remaining,
|
|
1793
2486
|
'status': self.parse_order_status(status),
|
|
1794
2487
|
'fee': None,
|
|
1795
2488
|
'trades': None,
|
|
1796
2489
|
}, market)
|
|
1797
2490
|
|
|
1798
2491
|
def parse_order_status(self, status: Str):
|
|
2492
|
+
if status is None:
|
|
2493
|
+
return None
|
|
1799
2494
|
statuses: dict = {
|
|
1800
2495
|
'triggered': 'open',
|
|
1801
2496
|
'filled': 'closed',
|
|
2497
|
+
'open': 'open',
|
|
2498
|
+
'canceled': 'canceled',
|
|
2499
|
+
'rejected': 'rejected',
|
|
2500
|
+
'marginCanceled': 'canceled',
|
|
1802
2501
|
}
|
|
2502
|
+
if status.endswith('Rejected'):
|
|
2503
|
+
return 'rejected'
|
|
2504
|
+
if status.endswith('Canceled'):
|
|
2505
|
+
return 'canceled'
|
|
1803
2506
|
return self.safe_string(statuses, status, status)
|
|
1804
2507
|
|
|
1805
2508
|
def parse_order_type(self, status):
|
|
@@ -1812,13 +2515,16 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1812
2515
|
async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1813
2516
|
"""
|
|
1814
2517
|
fetch all trades made by the user
|
|
1815
|
-
|
|
1816
|
-
|
|
2518
|
+
|
|
2519
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills
|
|
2520
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills-by-time
|
|
2521
|
+
|
|
1817
2522
|
:param str symbol: unified market symbol
|
|
1818
2523
|
:param int [since]: the earliest time in ms to fetch trades for
|
|
1819
2524
|
:param int [limit]: the maximum number of trades structures to retrieve
|
|
1820
2525
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1821
2526
|
:param int [params.until]: timestamp in ms of the latest trade
|
|
2527
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1822
2528
|
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
1823
2529
|
"""
|
|
1824
2530
|
userAddress = None
|
|
@@ -1846,6 +2552,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1846
2552
|
# "crossed": True,
|
|
1847
2553
|
# "dir": "Close Long",
|
|
1848
2554
|
# "fee": "0.050062",
|
|
2555
|
+
# "feeToken": "USDC",
|
|
1849
2556
|
# "hash": "0x09d77c96791e98b5775a04092584ab010d009445119c71e4005c0d634ea322bc",
|
|
1850
2557
|
# "liquidationMarkPx": null,
|
|
1851
2558
|
# "oid": 3929354691,
|
|
@@ -1883,7 +2590,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1883
2590
|
price = self.safe_string(trade, 'px')
|
|
1884
2591
|
amount = self.safe_string(trade, 'sz')
|
|
1885
2592
|
coin = self.safe_string(trade, 'coin')
|
|
1886
|
-
marketId = coin
|
|
2593
|
+
marketId = self.coin_to_market_id(coin)
|
|
1887
2594
|
market = self.safe_market(marketId, None)
|
|
1888
2595
|
symbol = market['symbol']
|
|
1889
2596
|
id = self.safe_string(trade, 'tid')
|
|
@@ -1891,6 +2598,10 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1891
2598
|
if side is not None:
|
|
1892
2599
|
side = 'sell' if (side == 'A') else 'buy'
|
|
1893
2600
|
fee = self.safe_string(trade, 'fee')
|
|
2601
|
+
takerOrMaker = None
|
|
2602
|
+
crossed = self.safe_bool(trade, 'crossed')
|
|
2603
|
+
if crossed is not None:
|
|
2604
|
+
takerOrMaker = 'taker' if crossed else 'maker'
|
|
1894
2605
|
return self.safe_trade({
|
|
1895
2606
|
'info': trade,
|
|
1896
2607
|
'timestamp': timestamp,
|
|
@@ -1900,17 +2611,23 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1900
2611
|
'order': self.safe_string(trade, 'oid'),
|
|
1901
2612
|
'type': None,
|
|
1902
2613
|
'side': side,
|
|
1903
|
-
'takerOrMaker':
|
|
2614
|
+
'takerOrMaker': takerOrMaker,
|
|
1904
2615
|
'price': price,
|
|
1905
2616
|
'amount': amount,
|
|
1906
2617
|
'cost': None,
|
|
1907
|
-
'fee': {
|
|
2618
|
+
'fee': {
|
|
2619
|
+
'cost': fee,
|
|
2620
|
+
'currency': self.safe_string(trade, 'feeToken'),
|
|
2621
|
+
'rate': None,
|
|
2622
|
+
},
|
|
1908
2623
|
}, market)
|
|
1909
2624
|
|
|
1910
2625
|
async def fetch_position(self, symbol: str, params={}):
|
|
1911
2626
|
"""
|
|
1912
2627
|
fetch data on an open position
|
|
1913
|
-
|
|
2628
|
+
|
|
2629
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-users-perpetuals-account-summary
|
|
2630
|
+
|
|
1914
2631
|
:param str symbol: unified market symbol of the market the position is held in
|
|
1915
2632
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1916
2633
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
@@ -1919,13 +2636,16 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
1919
2636
|
positions = await self.fetch_positions([symbol], params)
|
|
1920
2637
|
return self.safe_dict(positions, 0, {})
|
|
1921
2638
|
|
|
1922
|
-
async def fetch_positions(self, symbols: Strings = None, params={}):
|
|
2639
|
+
async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
|
|
1923
2640
|
"""
|
|
1924
2641
|
fetch all open positions
|
|
1925
|
-
|
|
2642
|
+
|
|
2643
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals#retrieve-users-perpetuals-account-summary
|
|
2644
|
+
|
|
1926
2645
|
:param str[] [symbols]: list of unified market symbols
|
|
1927
2646
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1928
2647
|
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
2648
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
1929
2649
|
:returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
|
1930
2650
|
"""
|
|
1931
2651
|
await self.load_markets()
|
|
@@ -2017,18 +2737,22 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2017
2737
|
#
|
|
2018
2738
|
entry = self.safe_dict(position, 'position', {})
|
|
2019
2739
|
coin = self.safe_string(entry, 'coin')
|
|
2020
|
-
marketId = coin
|
|
2740
|
+
marketId = self.coin_to_market_id(coin)
|
|
2021
2741
|
market = self.safe_market(marketId, None)
|
|
2022
2742
|
symbol = market['symbol']
|
|
2023
2743
|
leverage = self.safe_dict(entry, 'leverage', {})
|
|
2024
|
-
|
|
2025
|
-
|
|
2744
|
+
marginMode = self.safe_string(leverage, 'type')
|
|
2745
|
+
isIsolated = (marginMode == 'isolated')
|
|
2746
|
+
rawSize = self.safe_string(entry, 'szi')
|
|
2747
|
+
size = rawSize
|
|
2026
2748
|
side = None
|
|
2027
|
-
if
|
|
2028
|
-
side = '
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2749
|
+
if size is not None:
|
|
2750
|
+
side = 'long' if Precise.string_gt(rawSize, '0') else 'short'
|
|
2751
|
+
size = Precise.string_abs(size)
|
|
2752
|
+
rawUnrealizedPnl = self.safe_string(entry, 'unrealizedPnl')
|
|
2753
|
+
absRawUnrealizedPnl = Precise.string_abs(rawUnrealizedPnl)
|
|
2754
|
+
initialMargin = self.safe_string(entry, 'marginUsed')
|
|
2755
|
+
percentage = Precise.string_mul(Precise.string_div(absRawUnrealizedPnl, initialMargin), '100')
|
|
2032
2756
|
return self.safe_position({
|
|
2033
2757
|
'info': position,
|
|
2034
2758
|
'id': None,
|
|
@@ -2038,21 +2762,21 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2038
2762
|
'isolated': isIsolated,
|
|
2039
2763
|
'hedged': None,
|
|
2040
2764
|
'side': side,
|
|
2041
|
-
'contracts': self.
|
|
2765
|
+
'contracts': self.parse_number(size),
|
|
2042
2766
|
'contractSize': None,
|
|
2043
2767
|
'entryPrice': self.safe_number(entry, 'entryPx'),
|
|
2044
2768
|
'markPrice': None,
|
|
2045
2769
|
'notional': self.safe_number(entry, 'positionValue'),
|
|
2046
2770
|
'leverage': self.safe_number(leverage, 'value'),
|
|
2047
|
-
'collateral':
|
|
2048
|
-
'initialMargin': initialMargin,
|
|
2771
|
+
'collateral': self.safe_number(entry, 'marginUsed'),
|
|
2772
|
+
'initialMargin': self.parse_number(initialMargin),
|
|
2049
2773
|
'maintenanceMargin': None,
|
|
2050
2774
|
'initialMarginPercentage': None,
|
|
2051
2775
|
'maintenanceMarginPercentage': None,
|
|
2052
|
-
'unrealizedPnl':
|
|
2776
|
+
'unrealizedPnl': self.parse_number(rawUnrealizedPnl),
|
|
2053
2777
|
'liquidationPrice': self.safe_number(entry, 'liquidationPx'),
|
|
2054
|
-
'marginMode':
|
|
2055
|
-
'percentage': percentage,
|
|
2778
|
+
'marginMode': marginMode,
|
|
2779
|
+
'percentage': self.parse_number(percentage),
|
|
2056
2780
|
})
|
|
2057
2781
|
|
|
2058
2782
|
async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
|
|
@@ -2062,6 +2786,8 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2062
2786
|
:param str symbol: unified market symbol of the market the position is held in, default is None
|
|
2063
2787
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2064
2788
|
:param str [params.leverage]: the rate of leverage, is required if setting trade mode(symbol)
|
|
2789
|
+
:param str [params.vaultAddress]: the vault address
|
|
2790
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
2065
2791
|
:returns dict: response from the exchange
|
|
2066
2792
|
"""
|
|
2067
2793
|
if symbol is None:
|
|
@@ -2081,15 +2807,14 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2081
2807
|
'isCross': isCross,
|
|
2082
2808
|
'leverage': leverage,
|
|
2083
2809
|
}
|
|
2084
|
-
vaultAddress =
|
|
2810
|
+
vaultAddress = None
|
|
2811
|
+
vaultAddress, params = self.handle_option_and_params_2(params, 'setMarginMode', 'vaultAddress', 'subAccountAddress')
|
|
2085
2812
|
if vaultAddress is not None:
|
|
2086
|
-
params = self.omit(params, 'vaultAddress')
|
|
2087
2813
|
if vaultAddress.startswith('0x'):
|
|
2088
2814
|
vaultAddress = vaultAddress.replace('0x', '')
|
|
2089
|
-
|
|
2090
|
-
signature = self.sign_l1_action(extendedAction, nonce, vaultAddress)
|
|
2815
|
+
signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
|
|
2091
2816
|
request: dict = {
|
|
2092
|
-
'action':
|
|
2817
|
+
'action': updateAction,
|
|
2093
2818
|
'nonce': nonce,
|
|
2094
2819
|
'signature': signature,
|
|
2095
2820
|
# 'vaultAddress': vaultAddress,
|
|
@@ -2107,7 +2832,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2107
2832
|
#
|
|
2108
2833
|
return response
|
|
2109
2834
|
|
|
2110
|
-
async def set_leverage(self, leverage:
|
|
2835
|
+
async def set_leverage(self, leverage: int, symbol: Str = None, params={}):
|
|
2111
2836
|
"""
|
|
2112
2837
|
set the level of leverage for a market
|
|
2113
2838
|
:param float leverage: the rate of leverage
|
|
@@ -2131,7 +2856,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2131
2856
|
'isCross': isCross,
|
|
2132
2857
|
'leverage': leverage,
|
|
2133
2858
|
}
|
|
2134
|
-
vaultAddress =
|
|
2859
|
+
vaultAddress = None
|
|
2860
|
+
vaultAddress, params = self.handle_option_and_params_2(params, 'setLeverage', 'vaultAddress', 'subAccountAddress')
|
|
2861
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
2135
2862
|
signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
|
|
2136
2863
|
request: dict = {
|
|
2137
2864
|
'action': updateAction,
|
|
@@ -2142,7 +2869,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2142
2869
|
if vaultAddress is not None:
|
|
2143
2870
|
params = self.omit(params, 'vaultAddress')
|
|
2144
2871
|
request['vaultAddress'] = vaultAddress
|
|
2145
|
-
response = await self.privatePostExchange(
|
|
2872
|
+
response = await self.privatePostExchange(request)
|
|
2146
2873
|
#
|
|
2147
2874
|
# {
|
|
2148
2875
|
# 'response': {
|
|
@@ -2156,21 +2883,29 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2156
2883
|
async def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
|
|
2157
2884
|
"""
|
|
2158
2885
|
add margin
|
|
2159
|
-
|
|
2886
|
+
|
|
2887
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
|
|
2888
|
+
|
|
2160
2889
|
:param str symbol: unified market symbol
|
|
2161
2890
|
:param float amount: amount of margin to add
|
|
2162
2891
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2892
|
+
:param str [params.vaultAddress]: the vault address
|
|
2893
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
2163
2894
|
:returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
|
|
2164
2895
|
"""
|
|
2165
2896
|
return await self.modify_margin_helper(symbol, amount, 'add', params)
|
|
2166
2897
|
|
|
2167
2898
|
async def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
|
|
2168
2899
|
"""
|
|
2169
|
-
|
|
2900
|
+
|
|
2901
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
|
|
2902
|
+
|
|
2170
2903
|
remove margin from a position
|
|
2171
2904
|
:param str symbol: unified market symbol
|
|
2172
2905
|
:param float amount: the amount of margin to remove
|
|
2173
2906
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2907
|
+
:param str [params.vaultAddress]: the vault address
|
|
2908
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
2174
2909
|
:returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
|
|
2175
2910
|
"""
|
|
2176
2911
|
return await self.modify_margin_helper(symbol, amount, 'reduce', params)
|
|
@@ -2189,7 +2924,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2189
2924
|
'isBuy': True,
|
|
2190
2925
|
'ntli': sz,
|
|
2191
2926
|
}
|
|
2192
|
-
vaultAddress =
|
|
2927
|
+
vaultAddress = None
|
|
2928
|
+
vaultAddress, params = self.handle_option_and_params_2(params, 'modifyMargin', 'vaultAddress', 'subAccountAddress')
|
|
2929
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
2193
2930
|
signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
|
|
2194
2931
|
request: dict = {
|
|
2195
2932
|
'action': updateAction,
|
|
@@ -2198,9 +2935,8 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2198
2935
|
# 'vaultAddress': vaultAddress,
|
|
2199
2936
|
}
|
|
2200
2937
|
if vaultAddress is not None:
|
|
2201
|
-
params = self.omit(params, 'vaultAddress')
|
|
2202
2938
|
request['vaultAddress'] = vaultAddress
|
|
2203
|
-
response = await self.privatePostExchange(
|
|
2939
|
+
response = await self.privatePostExchange(request)
|
|
2204
2940
|
#
|
|
2205
2941
|
# {
|
|
2206
2942
|
# 'response': {
|
|
@@ -2235,7 +2971,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2235
2971
|
async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
|
2236
2972
|
"""
|
|
2237
2973
|
transfer currency internally between wallets on the same account
|
|
2238
|
-
|
|
2974
|
+
|
|
2975
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#l1-usdc-transfer
|
|
2976
|
+
|
|
2239
2977
|
:param str code: unified currency code
|
|
2240
2978
|
:param float amount: amount to transfer
|
|
2241
2979
|
:param str fromAccount: account to transfer from *spot, swap*
|
|
@@ -2251,64 +2989,115 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2251
2989
|
if self.in_array(fromAccount, ['spot', 'swap', 'perp']):
|
|
2252
2990
|
# handle swap <> spot account transfer
|
|
2253
2991
|
if not self.in_array(toAccount, ['spot', 'swap', 'perp']):
|
|
2254
|
-
raise NotSupported(self.id + 'transfer() only support spot <> swap transfer')
|
|
2255
|
-
|
|
2256
|
-
|
|
2992
|
+
raise NotSupported(self.id + ' transfer() only support spot <> swap transfer')
|
|
2993
|
+
strAmount = self.number_to_string(amount)
|
|
2994
|
+
vaultAddress = self.safe_string_2(params, 'vaultAddress', 'subAccountAddress')
|
|
2995
|
+
if vaultAddress is not None:
|
|
2996
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
2997
|
+
strAmount = strAmount + ' subaccount:' + vaultAddress
|
|
2257
2998
|
toPerp = (toAccount == 'perp') or (toAccount == 'swap')
|
|
2258
|
-
|
|
2259
|
-
'
|
|
2260
|
-
'
|
|
2261
|
-
|
|
2999
|
+
transferPayload: dict = {
|
|
3000
|
+
'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
|
|
3001
|
+
'amount': strAmount,
|
|
3002
|
+
'toPerp': toPerp,
|
|
3003
|
+
'nonce': nonce,
|
|
3004
|
+
}
|
|
3005
|
+
transferSig = self.build_usd_class_send_sig(transferPayload)
|
|
3006
|
+
transferRequest: dict = {
|
|
3007
|
+
'action': {
|
|
3008
|
+
'hyperliquidChain': transferPayload['hyperliquidChain'],
|
|
3009
|
+
'signatureChainId': '0x66eee',
|
|
3010
|
+
'type': 'usdClassTransfer',
|
|
3011
|
+
'amount': strAmount,
|
|
2262
3012
|
'toPerp': toPerp,
|
|
3013
|
+
'nonce': nonce,
|
|
2263
3014
|
},
|
|
2264
|
-
}
|
|
2265
|
-
signature = self.sign_l1_action(action, nonce, vaultAddress)
|
|
2266
|
-
innerRequest: dict = {
|
|
2267
|
-
'action': self.extend(action, params),
|
|
2268
3015
|
'nonce': nonce,
|
|
2269
|
-
'signature':
|
|
3016
|
+
'signature': transferSig,
|
|
2270
3017
|
}
|
|
2271
3018
|
if vaultAddress is not None:
|
|
2272
|
-
|
|
2273
|
-
transferResponse = await self.privatePostExchange(
|
|
3019
|
+
transferRequest['vaultAddress'] = vaultAddress
|
|
3020
|
+
transferResponse = await self.privatePostExchange(transferRequest)
|
|
2274
3021
|
return transferResponse
|
|
2275
|
-
#
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
'
|
|
2291
|
-
'
|
|
2292
|
-
'
|
|
2293
|
-
'
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
3022
|
+
# transfer between main account and subaccount
|
|
3023
|
+
isDeposit = False
|
|
3024
|
+
subAccountAddress = None
|
|
3025
|
+
if fromAccount == 'main':
|
|
3026
|
+
subAccountAddress = toAccount
|
|
3027
|
+
isDeposit = True
|
|
3028
|
+
elif toAccount == 'main':
|
|
3029
|
+
subAccountAddress = fromAccount
|
|
3030
|
+
else:
|
|
3031
|
+
raise NotSupported(self.id + ' transfer() only support main <> subaccount transfer')
|
|
3032
|
+
self.check_address(subAccountAddress)
|
|
3033
|
+
if code is None or code.upper() == 'USDC':
|
|
3034
|
+
# Transfer USDC with subAccountTransfer
|
|
3035
|
+
usd = self.parse_to_int(Precise.string_mul(self.number_to_string(amount), '1000000'))
|
|
3036
|
+
action = {
|
|
3037
|
+
'type': 'subAccountTransfer',
|
|
3038
|
+
'subAccountUser': subAccountAddress,
|
|
3039
|
+
'isDeposit': isDeposit,
|
|
3040
|
+
'usd': usd,
|
|
3041
|
+
}
|
|
3042
|
+
sig = self.sign_l1_action(action, nonce)
|
|
3043
|
+
request: dict = {
|
|
3044
|
+
'action': action,
|
|
3045
|
+
'nonce': nonce,
|
|
3046
|
+
'signature': sig,
|
|
3047
|
+
}
|
|
3048
|
+
response = await self.privatePostExchange(request)
|
|
3049
|
+
#
|
|
3050
|
+
# {'response': {'type': 'default'}, 'status': 'ok'}
|
|
3051
|
+
#
|
|
3052
|
+
return self.parse_transfer(response)
|
|
3053
|
+
else:
|
|
3054
|
+
# Transfer non-USDC with subAccountSpotTransfer
|
|
3055
|
+
symbol = self.symbol(code)
|
|
3056
|
+
action = {
|
|
3057
|
+
'type': 'subAccountSpotTransfer',
|
|
3058
|
+
'subAccountUser': subAccountAddress,
|
|
3059
|
+
'isDeposit': isDeposit,
|
|
3060
|
+
'token': symbol,
|
|
3061
|
+
'amount': self.number_to_string(amount),
|
|
3062
|
+
}
|
|
3063
|
+
sig = self.sign_l1_action(action, nonce)
|
|
3064
|
+
request: dict = {
|
|
3065
|
+
'action': action,
|
|
3066
|
+
'nonce': nonce,
|
|
3067
|
+
'signature': sig,
|
|
3068
|
+
}
|
|
3069
|
+
response = await self.privatePostExchange(request)
|
|
3070
|
+
return self.parse_transfer(response)
|
|
3071
|
+
|
|
3072
|
+
def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
|
|
3073
|
+
#
|
|
3074
|
+
# {'response': {'type': 'default'}, 'status': 'ok'}
|
|
3075
|
+
#
|
|
3076
|
+
return {
|
|
3077
|
+
'info': transfer,
|
|
3078
|
+
'id': None,
|
|
3079
|
+
'timestamp': None,
|
|
3080
|
+
'datetime': None,
|
|
3081
|
+
'currency': None,
|
|
3082
|
+
'amount': None,
|
|
3083
|
+
'fromAccount': None,
|
|
3084
|
+
'toAccount': None,
|
|
3085
|
+
'status': 'ok',
|
|
2299
3086
|
}
|
|
2300
|
-
response = await self.privatePostExchange(self.extend(request, params))
|
|
2301
|
-
return response
|
|
2302
3087
|
|
|
2303
|
-
async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
|
|
3088
|
+
async def withdraw(self, code: str, amount: float, address: str, tag: Str = None, params={}) -> Transaction:
|
|
2304
3089
|
"""
|
|
2305
3090
|
make a withdrawal(only support USDC)
|
|
2306
|
-
|
|
3091
|
+
|
|
3092
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#initiate-a-withdrawal-request
|
|
3093
|
+
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#deposit-or-withdraw-from-a-vault
|
|
3094
|
+
|
|
2307
3095
|
:param str code: unified currency code
|
|
2308
3096
|
:param float amount: the amount to withdraw
|
|
2309
3097
|
:param str address: the address to withdraw to
|
|
2310
3098
|
:param str tag:
|
|
2311
3099
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
3100
|
+
:param str [params.vaultAddress]: vault address withdraw from
|
|
2312
3101
|
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2313
3102
|
"""
|
|
2314
3103
|
self.check_required_credentials()
|
|
@@ -2317,57 +3106,541 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2317
3106
|
if code is not None:
|
|
2318
3107
|
code = code.upper()
|
|
2319
3108
|
if code != 'USDC':
|
|
2320
|
-
raise NotSupported(self.id + 'withdraw() only support USDC')
|
|
2321
|
-
|
|
3109
|
+
raise NotSupported(self.id + ' withdraw() only support USDC')
|
|
3110
|
+
vaultAddress = None
|
|
3111
|
+
vaultAddress, params = self.handle_option_and_params(params, 'withdraw', 'vaultAddress')
|
|
3112
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
3113
|
+
params = self.omit(params, 'vaultAddress')
|
|
2322
3114
|
nonce = self.milliseconds()
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
3115
|
+
action: dict = {}
|
|
3116
|
+
sig = None
|
|
3117
|
+
if vaultAddress is not None:
|
|
3118
|
+
action = {
|
|
3119
|
+
'type': 'vaultTransfer',
|
|
3120
|
+
'vaultAddress': '0x' + vaultAddress,
|
|
3121
|
+
'isDeposit': False,
|
|
3122
|
+
'usd': amount,
|
|
3123
|
+
}
|
|
3124
|
+
sig = self.sign_l1_action(action, nonce)
|
|
3125
|
+
else:
|
|
3126
|
+
isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
|
|
3127
|
+
payload: dict = {
|
|
3128
|
+
'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
|
|
3129
|
+
'destination': address,
|
|
3130
|
+
'amount': str(amount),
|
|
3131
|
+
'time': nonce,
|
|
3132
|
+
}
|
|
3133
|
+
sig = self.build_withdraw_sig(payload)
|
|
3134
|
+
action = {
|
|
2332
3135
|
'hyperliquidChain': payload['hyperliquidChain'],
|
|
2333
3136
|
'signatureChainId': '0x66eee', # check self out
|
|
2334
3137
|
'destination': address,
|
|
2335
3138
|
'amount': str(amount),
|
|
2336
3139
|
'time': nonce,
|
|
2337
3140
|
'type': 'withdraw3',
|
|
2338
|
-
}
|
|
3141
|
+
}
|
|
3142
|
+
request: dict = {
|
|
3143
|
+
'action': action,
|
|
2339
3144
|
'nonce': nonce,
|
|
2340
3145
|
'signature': sig,
|
|
2341
3146
|
}
|
|
2342
|
-
response = await self.privatePostExchange(
|
|
3147
|
+
response = await self.privatePostExchange(request)
|
|
2343
3148
|
return self.parse_transaction(response)
|
|
2344
3149
|
|
|
2345
3150
|
def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
|
|
2346
3151
|
#
|
|
2347
3152
|
# {status: 'ok', response: {type: 'default'}}
|
|
2348
3153
|
#
|
|
3154
|
+
# fetchDeposits / fetchWithdrawals
|
|
3155
|
+
# {
|
|
3156
|
+
# "time":1724762307531,
|
|
3157
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
|
3158
|
+
# "delta":{
|
|
3159
|
+
# "type":"accountClassTransfer",
|
|
3160
|
+
# "usdc":"50.0",
|
|
3161
|
+
# "toPerp":false
|
|
3162
|
+
# }
|
|
3163
|
+
# }
|
|
3164
|
+
#
|
|
3165
|
+
timestamp = self.safe_integer(transaction, 'time')
|
|
3166
|
+
delta = self.safe_dict(transaction, 'delta', {})
|
|
3167
|
+
fee = None
|
|
3168
|
+
feeCost = self.safe_integer(delta, 'fee')
|
|
3169
|
+
if feeCost is not None:
|
|
3170
|
+
fee = {
|
|
3171
|
+
'currency': 'USDC',
|
|
3172
|
+
'cost': feeCost,
|
|
3173
|
+
}
|
|
3174
|
+
internal = None
|
|
3175
|
+
type = self.safe_string(delta, 'type')
|
|
3176
|
+
if type is not None:
|
|
3177
|
+
internal = (type == 'internalTransfer')
|
|
2349
3178
|
return {
|
|
2350
3179
|
'info': transaction,
|
|
2351
3180
|
'id': None,
|
|
2352
|
-
'txid':
|
|
2353
|
-
'timestamp':
|
|
2354
|
-
'datetime':
|
|
3181
|
+
'txid': self.safe_string(transaction, 'hash'),
|
|
3182
|
+
'timestamp': timestamp,
|
|
3183
|
+
'datetime': self.iso8601(timestamp),
|
|
2355
3184
|
'network': None,
|
|
2356
3185
|
'address': None,
|
|
2357
|
-
'addressTo':
|
|
2358
|
-
'addressFrom':
|
|
3186
|
+
'addressTo': self.safe_string(delta, 'destination'),
|
|
3187
|
+
'addressFrom': self.safe_string(delta, 'user'),
|
|
2359
3188
|
'tag': None,
|
|
2360
3189
|
'tagTo': None,
|
|
2361
3190
|
'tagFrom': None,
|
|
2362
3191
|
'type': None,
|
|
2363
|
-
'amount':
|
|
3192
|
+
'amount': self.safe_number(delta, 'usdc'),
|
|
2364
3193
|
'currency': None,
|
|
2365
3194
|
'status': self.safe_string(transaction, 'status'),
|
|
2366
3195
|
'updated': None,
|
|
2367
3196
|
'comment': None,
|
|
2368
|
-
'internal':
|
|
2369
|
-
'fee':
|
|
3197
|
+
'internal': internal,
|
|
3198
|
+
'fee': fee,
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
|
|
3202
|
+
"""
|
|
3203
|
+
fetch the trading fees for a market
|
|
3204
|
+
:param str symbol: unified market symbol
|
|
3205
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
3206
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
3207
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
3208
|
+
:returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
|
|
3209
|
+
"""
|
|
3210
|
+
await self.load_markets()
|
|
3211
|
+
userAddress = None
|
|
3212
|
+
userAddress, params = self.handle_public_address('fetchTradingFee', params)
|
|
3213
|
+
market = self.market(symbol)
|
|
3214
|
+
request: dict = {
|
|
3215
|
+
'type': 'userFees',
|
|
3216
|
+
'user': userAddress,
|
|
3217
|
+
}
|
|
3218
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
|
3219
|
+
#
|
|
3220
|
+
# {
|
|
3221
|
+
# "dailyUserVlm": [
|
|
3222
|
+
# {
|
|
3223
|
+
# "date": "2024-07-08",
|
|
3224
|
+
# "userCross": "0.0",
|
|
3225
|
+
# "userAdd": "0.0",
|
|
3226
|
+
# "exchange": "90597185.23639999"
|
|
3227
|
+
# }
|
|
3228
|
+
# ],
|
|
3229
|
+
# "feeSchedule": {
|
|
3230
|
+
# "cross": "0.00035",
|
|
3231
|
+
# "add": "0.0001",
|
|
3232
|
+
# "tiers": {
|
|
3233
|
+
# "vip": [
|
|
3234
|
+
# {
|
|
3235
|
+
# "ntlCutoff": "5000000.0",
|
|
3236
|
+
# "cross": "0.0003",
|
|
3237
|
+
# "add": "0.00005"
|
|
3238
|
+
# }
|
|
3239
|
+
# ],
|
|
3240
|
+
# "mm": [
|
|
3241
|
+
# {
|
|
3242
|
+
# "makerFractionCutoff": "0.005",
|
|
3243
|
+
# "add": "-0.00001"
|
|
3244
|
+
# }
|
|
3245
|
+
# ]
|
|
3246
|
+
# },
|
|
3247
|
+
# "referralDiscount": "0.04"
|
|
3248
|
+
# },
|
|
3249
|
+
# "userCrossRate": "0.00035",
|
|
3250
|
+
# "userAddRate": "0.0001",
|
|
3251
|
+
# "activeReferralDiscount": "0.0"
|
|
3252
|
+
# }
|
|
3253
|
+
#
|
|
3254
|
+
data: dict = {
|
|
3255
|
+
'userCrossRate': self.safe_string(response, 'userCrossRate'),
|
|
3256
|
+
'userAddRate': self.safe_string(response, 'userAddRate'),
|
|
3257
|
+
}
|
|
3258
|
+
return self.parse_trading_fee(data, market)
|
|
3259
|
+
|
|
3260
|
+
def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
|
|
3261
|
+
#
|
|
3262
|
+
# {
|
|
3263
|
+
# "dailyUserVlm": [
|
|
3264
|
+
# {
|
|
3265
|
+
# "date": "2024-07-08",
|
|
3266
|
+
# "userCross": "0.0",
|
|
3267
|
+
# "userAdd": "0.0",
|
|
3268
|
+
# "exchange": "90597185.23639999"
|
|
3269
|
+
# }
|
|
3270
|
+
# ],
|
|
3271
|
+
# "feeSchedule": {
|
|
3272
|
+
# "cross": "0.00035",
|
|
3273
|
+
# "add": "0.0001",
|
|
3274
|
+
# "tiers": {
|
|
3275
|
+
# "vip": [
|
|
3276
|
+
# {
|
|
3277
|
+
# "ntlCutoff": "5000000.0",
|
|
3278
|
+
# "cross": "0.0003",
|
|
3279
|
+
# "add": "0.00005"
|
|
3280
|
+
# }
|
|
3281
|
+
# ],
|
|
3282
|
+
# "mm": [
|
|
3283
|
+
# {
|
|
3284
|
+
# "makerFractionCutoff": "0.005",
|
|
3285
|
+
# "add": "-0.00001"
|
|
3286
|
+
# }
|
|
3287
|
+
# ]
|
|
3288
|
+
# },
|
|
3289
|
+
# "referralDiscount": "0.04"
|
|
3290
|
+
# },
|
|
3291
|
+
# "userCrossRate": "0.00035",
|
|
3292
|
+
# "userAddRate": "0.0001",
|
|
3293
|
+
# "activeReferralDiscount": "0.0"
|
|
3294
|
+
# }
|
|
3295
|
+
#
|
|
3296
|
+
symbol = self.safe_symbol(None, market)
|
|
3297
|
+
return {
|
|
3298
|
+
'info': fee,
|
|
3299
|
+
'symbol': symbol,
|
|
3300
|
+
'maker': self.safe_number(fee, 'userAddRate'),
|
|
3301
|
+
'taker': self.safe_number(fee, 'userCrossRate'),
|
|
3302
|
+
'percentage': None,
|
|
3303
|
+
'tierBased': None,
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3306
|
+
async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
|
|
3307
|
+
"""
|
|
3308
|
+
fetch the history of changes, actions done by the user or operations that altered the balance of the user
|
|
3309
|
+
:param str [code]: unified currency code
|
|
3310
|
+
:param int [since]: timestamp in ms of the earliest ledger entry
|
|
3311
|
+
:param int [limit]: max number of ledger entries to return
|
|
3312
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
3313
|
+
:param int [params.until]: timestamp in ms of the latest ledger entry
|
|
3314
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
3315
|
+
:returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
|
|
3316
|
+
"""
|
|
3317
|
+
await self.load_markets()
|
|
3318
|
+
userAddress = None
|
|
3319
|
+
userAddress, params = self.handle_public_address('fetchLedger', params)
|
|
3320
|
+
request: dict = {
|
|
3321
|
+
'type': 'userNonFundingLedgerUpdates',
|
|
3322
|
+
'user': userAddress,
|
|
3323
|
+
}
|
|
3324
|
+
if since is not None:
|
|
3325
|
+
request['startTime'] = since
|
|
3326
|
+
until = self.safe_integer(params, 'until')
|
|
3327
|
+
if until is not None:
|
|
3328
|
+
request['endTime'] = until
|
|
3329
|
+
params = self.omit(params, ['until'])
|
|
3330
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
|
3331
|
+
#
|
|
3332
|
+
# [
|
|
3333
|
+
# {
|
|
3334
|
+
# "time":1724762307531,
|
|
3335
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
|
3336
|
+
# "delta":{
|
|
3337
|
+
# "type":"accountClassTransfer",
|
|
3338
|
+
# "usdc":"50.0",
|
|
3339
|
+
# "toPerp":false
|
|
3340
|
+
# }
|
|
3341
|
+
# }
|
|
3342
|
+
# ]
|
|
3343
|
+
#
|
|
3344
|
+
return self.parse_ledger(response, None, since, limit)
|
|
3345
|
+
|
|
3346
|
+
def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
|
|
3347
|
+
#
|
|
3348
|
+
# {
|
|
3349
|
+
# "time":1724762307531,
|
|
3350
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
|
3351
|
+
# "delta":{
|
|
3352
|
+
# "type":"accountClassTransfer",
|
|
3353
|
+
# "usdc":"50.0",
|
|
3354
|
+
# "toPerp":false
|
|
3355
|
+
# }
|
|
3356
|
+
# }
|
|
3357
|
+
#
|
|
3358
|
+
timestamp = self.safe_integer(item, 'time')
|
|
3359
|
+
delta = self.safe_dict(item, 'delta', {})
|
|
3360
|
+
fee = None
|
|
3361
|
+
feeCost = self.safe_integer(delta, 'fee')
|
|
3362
|
+
if feeCost is not None:
|
|
3363
|
+
fee = {
|
|
3364
|
+
'currency': 'USDC',
|
|
3365
|
+
'cost': feeCost,
|
|
3366
|
+
}
|
|
3367
|
+
type = self.safe_string(delta, 'type')
|
|
3368
|
+
amount = self.safe_string(delta, 'usdc')
|
|
3369
|
+
return self.safe_ledger_entry({
|
|
3370
|
+
'info': item,
|
|
3371
|
+
'id': self.safe_string(item, 'hash'),
|
|
3372
|
+
'direction': None,
|
|
3373
|
+
'account': None,
|
|
3374
|
+
'referenceAccount': self.safe_string(delta, 'user'),
|
|
3375
|
+
'referenceId': self.safe_string(item, 'hash'),
|
|
3376
|
+
'type': self.parse_ledger_entry_type(type),
|
|
3377
|
+
'currency': None,
|
|
3378
|
+
'amount': self.parse_number(amount),
|
|
3379
|
+
'timestamp': timestamp,
|
|
3380
|
+
'datetime': self.iso8601(timestamp),
|
|
3381
|
+
'before': None,
|
|
3382
|
+
'after': None,
|
|
3383
|
+
'status': None,
|
|
3384
|
+
'fee': fee,
|
|
3385
|
+
}, currency)
|
|
3386
|
+
|
|
3387
|
+
def parse_ledger_entry_type(self, type):
|
|
3388
|
+
ledgerType: dict = {
|
|
3389
|
+
'internalTransfer': 'transfer',
|
|
3390
|
+
'accountClassTransfer': 'transfer',
|
|
3391
|
+
}
|
|
3392
|
+
return self.safe_string(ledgerType, type, type)
|
|
3393
|
+
|
|
3394
|
+
async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
3395
|
+
"""
|
|
3396
|
+
fetch all deposits made to an account
|
|
3397
|
+
:param str code: unified currency code
|
|
3398
|
+
:param int [since]: the earliest time in ms to fetch deposits for
|
|
3399
|
+
:param int [limit]: the maximum number of deposits structures to retrieve
|
|
3400
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
3401
|
+
:param int [params.until]: the latest time in ms to fetch withdrawals for
|
|
3402
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
3403
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
3404
|
+
"""
|
|
3405
|
+
await self.load_markets()
|
|
3406
|
+
userAddress = None
|
|
3407
|
+
userAddress, params = self.handle_public_address('fetchDepositsWithdrawals', params)
|
|
3408
|
+
request: dict = {
|
|
3409
|
+
'type': 'userNonFundingLedgerUpdates',
|
|
3410
|
+
'user': userAddress,
|
|
2370
3411
|
}
|
|
3412
|
+
if since is not None:
|
|
3413
|
+
request['startTime'] = since
|
|
3414
|
+
until = self.safe_integer(params, 'until')
|
|
3415
|
+
if until is not None:
|
|
3416
|
+
request['endTime'] = until
|
|
3417
|
+
params = self.omit(params, ['until'])
|
|
3418
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
|
3419
|
+
#
|
|
3420
|
+
# [
|
|
3421
|
+
# {
|
|
3422
|
+
# "time":1724762307531,
|
|
3423
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
|
3424
|
+
# "delta":{
|
|
3425
|
+
# "type":"accountClassTransfer",
|
|
3426
|
+
# "usdc":"50.0",
|
|
3427
|
+
# "toPerp":false
|
|
3428
|
+
# }
|
|
3429
|
+
# }
|
|
3430
|
+
# ]
|
|
3431
|
+
#
|
|
3432
|
+
records = self.extract_type_from_delta(response)
|
|
3433
|
+
deposits = self.filter_by_array(records, 'type', ['deposit'], False)
|
|
3434
|
+
return self.parse_transactions(deposits, None, since, limit)
|
|
3435
|
+
|
|
3436
|
+
async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
|
3437
|
+
"""
|
|
3438
|
+
fetch all withdrawals made from an account
|
|
3439
|
+
:param str code: unified currency code
|
|
3440
|
+
:param int [since]: the earliest time in ms to fetch withdrawals for
|
|
3441
|
+
:param int [limit]: the maximum number of withdrawals structures to retrieve
|
|
3442
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
3443
|
+
:param int [params.until]: the latest time in ms to fetch withdrawals for
|
|
3444
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
3445
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
3446
|
+
"""
|
|
3447
|
+
await self.load_markets()
|
|
3448
|
+
userAddress = None
|
|
3449
|
+
userAddress, params = self.handle_public_address('fetchDepositsWithdrawals', params)
|
|
3450
|
+
request: dict = {
|
|
3451
|
+
'type': 'userNonFundingLedgerUpdates',
|
|
3452
|
+
'user': userAddress,
|
|
3453
|
+
}
|
|
3454
|
+
if since is not None:
|
|
3455
|
+
request['startTime'] = since
|
|
3456
|
+
until = self.safe_integer(params, 'until')
|
|
3457
|
+
if until is not None:
|
|
3458
|
+
request['endTime'] = until
|
|
3459
|
+
params = self.omit(params, ['until'])
|
|
3460
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
|
3461
|
+
#
|
|
3462
|
+
# [
|
|
3463
|
+
# {
|
|
3464
|
+
# "time":1724762307531,
|
|
3465
|
+
# "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
|
|
3466
|
+
# "delta":{
|
|
3467
|
+
# "type":"accountClassTransfer",
|
|
3468
|
+
# "usdc":"50.0",
|
|
3469
|
+
# "toPerp":false
|
|
3470
|
+
# }
|
|
3471
|
+
# }
|
|
3472
|
+
# ]
|
|
3473
|
+
#
|
|
3474
|
+
records = self.extract_type_from_delta(response)
|
|
3475
|
+
withdrawals = self.filter_by_array(records, 'type', ['withdraw'], False)
|
|
3476
|
+
return self.parse_transactions(withdrawals, None, since, limit)
|
|
3477
|
+
|
|
3478
|
+
async def fetch_open_interests(self, symbols: Strings = None, params={}):
|
|
3479
|
+
"""
|
|
3480
|
+
Retrieves the open interest for a list of symbols
|
|
3481
|
+
:param str[] [symbols]: Unified CCXT market symbol
|
|
3482
|
+
:param dict [params]: exchange specific parameters
|
|
3483
|
+
:returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
|
|
3484
|
+
"""
|
|
3485
|
+
await self.load_markets()
|
|
3486
|
+
symbols = self.market_symbols(symbols)
|
|
3487
|
+
swapMarkets = await self.fetch_swap_markets()
|
|
3488
|
+
return self.parse_open_interests(swapMarkets, symbols)
|
|
3489
|
+
|
|
3490
|
+
async def fetch_open_interest(self, symbol: str, params={}):
|
|
3491
|
+
"""
|
|
3492
|
+
retrieves the open interest of a contract trading pair
|
|
3493
|
+
:param str symbol: unified CCXT market symbol
|
|
3494
|
+
:param dict [params]: exchange specific parameters
|
|
3495
|
+
:returns dict: an `open interest structure <https://docs.ccxt.com/#/?id=open-interest-structure>`
|
|
3496
|
+
"""
|
|
3497
|
+
symbol = self.symbol(symbol)
|
|
3498
|
+
await self.load_markets()
|
|
3499
|
+
ois = await self.fetch_open_interests([symbol], params)
|
|
3500
|
+
return ois[symbol]
|
|
3501
|
+
|
|
3502
|
+
def parse_open_interest(self, interest, market: Market = None):
|
|
3503
|
+
#
|
|
3504
|
+
# {
|
|
3505
|
+
# szDecimals: '2',
|
|
3506
|
+
# name: 'HYPE',
|
|
3507
|
+
# maxLeverage: '3',
|
|
3508
|
+
# funding: '0.00014735',
|
|
3509
|
+
# openInterest: '14677900.74',
|
|
3510
|
+
# prevDayPx: '26.145',
|
|
3511
|
+
# dayNtlVlm: '299643445.12560016',
|
|
3512
|
+
# premium: '0.00081613',
|
|
3513
|
+
# oraclePx: '27.569',
|
|
3514
|
+
# markPx: '27.63',
|
|
3515
|
+
# midPx: '27.599',
|
|
3516
|
+
# impactPxs: ['27.5915', '27.6319'],
|
|
3517
|
+
# dayBaseVlm: '10790652.83',
|
|
3518
|
+
# baseId: 159
|
|
3519
|
+
# }
|
|
3520
|
+
#
|
|
3521
|
+
interest = self.safe_dict(interest, 'info', {})
|
|
3522
|
+
coin = self.safe_string(interest, 'name')
|
|
3523
|
+
marketId = None
|
|
3524
|
+
if coin is not None:
|
|
3525
|
+
marketId = self.coin_to_market_id(coin)
|
|
3526
|
+
return self.safe_open_interest({
|
|
3527
|
+
'symbol': self.safe_symbol(marketId),
|
|
3528
|
+
'openInterestAmount': self.safe_number(interest, 'openInterest'),
|
|
3529
|
+
'openInterestValue': None,
|
|
3530
|
+
'timestamp': None,
|
|
3531
|
+
'datetime': None,
|
|
3532
|
+
'info': interest,
|
|
3533
|
+
}, market)
|
|
3534
|
+
|
|
3535
|
+
async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
3536
|
+
"""
|
|
3537
|
+
fetch the history of funding payments paid and received on self account
|
|
3538
|
+
:param str [symbol]: unified market symbol
|
|
3539
|
+
:param int [since]: the earliest time in ms to fetch funding history for
|
|
3540
|
+
:param int [limit]: the maximum number of funding history structures to retrieve
|
|
3541
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
3542
|
+
:param str [params.subAccountAddress]: sub account user address
|
|
3543
|
+
:returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
|
|
3544
|
+
"""
|
|
3545
|
+
await self.load_markets()
|
|
3546
|
+
market = None
|
|
3547
|
+
if symbol is not None:
|
|
3548
|
+
market = self.market(symbol)
|
|
3549
|
+
userAddress = None
|
|
3550
|
+
userAddress, params = self.handle_public_address('fetchFundingHistory', params)
|
|
3551
|
+
request: dict = {
|
|
3552
|
+
'user': userAddress,
|
|
3553
|
+
'type': 'userFunding',
|
|
3554
|
+
}
|
|
3555
|
+
if since is not None:
|
|
3556
|
+
request['startTime'] = since
|
|
3557
|
+
until = self.safe_integer(params, 'until')
|
|
3558
|
+
params = self.omit(params, 'until')
|
|
3559
|
+
if until is not None:
|
|
3560
|
+
request['endTime'] = until
|
|
3561
|
+
response = await self.publicPostInfo(self.extend(request, params))
|
|
3562
|
+
#
|
|
3563
|
+
# [
|
|
3564
|
+
# {
|
|
3565
|
+
# "time": 1734026400057,
|
|
3566
|
+
# "hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
3567
|
+
# "delta": {
|
|
3568
|
+
# "type": "funding",
|
|
3569
|
+
# "coin": "SOL",
|
|
3570
|
+
# "usdc": "75.635093",
|
|
3571
|
+
# "szi": "-7375.9",
|
|
3572
|
+
# "fundingRate": "0.00004381",
|
|
3573
|
+
# "nSamples": null
|
|
3574
|
+
# }
|
|
3575
|
+
# }
|
|
3576
|
+
# ]
|
|
3577
|
+
#
|
|
3578
|
+
return self.parse_incomes(response, market, since, limit)
|
|
3579
|
+
|
|
3580
|
+
def parse_income(self, income, market: Market = None):
|
|
3581
|
+
#
|
|
3582
|
+
# {
|
|
3583
|
+
# "time": 1734026400057,
|
|
3584
|
+
# "hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
3585
|
+
# "delta": {
|
|
3586
|
+
# "type": "funding",
|
|
3587
|
+
# "coin": "SOL",
|
|
3588
|
+
# "usdc": "75.635093",
|
|
3589
|
+
# "szi": "-7375.9",
|
|
3590
|
+
# "fundingRate": "0.00004381",
|
|
3591
|
+
# "nSamples": null
|
|
3592
|
+
# }
|
|
3593
|
+
# }
|
|
3594
|
+
#
|
|
3595
|
+
id = self.safe_string(income, 'hash')
|
|
3596
|
+
timestamp = self.safe_integer(income, 'time')
|
|
3597
|
+
delta = self.safe_dict(income, 'delta')
|
|
3598
|
+
baseId = self.safe_string(delta, 'coin')
|
|
3599
|
+
marketSymbol = baseId + '/USDC:USDC'
|
|
3600
|
+
market = self.safe_market(marketSymbol)
|
|
3601
|
+
symbol = market['symbol']
|
|
3602
|
+
amount = self.safe_string(delta, 'usdc')
|
|
3603
|
+
code = self.safe_currency_code('USDC')
|
|
3604
|
+
rate = self.safe_number(delta, 'fundingRate')
|
|
3605
|
+
return {
|
|
3606
|
+
'info': income,
|
|
3607
|
+
'symbol': symbol,
|
|
3608
|
+
'code': code,
|
|
3609
|
+
'timestamp': timestamp,
|
|
3610
|
+
'datetime': self.iso8601(timestamp),
|
|
3611
|
+
'id': id,
|
|
3612
|
+
'amount': self.parse_number(amount),
|
|
3613
|
+
'rate': rate,
|
|
3614
|
+
}
|
|
3615
|
+
|
|
3616
|
+
async def reserve_request_weight(self, weight: Num, params={}) -> dict:
|
|
3617
|
+
"""
|
|
3618
|
+
Instead of trading to increase the address based rate limits, self action allows reserving additional actions for 0.0005 USDC per request. The cost is paid from the Perps balance.
|
|
3619
|
+
:param number weight: the weight to reserve, 1 weight = 1 action, 0.0005 USDC per action
|
|
3620
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
3621
|
+
:returns dict: a response object
|
|
3622
|
+
"""
|
|
3623
|
+
nonce = self.milliseconds()
|
|
3624
|
+
request: dict = {
|
|
3625
|
+
'nonce': nonce,
|
|
3626
|
+
}
|
|
3627
|
+
action: dict = {
|
|
3628
|
+
'type': 'reserveRequestWeight',
|
|
3629
|
+
'weight': weight,
|
|
3630
|
+
}
|
|
3631
|
+
signature = self.sign_l1_action(action, nonce)
|
|
3632
|
+
request['action'] = action
|
|
3633
|
+
request['signature'] = signature
|
|
3634
|
+
response = await self.privatePostExchange(self.extend(request, params))
|
|
3635
|
+
return response
|
|
3636
|
+
|
|
3637
|
+
def extract_type_from_delta(self, data=[]):
|
|
3638
|
+
records = []
|
|
3639
|
+
for i in range(0, len(data)):
|
|
3640
|
+
record = data[i]
|
|
3641
|
+
record['type'] = record['delta']['type']
|
|
3642
|
+
records.append(record)
|
|
3643
|
+
return records
|
|
2371
3644
|
|
|
2372
3645
|
def format_vault_address(self, address: Str = None):
|
|
2373
3646
|
if address is None:
|
|
@@ -2378,7 +3651,7 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2378
3651
|
|
|
2379
3652
|
def handle_public_address(self, methodName: str, params: dict):
|
|
2380
3653
|
userAux = None
|
|
2381
|
-
userAux, params = self.
|
|
3654
|
+
userAux, params = self.handle_option_and_params_2(params, methodName, 'user', 'subAccountAddress')
|
|
2382
3655
|
user = userAux
|
|
2383
3656
|
user, params = self.handle_option_and_params(params, methodName, 'address', userAux)
|
|
2384
3657
|
if (user is not None) and (user != ''):
|
|
@@ -2388,9 +3661,9 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2388
3661
|
raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a user parameter inside \'params\' or the wallet address set')
|
|
2389
3662
|
|
|
2390
3663
|
def coin_to_market_id(self, coin: Str):
|
|
2391
|
-
if coin.find('/') > -1:
|
|
3664
|
+
if coin.find('/') > -1 or coin.find('@') > -1:
|
|
2392
3665
|
return coin # spot
|
|
2393
|
-
return coin + '/USDC:USDC'
|
|
3666
|
+
return self.safe_currency_code(coin) + '/USDC:USDC'
|
|
2394
3667
|
|
|
2395
3668
|
def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
|
|
2396
3669
|
if not response:
|
|
@@ -2401,17 +3674,27 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2401
3674
|
# status: 'ok',
|
|
2402
3675
|
# response: {type: 'order', data: {statuses: [{error: 'Insufficient margin to place order. asset=4'}]}}
|
|
2403
3676
|
# }
|
|
3677
|
+
# {"status":"ok","response":{"type":"order","data":{"statuses":[{"error":"Insufficient margin to place order. asset=84"}]}}}
|
|
3678
|
+
#
|
|
3679
|
+
# {"status":"unknownOid"}
|
|
2404
3680
|
#
|
|
2405
3681
|
status = self.safe_string(response, 'status', '')
|
|
3682
|
+
error = self.safe_string(response, 'error')
|
|
2406
3683
|
message = None
|
|
2407
3684
|
if status == 'err':
|
|
2408
3685
|
message = self.safe_string(response, 'response')
|
|
3686
|
+
elif status == 'unknownOid':
|
|
3687
|
+
raise OrderNotFound(self.id + ' ' + body) # {"status":"unknownOid"}
|
|
3688
|
+
elif error is not None:
|
|
3689
|
+
message = error
|
|
2409
3690
|
else:
|
|
2410
3691
|
responsePayload = self.safe_dict(response, 'response', {})
|
|
2411
3692
|
data = self.safe_dict(responsePayload, 'data', {})
|
|
2412
3693
|
statuses = self.safe_list(data, 'statuses', [])
|
|
2413
|
-
|
|
2414
|
-
|
|
3694
|
+
for i in range(0, len(statuses)):
|
|
3695
|
+
message = self.safe_string(statuses[i], 'error')
|
|
3696
|
+
if message is not None:
|
|
3697
|
+
break
|
|
2415
3698
|
feedback = self.id + ' ' + body
|
|
2416
3699
|
nonEmptyMessage = ((message is not None) and (message != ''))
|
|
2417
3700
|
if nonEmptyMessage:
|
|
@@ -2429,3 +3712,32 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
|
2429
3712
|
}
|
|
2430
3713
|
body = self.json(params)
|
|
2431
3714
|
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
|
3715
|
+
|
|
3716
|
+
def calculate_rate_limiter_cost(self, api, method, path, params, config={}):
|
|
3717
|
+
if ('byType' in config) and ('type' in params):
|
|
3718
|
+
type = params['type']
|
|
3719
|
+
byType = config['byType']
|
|
3720
|
+
if type in byType:
|
|
3721
|
+
return byType[type]
|
|
3722
|
+
return self.safe_value(config, 'cost', 1)
|
|
3723
|
+
|
|
3724
|
+
def parse_create_edit_order_args(self, id: Str, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
3725
|
+
market = self.market(symbol)
|
|
3726
|
+
vaultAddress = None
|
|
3727
|
+
vaultAddress, params = self.handle_option_and_params_2(params, 'createOrder', 'vaultAddress', 'subAccountAddress')
|
|
3728
|
+
vaultAddress = self.format_vault_address(vaultAddress)
|
|
3729
|
+
symbol = market['symbol']
|
|
3730
|
+
order = {
|
|
3731
|
+
'symbol': symbol,
|
|
3732
|
+
'type': type,
|
|
3733
|
+
'side': side,
|
|
3734
|
+
'amount': amount,
|
|
3735
|
+
'price': price,
|
|
3736
|
+
'params': params,
|
|
3737
|
+
}
|
|
3738
|
+
globalParams = {}
|
|
3739
|
+
if vaultAddress is not None:
|
|
3740
|
+
globalParams['vaultAddress'] = vaultAddress
|
|
3741
|
+
if id is not None:
|
|
3742
|
+
order['id'] = id
|
|
3743
|
+
return [order, globalParams]
|