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